signet_types/signing/
fill.rs1use crate::agg::AggregateOrders;
2use crate::signing::{permit_signing_info, SignedPermitError, SigningError};
3use alloy::{
4 network::TransactionBuilder, primitives::Address, rpc::types::TransactionRequest,
5 signers::Signer, sol_types::SolCall,
6};
7use chrono::Utc;
8use serde::{Deserialize, Serialize};
9use signet_zenith::{
10 BundleHelper::{FillPermit2, IOrders},
11 RollupOrders::{fillPermit2Call, Output, Permit2Batch, TokenPermissions},
12};
13use std::{borrow::Cow, collections::HashMap};
14
15#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
38pub struct SignedFill {
39 #[serde(flatten)]
41 pub permit: Permit2Batch,
42 pub outputs: Vec<Output>,
44}
45
46impl SignedFill {
47 pub const fn new(permit: Permit2Batch, outputs: Vec<Output>) -> Self {
49 Self { permit, outputs }
50 }
51
52 pub fn validate(&self, timestamp: u64) -> Result<(), SignedPermitError> {
58 let deadline = self.permit.permit.deadline.saturating_to::<u64>();
59 if timestamp > deadline {
60 return Err(SignedPermitError::DeadlinePassed { current: timestamp, deadline });
61 }
62
63 if self.outputs.len() != self.permit.permit.permitted.len() {
65 return Err(SignedPermitError::PermitMismatch);
66 }
67
68 for (output, permit) in self.outputs.iter().zip(self.permit.permit.permitted.iter()) {
69 if output.token != permit.token {
71 return Err(SignedPermitError::PermitMismatch);
72 }
73 if output.amount != permit.amount {
75 return Err(SignedPermitError::PermitMismatch);
76 }
77 }
78
79 Ok(())
80 }
81
82 pub fn to_fill_tx(&self, order_contract: Address) -> TransactionRequest {
84 let fill_data =
86 fillPermit2Call { outputs: self.outputs.clone(), permit2: self.permit.clone() }
87 .abi_encode();
88
89 TransactionRequest::default().with_input(fill_data).with_to(order_contract)
91 }
92}
93
94impl From<SignedFill> for FillPermit2 {
95 fn from(fill: SignedFill) -> Self {
96 FillPermit2 {
97 permit2: fill.permit.into(),
98 outputs: fill.outputs.into_iter().map(IOrders::Output::from).collect(),
99 }
100 }
101}
102
103impl From<&SignedFill> for FillPermit2 {
104 fn from(fill: &SignedFill) -> Self {
105 FillPermit2 {
106 permit2: (&fill.permit).into(),
107 outputs: fill.outputs.iter().map(IOrders::Output::from).collect(),
108 }
109 }
110}
111
112#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
114pub struct UnsignedFill<'a> {
115 orders: Cow<'a, AggregateOrders>,
116 deadline: Option<u64>,
117 nonce: Option<u64>,
118 destination_chains: HashMap<u64, Address>,
119}
120
121impl<'a> From<&'a AggregateOrders> for UnsignedFill<'a> {
122 fn from(orders: &'a AggregateOrders) -> Self {
123 UnsignedFill::new(orders)
124 }
125}
126
127impl<'a> UnsignedFill<'a> {
128 pub fn new(orders: &'a AggregateOrders) -> Self {
130 Self {
131 orders: orders.into(),
132 deadline: None,
133 nonce: None,
134 destination_chains: HashMap::new(),
135 }
136 }
137
138 pub fn with_nonce(self, nonce: u64) -> Self {
140 Self { nonce: Some(nonce), ..self }
141 }
142
143 pub fn with_deadline(self, deadline: u64) -> Self {
145 Self { deadline: Some(deadline), ..self }
146 }
147
148 pub fn with_chain(mut self, chain_id: u64, order_contract_address: Address) -> Self {
150 self.destination_chains.insert(chain_id, order_contract_address);
151 self
152 }
153
154 pub async fn sign<S: Signer>(
157 &self,
158 signer: &S,
159 ) -> Result<HashMap<u64, SignedFill>, SigningError> {
160 let mut fills = HashMap::new();
161
162 for destination_chain_id in self.orders.destination_chain_ids() {
164 let signed_fill = self.sign_for(destination_chain_id, signer).await?;
165 fills.insert(destination_chain_id, signed_fill);
166 }
167
168 Ok(fills)
170 }
171
172 pub async fn sign_for<S: Signer>(
178 &self,
179 chain_id: u64,
180 signer: &S,
181 ) -> Result<SignedFill, SigningError> {
182 let now = Utc::now();
183 let nonce = self.nonce.unwrap_or(now.timestamp_micros() as u64);
185 let deadline = self.deadline.unwrap_or(now.timestamp() as u64 + 12);
187
188 let destination_order_address = self
190 .destination_chains
191 .get(&chain_id)
192 .ok_or(SigningError::MissingOrderContract(chain_id))?;
193
194 let outputs = self.orders.outputs_for(chain_id);
196 let permitted: Vec<TokenPermissions> = outputs.iter().map(Into::into).collect();
198
199 let permit = permit_signing_info(
201 outputs,
202 permitted,
203 deadline,
204 nonce,
205 chain_id,
206 *destination_order_address,
207 );
208
209 let signature = signer.sign_hash(&permit.signing_hash).await?;
211
212 Ok(SignedFill {
214 permit: Permit2Batch {
215 permit: permit.permit,
216 owner: signer.address(),
217 signature: signature.as_bytes().into(),
218 },
219 outputs: permit.outputs,
220 })
221 }
222}