1use crate::{FillSubmitter, OrderSource};
2use alloy::{primitives::Address, signers::Signer};
3use chrono::Utc;
4use futures_util::{Stream, StreamExt};
5use signet_constants::SignetSystemConstants;
6use signet_types::{SignedFill, SignedOrder, SigningError, UnsignedFill};
7use std::collections::HashMap;
8use tracing::instrument;
9
10#[derive(Debug, thiserror::Error)]
12#[non_exhaustive]
13pub enum FillerError {
14 #[error("failed to get orders: {0}")]
16 Source(#[source] Box<dyn core::error::Error + Send + Sync>),
17 #[error("no orders to fill")]
19 NoOrders,
20 #[error("failed to sign fills: {0}")]
22 Signing(#[from] SigningError),
23 #[error("failed to submit fills: {0}")]
25 Submission(#[source] Box<dyn core::error::Error + Send + Sync>),
26}
27
28#[derive(Debug, Clone, Copy, Default)]
30pub struct FillerOptions {
31 pub deadline_offset: Option<u64>,
33 pub nonce: Option<u64>,
35}
36
37impl FillerOptions {
38 pub const fn new() -> Self {
40 Self { deadline_offset: None, nonce: None }
41 }
42
43 pub const fn with_deadline_offset(mut self, offset: u64) -> Self {
45 self.deadline_offset = Some(offset);
46 self
47 }
48
49 pub const fn with_nonce(mut self, nonce: u64) -> Self {
51 self.nonce = Some(nonce);
52 self
53 }
54}
55
56#[derive(Debug, Clone)]
59pub struct OrdersAndFills {
60 pub(crate) orders: Vec<SignedOrder>,
61 pub(crate) fills: HashMap<u64, SignedFill>,
62 pub(crate) signer_address: Address,
63}
64
65impl OrdersAndFills {
66 pub fn orders(&self) -> &[SignedOrder] {
68 &self.orders
69 }
70
71 pub const fn fills(&self) -> &HashMap<u64, SignedFill> {
73 &self.fills
74 }
75
76 pub const fn signer_address(&self) -> Address {
78 self.signer_address
79 }
80}
81
82#[derive(Debug, Clone)]
89pub struct Filler<Sign, Source, Submit> {
90 signer: Sign,
91 order_source: Source,
92 submitter: Submit,
93 constants: SignetSystemConstants,
94 options: FillerOptions,
95}
96
97impl<Sign, Source, Submit> Filler<Sign, Source, Submit> {
98 pub const fn new(
100 signer: Sign,
101 order_source: Source,
102 submitter: Submit,
103 constants: SignetSystemConstants,
104 options: FillerOptions,
105 ) -> Self {
106 Self { signer, order_source, submitter, constants, options }
107 }
108
109 pub const fn signer(&self) -> &Sign {
111 &self.signer
112 }
113
114 pub const fn order_source(&self) -> &Source {
116 &self.order_source
117 }
118
119 pub const fn submitter(&self) -> &Submit {
121 &self.submitter
122 }
123
124 pub const fn constants(&self) -> &SignetSystemConstants {
126 &self.constants
127 }
128
129 pub const fn options(&self) -> &FillerOptions {
131 &self.options
132 }
133}
134
135impl<Sign, Source, Submit> Filler<Sign, Source, Submit>
136where
137 Source: OrderSource + Send + Sync,
138{
139 pub fn get_orders(
141 &self,
142 ) -> impl Stream<Item = Result<SignedOrder, FillerError>> + Send + use<'_, Sign, Source, Submit>
143 {
144 self.order_source
145 .get_orders()
146 .map(|result| result.map_err(|e| FillerError::Source(Box::new(e))))
147 }
148}
149
150impl<Sign, Source, Submit> Filler<Sign, Source, Submit>
151where
152 Sign: Signer + Send + Sync,
153{
154 pub async fn sign_fills(
158 &self,
159 orders: Vec<SignedOrder>,
160 ) -> Result<OrdersAndFills, FillerError> {
161 let mut unsigned_fill = UnsignedFill::new().with_chain(self.constants.clone());
162
163 if let Some(deadline_offset) = self.options.deadline_offset {
164 let deadline = Utc::now().timestamp() as u64 + deadline_offset;
165 unsigned_fill = unsigned_fill.with_deadline(deadline);
166 }
167
168 if let Some(nonce) = self.options.nonce {
169 unsigned_fill = unsigned_fill.with_nonce(nonce);
170 }
171
172 for order in &orders {
173 unsigned_fill = unsigned_fill.fill(order);
174 }
175
176 let fills = unsigned_fill.sign(&self.signer).await?;
177 let signer_address = self.signer.address();
178 Ok(OrdersAndFills { orders, fills, signer_address })
179 }
180}
181
182impl<Sign, Source, Submit> Filler<Sign, Source, Submit>
183where
184 Sign: Signer + Send + Sync,
185 Submit: FillSubmitter + Send + Sync,
186{
187 #[instrument(skip_all, fields(order_count = orders.len()))]
193 pub async fn fill(&self, orders: Vec<SignedOrder>) -> Result<Submit::Response, FillerError> {
194 if orders.is_empty() {
195 return Err(FillerError::NoOrders);
196 }
197
198 let orders_and_fills = self.sign_fills(orders).await?;
199 self.submitter
200 .submit_fills(orders_and_fills)
201 .await
202 .map_err(|error| FillerError::Submission(Box::new(error)))
203 }
204}