1use crate::users::TEST_SIGNERS;
3use alloy::{
4 network::{Ethereum, EthereumWallet, TransactionBuilder},
5 primitives::{Address, U256},
6 providers::{fillers::FillerControlFlow, Provider, ProviderBuilder, RootProvider, SendableTx},
7 signers::{local::PrivateKeySigner, Signer},
8 transports::{mock::Asserter, TransportResult},
9};
10use core::convert::Infallible;
11use futures_util::{stream, Stream};
12use signet_bundle::SignetEthBundle;
13use signet_constants::{test_utils::TEST_SYS, SignetSystemConstants};
14use signet_orders::{
15 BundleSubmitter, FillSubmitter, OrderSource, OrderSubmitter, OrdersAndFills, TxBuilder,
16};
17use signet_types::{SignedOrder, UnsignedOrder};
18use signet_zenith::RollupOrders::Output;
19use std::sync::{
20 atomic::{AtomicU64, Ordering},
21 Arc, Mutex,
22};
23
24#[derive(Debug, Clone, Default)]
26pub struct MockOrderSubmitter {
27 orders: Arc<Mutex<Vec<SignedOrder>>>,
28}
29
30impl MockOrderSubmitter {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn submitted_orders(&self) -> Vec<SignedOrder> {
38 self.orders.lock().unwrap().clone()
39 }
40}
41
42impl OrderSubmitter for MockOrderSubmitter {
43 type Error = Infallible;
44
45 async fn submit_order(&self, order: SignedOrder) -> Result<(), Self::Error> {
46 self.orders.lock().unwrap().push(order);
47 Ok(())
48 }
49}
50
51#[derive(Debug, Clone)]
53pub struct MockOrderSource {
54 orders: Vec<SignedOrder>,
55}
56
57impl MockOrderSource {
58 pub fn new(orders: Vec<SignedOrder>) -> Self {
60 Self { orders }
61 }
62
63 pub fn empty() -> Self {
65 Self { orders: vec![] }
66 }
67}
68
69impl OrderSource for MockOrderSource {
70 type Error = Infallible;
71
72 fn get_orders(&self) -> impl Stream<Item = Result<SignedOrder, Self::Error>> + Send {
73 stream::iter(self.orders.clone().into_iter().map(Ok))
74 }
75}
76
77#[derive(Debug, Clone, Default)]
79pub struct MockBundleSubmitter {
80 bundles: Arc<Mutex<Vec<SignetEthBundle>>>,
81}
82
83impl MockBundleSubmitter {
84 pub fn new() -> Self {
86 Self::default()
87 }
88
89 pub fn submitted_bundles(&self) -> Vec<SignetEthBundle> {
91 self.bundles.lock().unwrap().clone()
92 }
93}
94
95impl BundleSubmitter for MockBundleSubmitter {
96 type Response = ();
97 type Error = Infallible;
98
99 async fn submit_bundle(&self, bundle: SignetEthBundle) -> Result<(), Self::Error> {
100 self.bundles.lock().unwrap().push(bundle);
101 Ok(())
102 }
103}
104
105#[derive(Clone)]
115pub struct MockTxBuilder<P> {
116 inner: P,
117 asserter: Asserter,
118 nonce: Arc<AtomicU64>,
119}
120
121impl<P> MockTxBuilder<P> {
122 fn new(inner: P, asserter: Asserter) -> Self {
124 Self { inner, asserter, nonce: Arc::new(AtomicU64::new(0)) }
125 }
126
127 pub fn asserter(&self) -> &Asserter {
129 &self.asserter
130 }
131}
132
133impl<P: Provider<Ethereum>> Provider<Ethereum> for MockTxBuilder<P> {
134 fn root(&self) -> &RootProvider<Ethereum> {
135 self.inner.root()
136 }
137}
138
139impl<P> TxBuilder<Ethereum> for MockTxBuilder<P>
140where
141 P: TxBuilder<Ethereum>,
142{
143 async fn fill(
144 &self,
145 mut tx: <Ethereum as alloy::network::Network>::TransactionRequest,
146 ) -> TransportResult<SendableTx<Ethereum>> {
147 if tx.nonce.is_none() {
150 let nonce = self.nonce.fetch_add(1, Ordering::SeqCst);
151 tx = tx.with_nonce(nonce);
152 }
153 if tx.gas.is_none() {
154 tx = tx.with_gas_limit(100_000);
155 }
156 if tx.max_fee_per_gas.is_none() {
157 tx = tx.with_max_fee_per_gas(1_000_000_000); }
159 if tx.max_priority_fee_per_gas.is_none() {
160 tx = tx.with_max_priority_fee_per_gas(1_000_000_000); }
162 self.inner.fill(tx).await
163 }
164
165 fn status(
166 &self,
167 tx: &<Ethereum as alloy::network::Network>::TransactionRequest,
168 ) -> FillerControlFlow {
169 self.inner.status(tx)
170 }
171}
172
173pub fn mock_tx_builder(
178 wallet: PrivateKeySigner,
179 chain_id: u64,
180) -> MockTxBuilder<impl TxBuilder<Ethereum>> {
181 let asserter = Asserter::new();
182 let inner = ProviderBuilder::new()
183 .with_chain_id(chain_id)
184 .wallet(EthereumWallet::new(wallet))
185 .connect_mocked_client(asserter.clone());
186 MockTxBuilder::new(inner, asserter)
187}
188
189#[derive(Debug, Clone, Default)]
191pub struct MockFillSubmitter {
192 submissions: Arc<Mutex<Vec<OrdersAndFills>>>,
193}
194
195impl MockFillSubmitter {
196 pub fn new() -> Self {
198 Self::default()
199 }
200
201 pub fn submissions(&self) -> Vec<OrdersAndFills> {
203 self.submissions.lock().unwrap().clone()
204 }
205}
206
207impl FillSubmitter for MockFillSubmitter {
208 type Response = ();
209 type Error = Infallible;
210
211 async fn submit_fills(
212 &self,
213 orders_and_fills: OrdersAndFills,
214 _target_block_count: u8,
215 ) -> Result<(), Self::Error> {
216 self.submissions.lock().unwrap().push(orders_and_fills);
217 Ok(())
218 }
219}
220
221#[derive(Debug, Clone)]
223pub struct TestOrderBuilder {
224 constants: SignetSystemConstants,
225 inputs: Vec<(Address, U256)>,
226 outputs: Vec<Output>,
227 nonce: Option<u64>,
228}
229
230impl Default for TestOrderBuilder {
231 fn default() -> Self {
232 Self::new()
233 }
234}
235
236impl TestOrderBuilder {
237 pub fn new() -> Self {
239 Self { constants: TEST_SYS, inputs: vec![], outputs: vec![], nonce: None }
240 }
241
242 pub fn with_constants(mut self, constants: SignetSystemConstants) -> Self {
244 self.constants = constants;
245 self
246 }
247
248 pub fn with_input(mut self, token: Address, amount: U256) -> Self {
250 self.inputs.push((token, amount));
251 self
252 }
253
254 pub fn with_output(
256 mut self,
257 token: Address,
258 amount: U256,
259 recipient: Address,
260 chain_id: u64,
261 ) -> Self {
262 self.outputs.push(Output { token, amount, recipient, chainId: chain_id as u32 });
263 self
264 }
265
266 pub fn with_nonce(mut self, nonce: u64) -> Self {
268 self.nonce = Some(nonce);
269 self
270 }
271
272 pub async fn sign<S: Signer>(self, signer: &S) -> SignedOrder {
274 let mut unsigned = UnsignedOrder::new();
275
276 for (token, amount) in self.inputs {
277 unsigned = unsigned.with_input(token, amount);
278 }
279
280 for output in self.outputs {
281 unsigned = unsigned.with_raw_output(output);
282 }
283
284 if let Some(nonce) = self.nonce {
285 unsigned = unsigned.with_nonce(nonce);
286 }
287
288 unsigned = unsigned.with_chain(&self.constants);
289
290 unsigned.sign(signer).await.expect("signing should succeed with test signer")
291 }
292}
293
294pub async fn default_test_orders() -> Vec<SignedOrder> {
296 let signer = &TEST_SIGNERS[0];
297
298 let host_order = TestOrderBuilder::new()
299 .with_input(Address::repeat_byte(0x11), U256::from(1000))
300 .with_output(
301 Address::repeat_byte(0x22),
302 U256::from(500),
303 signer.address(),
304 TEST_SYS.host_chain_id(),
305 )
306 .with_nonce(1)
307 .sign(signer)
308 .await;
309
310 let rollup_order = TestOrderBuilder::new()
311 .with_input(Address::repeat_byte(0x11), U256::from(2000))
312 .with_output(
313 Address::repeat_byte(0x33),
314 U256::from(1000),
315 signer.address(),
316 TEST_SYS.ru_chain_id(),
317 )
318 .with_nonce(2)
319 .sign(signer)
320 .await;
321
322 vec![host_order, rollup_order]
323}