Skip to content

Commit 5adf731

Browse files
authored
Merge branch 'cowprotocol:main' into main
2 parents b633ee7 + c12eddc commit 5adf731

File tree

21 files changed

+1279
-648
lines changed

21 files changed

+1279
-648
lines changed

crates/autopilot/src/arguments.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,9 +232,17 @@ pub struct Arguments {
232232
#[clap(long, env, default_value = "0s", value_parser = humantime::parse_duration)]
233233
pub run_loop_native_price_timeout: Duration,
234234

235-
#[clap(long, env, default_value = "20")]
235+
#[clap(long, env)]
236+
/// When set, enables combinatorial auctions for auctions with a deadline
237+
/// later than this timestamp.
238+
// TODO: Remove after the cutover has fully taken effect.
239+
pub combinatorial_auctions_cutover: Option<chrono::DateTime<chrono::Utc>>,
240+
241+
#[clap(long, env, default_value = "1")]
236242
/// The maximum number of winners per auction. Each winner will be allowed
237243
/// to settle their winning orders at the same time.
244+
/// This setting only applies to auctions occurring after
245+
/// `combinatorial_auctions_cutover`.
238246
pub max_winners_per_auction: NonZeroUsize,
239247

240248
#[clap(long, env, default_value = "3")]
@@ -372,6 +380,7 @@ impl std::fmt::Display for Arguments {
372380
cow_amm_configs,
373381
max_run_loop_delay,
374382
run_loop_native_price_timeout,
383+
combinatorial_auctions_cutover,
375384
max_winners_per_auction,
376385
archive_node_url,
377386
max_solutions_per_solver,
@@ -440,6 +449,10 @@ impl std::fmt::Display for Arguments {
440449
f,
441450
"run_loop_native_price_timeout: {run_loop_native_price_timeout:?}"
442451
)?;
452+
writeln!(
453+
f,
454+
"combinatorial_auctions_cutover: {combinatorial_auctions_cutover:?}"
455+
)?;
443456
writeln!(f, "max_winners_per_auction: {max_winners_per_auction:?}")?;
444457
writeln!(f, "archive_node_url: {archive_node_url:?}")?;
445458
writeln!(f, "max_solutions_per_solver: {max_solutions_per_solver:?}")?;

crates/autopilot/src/database/competition.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use {
1919
#[derive(Clone, Default, Debug)]
2020
pub struct Competition {
2121
pub auction_id: AuctionId,
22+
// TODO: remove when `settlement_scores` table is no longer used
23+
pub legacy: Option<LegacyScore>,
2224
pub reference_scores: HashMap<eth::Address, Score>,
2325
/// Addresses to which the CIP20 participation rewards will be payed out.
2426
/// Usually the same as the solver addresses.
@@ -58,6 +60,33 @@ impl super::Postgres {
5860
.await
5961
.context("solver_competition::save")?;
6062

63+
// TODO: this is deprecated and needs to be removed once the solver team has
64+
// switched to the reference_scores table.
65+
// If we enable combinatorial auctions before that switch the solver rewards
66+
// payout will be blocked until the switch happens since no data would be
67+
// stored in the old format anymore.
68+
if let Some(legacy) = &competition.legacy {
69+
database::settlement_scores::insert(
70+
&mut ex,
71+
database::settlement_scores::Score {
72+
auction_id: competition.auction_id,
73+
winner: ByteArray(legacy.winner.0),
74+
winning_score: u256_to_big_decimal(&legacy.winning_score),
75+
reference_score: u256_to_big_decimal(&legacy.reference_score),
76+
block_deadline: competition
77+
.block_deadline
78+
.try_into()
79+
.context("convert block deadline")?,
80+
simulation_block: competition
81+
.competition_simulation_block
82+
.try_into()
83+
.context("convert simulation block")?,
84+
},
85+
)
86+
.await
87+
.context("settlement_scores::insert")?;
88+
}
89+
6190
let reference_scores: Vec<_> = competition
6291
.reference_scores
6392
.iter()

crates/autopilot/src/domain/competition/winner_selection.rs renamed to crates/autopilot/src/domain/competition/winner_selection/combinatorial.rs

Lines changed: 16 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
//! That is effectively a measurement of how much better each order got executed
2525
//! because solver S participated in the competition.
2626
use {
27+
super::{Arbitrator, PartitionedSolutions, Ranking},
2728
crate::domain::{
2829
self,
2930
OrderUid,
@@ -47,43 +48,7 @@ use {
4748
},
4849
};
4950

50-
/// Implements auction arbitration in 3 phases:
51-
/// 1. filter unfair solutions
52-
/// 2. mark winners
53-
/// 3. compute reference scores
54-
///
55-
/// The functions assume the `Arbitrator` is the only one
56-
/// changing the ordering or the `participants`.
57-
impl Arbitrator {
58-
/// Runs the entire auction mechanism on the passed in solutions.
59-
pub fn arbitrate(
60-
&self,
61-
participants: Vec<Participant<Unranked>>,
62-
auction: &domain::Auction,
63-
) -> Ranking {
64-
let partitioned = self.partition_unfair_solutions(participants, auction);
65-
let filtered_out = partitioned
66-
.discarded
67-
.into_iter()
68-
.map(|participant| participant.rank(Ranked::FilteredOut))
69-
.collect();
70-
71-
let mut ranked = self.mark_winners(partitioned.kept);
72-
ranked.sort_by_key(|participant| {
73-
(
74-
// winners before non-winners
75-
std::cmp::Reverse(participant.is_winner()),
76-
// high score before low score
77-
std::cmp::Reverse(participant.solution().computed_score().cloned()),
78-
)
79-
});
80-
Ranking {
81-
filtered_out,
82-
ranked,
83-
}
84-
}
85-
86-
/// Removes unfair solutions from the set of all solutions.
51+
impl Arbitrator for Config {
8752
fn partition_unfair_solutions(
8853
&self,
8954
mut participants: Vec<Participant<Unranked>>,
@@ -134,8 +99,6 @@ impl Arbitrator {
13499
}
135100
}
136101

137-
/// Picks winners and sorts all solutions where winners come before
138-
/// non-winners and higher scores come before lower scores.
139102
fn mark_winners(&self, participants: Vec<Participant<Unranked>>) -> Vec<Participant> {
140103
let winner_indexes = self.pick_winners(participants.iter().map(|p| p.solution()));
141104
participants
@@ -151,9 +114,7 @@ impl Arbitrator {
151114
.collect()
152115
}
153116

154-
/// Computes the reference scores which are used to compute
155-
/// rewards for the winning solvers.
156-
pub fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap<eth::Address, Score> {
117+
fn compute_reference_scores(&self, ranking: &Ranking) -> HashMap<eth::Address, Score> {
157118
let mut reference_scores = HashMap::default();
158119

159120
for participant in &ranking.ranked {
@@ -189,7 +150,9 @@ impl Arbitrator {
189150

190151
reference_scores
191152
}
153+
}
192154

155+
impl Config {
193156
/// Returns indices of winning solutions.
194157
/// Assumes that `solutions` is sorted by score descendingly.
195158
/// This logic was moved into a helper function to avoid a ton of `.clone()`
@@ -349,7 +312,7 @@ fn score_by_token_pair(solution: &Solution, auction: &Auction) -> Result<ScoreBy
349312
Ok(scores)
350313
}
351314

352-
pub struct Arbitrator {
315+
pub struct Config {
353316
pub max_winners: usize,
354317
pub weth: WrappedNativeToken,
355318
}
@@ -415,48 +378,6 @@ type ScoreByDirection = HashMap<DirectedTokenPair, Score>;
415378
/// of the auction.
416379
type ScoresBySolution = HashMap<SolutionKey, ScoreByDirection>;
417380

418-
pub struct Ranking {
419-
/// Solutions that were discarded because they were malformed
420-
/// in some way or deemed unfair by the selection mechanism.
421-
filtered_out: Vec<Participant<Ranked>>,
422-
/// Final ranking of the solutions that passed the fairness
423-
/// check. Winners come before non-winners and higher total
424-
/// scores come before lower scores.
425-
ranked: Vec<Participant<Ranked>>,
426-
}
427-
428-
impl Ranking {
429-
/// All solutions including the ones that got filtered out.
430-
pub fn all(&self) -> impl Iterator<Item = &Participant<Ranked>> {
431-
self.ranked.iter().chain(&self.filtered_out)
432-
}
433-
434-
/// Enumerates all solutions. The index is used as solution UID.
435-
pub fn enumerated(&self) -> impl Iterator<Item = (usize, &Participant<Ranked>)> {
436-
self.all().enumerate()
437-
}
438-
439-
/// All solutions that won the right to get executed.
440-
pub fn winners(&self) -> impl Iterator<Item = &Participant<Ranked>> {
441-
self.ranked.iter().filter(|p| p.is_winner())
442-
}
443-
444-
/// All solutions that were not filtered out but also did not win.
445-
pub fn non_winners(&self) -> impl Iterator<Item = &Participant<Ranked>> {
446-
self.ranked.iter().filter(|p| !p.is_winner())
447-
}
448-
449-
/// All solutions that passed the filtering step.
450-
pub fn ranked(&self) -> impl Iterator<Item = &Participant<Ranked>> {
451-
self.ranked.iter()
452-
}
453-
}
454-
455-
struct PartitionedSolutions {
456-
kept: Vec<Participant<Unranked>>,
457-
discarded: Vec<Participant<Unranked>>,
458-
}
459-
460381
#[cfg(test)]
461382
mod tests {
462383
use {
@@ -469,7 +390,14 @@ mod tests {
469390
Price,
470391
order::{self, AppDataHash},
471392
},
472-
competition::{Participant, Score, Solution, TradedOrder, Unranked},
393+
competition::{
394+
Participant,
395+
Score,
396+
Solution,
397+
TradedOrder,
398+
Unranked,
399+
winner_selection::Arbitrator,
400+
},
473401
eth::{self, TokenAddress},
474402
},
475403
infra::Driver,
@@ -1268,8 +1196,8 @@ mod tests {
12681196
pub buy_amount: eth::U256,
12691197
}
12701198

1271-
fn create_test_arbitrator() -> super::Arbitrator {
1272-
super::Arbitrator {
1199+
fn create_test_arbitrator() -> super::Config {
1200+
super::Config {
12731201
max_winners: 10,
12741202
weth: H160::from_slice(&hex!("C02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")).into(),
12751203
}

0 commit comments

Comments
 (0)