1use std::fmt;
4
5use alloy_primitives::{Address, B256, U256};
6use serde::{Deserialize, Serialize};
7
8use crate::types::OrderKind;
9
10pub const COMPOSABLE_COW_ADDRESS: Address = Address::new([
16 0xfd, 0xaf, 0xc9, 0xd1, 0x90, 0x2f, 0x4e, 0x0b, 0x84, 0xf6, 0x5f, 0x49, 0xf2, 0x44, 0xb3, 0x2b,
17 0x31, 0x01, 0x3b, 0x74,
18]);
19
20pub const TWAP_HANDLER_ADDRESS: Address = Address::new([
24 0x6c, 0xf1, 0xe9, 0xca, 0x41, 0xf7, 0x61, 0x1d, 0xef, 0x40, 0x81, 0x22, 0x79, 0x3c, 0x35, 0x8a,
25 0x3d, 0x11, 0xe5, 0xa5,
26]);
27
28pub const CURRENT_BLOCK_TIMESTAMP_FACTORY_ADDRESS: Address = Address::new([
37 0x52, 0xed, 0x56, 0xda, 0x04, 0x30, 0x9a, 0xca, 0x4c, 0x3f, 0xec, 0xc5, 0x95, 0x29, 0x8d, 0x80,
38 0xc2, 0xf1, 0x6b, 0xac,
39]);
40
41pub const MAX_FREQUENCY: u32 = 365 * 24 * 60 * 60; #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
50pub struct ConditionalOrderParams {
51 pub handler: Address,
53 pub salt: B256,
55 pub static_input: Vec<u8>,
57}
58
59impl ConditionalOrderParams {
60 #[must_use]
72 pub const fn new(handler: Address, salt: B256, static_input: Vec<u8>) -> Self {
73 Self { handler, salt, static_input }
74 }
75
76 #[must_use]
86 pub const fn with_handler(mut self, handler: Address) -> Self {
87 self.handler = handler;
88 self
89 }
90
91 #[must_use]
101 pub const fn with_salt(mut self, salt: B256) -> Self {
102 self.salt = salt;
103 self
104 }
105
106 #[must_use]
116 pub fn with_static_input(mut self, static_input: Vec<u8>) -> Self {
117 self.static_input = static_input;
118 self
119 }
120
121 #[must_use]
127 pub const fn is_empty_static_input(&self) -> bool {
128 self.static_input.is_empty()
129 }
130
131 #[must_use]
137 pub const fn static_input_len(&self) -> usize {
138 self.static_input.len()
139 }
140
141 #[must_use]
151 pub const fn salt_ref(&self) -> &B256 {
152 &self.salt
153 }
154}
155
156impl fmt::Display for ConditionalOrderParams {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 write!(f, "params(handler={:#x})", self.handler)
159 }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
166pub enum TwapStartTime {
167 AtMiningTime,
169 At(u32),
171}
172
173impl TwapStartTime {
174 #[must_use]
181 pub const fn as_str(self) -> &'static str {
182 match self {
183 Self::AtMiningTime => "at-mining-time",
184 Self::At(_) => "at-unix",
185 }
186 }
187
188 #[must_use]
194 pub const fn is_at_mining_time(self) -> bool {
195 matches!(self, Self::AtMiningTime)
196 }
197
198 #[must_use]
204 pub const fn is_fixed(self) -> bool {
205 matches!(self, Self::At(_))
206 }
207
208 #[must_use]
215 pub const fn timestamp(self) -> Option<u32> {
216 match self {
217 Self::At(ts) => Some(ts),
218 Self::AtMiningTime => None,
219 }
220 }
221}
222
223impl fmt::Display for TwapStartTime {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 match self {
226 Self::AtMiningTime => f.write_str("at-mining-time"),
227 Self::At(ts) => write!(f, "at-unix-{ts}"),
228 }
229 }
230}
231
232impl From<u32> for TwapStartTime {
233 fn from(ts: u32) -> Self {
238 if ts == 0 { Self::AtMiningTime } else { Self::At(ts) }
239 }
240}
241
242impl From<TwapStartTime> for u32 {
243 fn from(t: TwapStartTime) -> Self {
248 match t {
249 TwapStartTime::AtMiningTime => 0,
250 TwapStartTime::At(ts) => ts,
251 }
252 }
253}
254
255impl From<Option<u32>> for TwapStartTime {
256 fn from(ts: Option<u32>) -> Self {
261 match ts {
262 Some(t) => Self::At(t),
263 None => Self::AtMiningTime,
264 }
265 }
266}
267
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
275pub enum DurationOfPart {
276 #[default]
278 Auto,
279 LimitDuration {
281 duration: u32,
283 },
284}
285
286impl DurationOfPart {
287 #[must_use]
289 pub const fn duration(self) -> Option<u32> {
290 match self {
291 Self::LimitDuration { duration } => Some(duration),
292 Self::Auto => None,
293 }
294 }
295
296 #[must_use]
298 pub const fn is_auto(self) -> bool {
299 matches!(self, Self::Auto)
300 }
301
302 #[must_use]
312 pub const fn limit(duration: u32) -> Self {
313 Self::LimitDuration { duration }
314 }
315
316 #[must_use]
325 pub const fn is_limit_duration(self) -> bool {
326 matches!(self, Self::LimitDuration { .. })
327 }
328}
329
330impl fmt::Display for DurationOfPart {
331 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
332 match self {
333 Self::Auto => f.write_str("auto"),
334 Self::LimitDuration { duration } => write!(f, "limit-duration({duration}s)"),
335 }
336 }
337}
338
339impl From<Option<u32>> for DurationOfPart {
340 fn from(d: Option<u32>) -> Self {
345 match d {
346 Some(duration) => Self::LimitDuration { duration },
347 None => Self::Auto,
348 }
349 }
350}
351
352#[derive(Debug, Clone, Serialize, Deserialize)]
357#[serde(rename_all = "camelCase")]
358pub struct TwapData {
359 pub sell_token: Address,
361 pub buy_token: Address,
363 pub receiver: Address,
365 pub sell_amount: U256,
367 pub buy_amount: U256,
369 pub start_time: TwapStartTime,
371 pub part_duration: u32,
373 pub num_parts: u32,
375 pub app_data: B256,
377 pub partially_fillable: bool,
379 pub kind: OrderKind,
381 #[serde(default)]
385 pub duration_of_part: DurationOfPart,
386}
387
388impl fmt::Display for TwapData {
389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
390 write!(
391 f,
392 "TWAP {} × {}s [{}] sell {} {:#x} → buy ≥ {} {:#x}",
393 self.num_parts,
394 self.part_duration,
395 self.start_time,
396 self.sell_amount,
397 self.sell_token,
398 self.buy_amount,
399 self.buy_token,
400 )
401 }
402}
403
404impl TwapData {
405 #[must_use]
413 pub const fn total_duration_secs(&self) -> u64 {
414 self.num_parts as u64 * self.part_duration as u64
415 }
416
417 #[must_use]
426 pub const fn end_time(&self) -> Option<u64> {
427 match self.start_time {
428 TwapStartTime::At(ts) => Some(ts as u64 + self.total_duration_secs()),
429 TwapStartTime::AtMiningTime => None,
430 }
431 }
432
433 #[must_use]
444 pub const fn is_sell(&self) -> bool {
445 self.kind.is_sell()
446 }
447
448 #[must_use]
463 pub const fn is_buy(&self) -> bool {
464 self.kind.is_buy()
465 }
466
467 #[must_use]
483 pub const fn is_expired(&self, timestamp: u64) -> bool {
484 match self.end_time() {
485 Some(end) => timestamp >= end,
486 None => false,
487 }
488 }
489
490 #[must_use]
510 pub const fn sell(
511 sell_token: Address,
512 buy_token: Address,
513 sell_amount: U256,
514 num_parts: u32,
515 part_duration: u32,
516 ) -> Self {
517 Self {
518 sell_token,
519 buy_token,
520 receiver: Address::ZERO,
521 sell_amount,
522 buy_amount: U256::ZERO,
523 start_time: TwapStartTime::AtMiningTime,
524 part_duration,
525 num_parts,
526 app_data: B256::ZERO,
527 partially_fillable: false,
528 kind: OrderKind::Sell,
529 duration_of_part: DurationOfPart::Auto,
530 }
531 }
532
533 #[must_use]
553 pub const fn buy(
554 sell_token: Address,
555 buy_token: Address,
556 buy_amount: U256,
557 num_parts: u32,
558 part_duration: u32,
559 ) -> Self {
560 Self {
561 sell_token,
562 buy_token,
563 receiver: Address::ZERO,
564 sell_amount: U256::MAX,
565 buy_amount,
566 start_time: TwapStartTime::AtMiningTime,
567 part_duration,
568 num_parts,
569 app_data: B256::ZERO,
570 partially_fillable: false,
571 kind: OrderKind::Buy,
572 duration_of_part: DurationOfPart::Auto,
573 }
574 }
575
576 #[must_use]
584 pub const fn with_receiver(mut self, receiver: Address) -> Self {
585 self.receiver = receiver;
586 self
587 }
588
589 #[must_use]
597 pub const fn with_buy_amount(mut self, buy_amount: U256) -> Self {
598 self.buy_amount = buy_amount;
599 self
600 }
601
602 #[must_use]
610 pub const fn with_sell_amount(mut self, sell_amount: U256) -> Self {
611 self.sell_amount = sell_amount;
612 self
613 }
614
615 #[must_use]
621 pub const fn with_start_time(mut self, start_time: TwapStartTime) -> Self {
622 self.start_time = start_time;
623 self
624 }
625
626 #[must_use]
632 pub const fn with_app_data(mut self, app_data: B256) -> Self {
633 self.app_data = app_data;
634 self
635 }
636
637 #[must_use]
643 pub const fn with_partially_fillable(mut self, partially_fillable: bool) -> Self {
644 self.partially_fillable = partially_fillable;
645 self
646 }
647
648 #[must_use]
654 pub const fn with_duration_of_part(mut self, duration_of_part: DurationOfPart) -> Self {
655 self.duration_of_part = duration_of_part;
656 self
657 }
658
659 #[must_use]
674 pub fn has_app_data(&self) -> bool {
675 !self.app_data.is_zero()
676 }
677}
678
679#[derive(Debug, Clone)]
685pub struct TwapStruct {
686 pub sell_token: Address,
688 pub buy_token: Address,
690 pub receiver: Address,
692 pub part_sell_amount: U256,
694 pub min_part_limit: U256,
696 pub t0: u32,
698 pub n: u32,
700 pub t: u32,
702 pub span: u32,
704 pub app_data: B256,
706}
707
708impl TwapStruct {
709 #[must_use]
717 pub fn has_app_data(&self) -> bool {
718 !self.app_data.is_zero()
719 }
720
721 #[must_use]
730 pub fn has_custom_receiver(&self) -> bool {
731 !self.receiver.is_zero()
732 }
733
734 #[must_use]
743 pub const fn start_is_fixed(&self) -> bool {
744 self.t0 != 0
745 }
746}
747
748impl TryFrom<&TwapData> for TwapStruct {
749 type Error = crate::CowError;
750
751 fn try_from(d: &TwapData) -> Result<Self, Self::Error> {
755 crate::composable::data_to_struct(d)
756 }
757}
758
759impl From<&TwapStruct> for TwapData {
760 fn from(s: &TwapStruct) -> Self {
764 crate::composable::struct_to_data(s)
765 }
766}
767
768impl fmt::Display for TwapStruct {
769 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
770 write!(
771 f,
772 "twap-struct {} × {}s sell {} {:#x} → ≥{} {:#x}",
773 self.n,
774 self.t,
775 self.part_sell_amount,
776 self.sell_token,
777 self.min_part_limit,
778 self.buy_token,
779 )
780 }
781}
782
783#[derive(Debug, Clone)]
797pub struct GpV2OrderStruct {
798 pub sell_token: Address,
800 pub buy_token: Address,
802 pub receiver: Address,
804 pub sell_amount: U256,
806 pub buy_amount: U256,
808 pub valid_to: u32,
810 pub app_data: B256,
812 pub fee_amount: U256,
814 pub kind: B256,
816 pub partially_fillable: bool,
818 pub sell_token_balance: B256,
820 pub buy_token_balance: B256,
822}
823impl fmt::Display for GpV2OrderStruct {
824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
825 write!(
826 f,
827 "gpv2-order({:#x} sell={} → {:#x} buy={})",
828 self.sell_token, self.sell_amount, self.buy_token, self.buy_amount
829 )
830 }
831}
832
833impl GpV2OrderStruct {
834 #[must_use]
843 pub fn has_custom_receiver(&self) -> bool {
844 !self.receiver.is_zero()
845 }
846
847 #[must_use]
853 pub const fn is_partially_fillable(&self) -> bool {
854 self.partially_fillable
855 }
856}
857
858impl TryFrom<&GpV2OrderStruct> for crate::order_signing::types::UnsignedOrder {
859 type Error = crate::CowError;
860
861 fn try_from(s: &GpV2OrderStruct) -> Result<Self, Self::Error> {
867 crate::composable::from_struct_to_order(s)
868 }
869}
870
871#[derive(Debug, Clone)]
878pub enum PollResult {
879 Success {
886 order: Option<crate::order_signing::types::UnsignedOrder>,
888 signature: Option<String>,
890 },
891 TryNextBlock,
893 TryOnBlock {
895 block_number: u64,
897 },
898 TryAtEpoch {
900 epoch: u64,
902 },
903 UnexpectedError {
905 message: String,
907 },
908 DontTryAgain {
910 reason: String,
912 },
913}
914
915impl PollResult {
916 #[must_use]
922 pub const fn is_success(&self) -> bool {
923 matches!(self, Self::Success { .. })
924 }
925
926 #[must_use]
933 pub const fn is_retryable(&self) -> bool {
934 matches!(self, Self::TryNextBlock | Self::TryOnBlock { .. } | Self::TryAtEpoch { .. })
935 }
936
937 #[must_use]
943 pub const fn is_terminal(&self) -> bool {
944 matches!(self, Self::DontTryAgain { .. })
945 }
946
947 #[must_use]
953 pub const fn is_try_next_block(&self) -> bool {
954 matches!(self, Self::TryNextBlock)
955 }
956
957 #[must_use]
963 pub const fn is_try_on_block(&self) -> bool {
964 matches!(self, Self::TryOnBlock { .. })
965 }
966
967 #[must_use]
973 pub const fn is_try_at_epoch(&self) -> bool {
974 matches!(self, Self::TryAtEpoch { .. })
975 }
976
977 #[must_use]
983 pub const fn is_unexpected_error(&self) -> bool {
984 matches!(self, Self::UnexpectedError { .. })
985 }
986
987 #[must_use]
993 pub const fn is_dont_try_again(&self) -> bool {
994 matches!(self, Self::DontTryAgain { .. })
995 }
996
997 #[must_use]
1009 pub const fn get_block_number(&self) -> Option<u64> {
1010 if let Self::TryOnBlock { block_number } = self { Some(*block_number) } else { None }
1011 }
1012
1013 #[must_use]
1025 pub const fn get_epoch(&self) -> Option<u64> {
1026 if let Self::TryAtEpoch { epoch } = self { Some(*epoch) } else { None }
1027 }
1028
1029 #[must_use]
1035 pub const fn order_ref(&self) -> Option<&crate::order_signing::types::UnsignedOrder> {
1036 if let Self::Success { order, .. } = self { order.as_ref() } else { None }
1037 }
1038
1039 #[must_use]
1044 pub const fn as_error_message(&self) -> Option<&str> {
1045 match self {
1046 Self::UnexpectedError { message } => Some(message.as_str()),
1047 Self::DontTryAgain { reason } => Some(reason.as_str()),
1048 Self::Success { .. } |
1049 Self::TryNextBlock |
1050 Self::TryOnBlock { .. } |
1051 Self::TryAtEpoch { .. } => None,
1052 }
1053 }
1054}
1055
1056impl fmt::Display for PollResult {
1057 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1058 match self {
1059 Self::Success { .. } => f.write_str("success"),
1060 Self::TryNextBlock => f.write_str("try-next-block"),
1061 Self::TryOnBlock { block_number } => write!(f, "try-on-block({block_number})"),
1062 Self::TryAtEpoch { epoch } => write!(f, "try-at-epoch({epoch})"),
1063 Self::UnexpectedError { message } => write!(f, "unexpected-error({message})"),
1064 Self::DontTryAgain { reason } => write!(f, "dont-try-again({reason})"),
1065 }
1066 }
1067}
1068
1069#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
1073#[repr(u8)]
1074pub enum ProofLocation {
1075 #[default]
1077 Private = 0,
1078 Emitted = 1,
1080 Swarm = 2,
1082 Waku = 3,
1084 Reserved = 4,
1086 Ipfs = 5,
1088}
1089
1090impl ProofLocation {
1091 #[must_use]
1093 pub const fn as_str(self) -> &'static str {
1094 match self {
1095 Self::Private => "private",
1096 Self::Emitted => "emitted",
1097 Self::Swarm => "swarm",
1098 Self::Waku => "waku",
1099 Self::Reserved => "reserved",
1100 Self::Ipfs => "ipfs",
1101 }
1102 }
1103
1104 #[must_use]
1106 pub const fn is_private(self) -> bool {
1107 matches!(self, Self::Private)
1108 }
1109
1110 #[must_use]
1112 pub const fn is_emitted(self) -> bool {
1113 matches!(self, Self::Emitted)
1114 }
1115
1116 #[must_use]
1118 pub const fn is_swarm(self) -> bool {
1119 matches!(self, Self::Swarm)
1120 }
1121
1122 #[must_use]
1124 pub const fn is_waku(self) -> bool {
1125 matches!(self, Self::Waku)
1126 }
1127
1128 #[must_use]
1130 pub const fn is_reserved(self) -> bool {
1131 matches!(self, Self::Reserved)
1132 }
1133
1134 #[must_use]
1136 pub const fn is_ipfs(self) -> bool {
1137 matches!(self, Self::Ipfs)
1138 }
1139}
1140
1141impl fmt::Display for ProofLocation {
1142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1143 f.write_str(self.as_str())
1144 }
1145}
1146
1147impl TryFrom<u8> for ProofLocation {
1148 type Error = crate::CowError;
1149
1150 fn try_from(n: u8) -> Result<Self, Self::Error> {
1152 match n {
1153 0 => Ok(Self::Private),
1154 1 => Ok(Self::Emitted),
1155 2 => Ok(Self::Swarm),
1156 3 => Ok(Self::Waku),
1157 4 => Ok(Self::Reserved),
1158 5 => Ok(Self::Ipfs),
1159 other => Err(crate::CowError::Parse {
1160 field: "ProofLocation",
1161 reason: format!("unknown discriminant: {other}"),
1162 }),
1163 }
1164 }
1165}
1166
1167impl TryFrom<&str> for ProofLocation {
1168 type Error = crate::CowError;
1169
1170 fn try_from(s: &str) -> Result<Self, Self::Error> {
1172 match s {
1173 "private" => Ok(Self::Private),
1174 "emitted" => Ok(Self::Emitted),
1175 "swarm" => Ok(Self::Swarm),
1176 "waku" => Ok(Self::Waku),
1177 "reserved" => Ok(Self::Reserved),
1178 "ipfs" => Ok(Self::Ipfs),
1179 other => Err(crate::CowError::Parse {
1180 field: "ProofLocation",
1181 reason: format!("unknown value: {other}"),
1182 }),
1183 }
1184 }
1185}
1186
1187impl From<ProofLocation> for u8 {
1188 fn from(loc: ProofLocation) -> Self {
1192 loc as Self
1193 }
1194}
1195
1196impl ProofStruct {
1197 #[must_use]
1208 pub const fn new(location: ProofLocation, data: Vec<u8>) -> Self {
1209 Self { location, data }
1210 }
1211
1212 #[must_use]
1218 pub const fn private() -> Self {
1219 Self { location: ProofLocation::Private, data: Vec::new() }
1220 }
1221
1222 #[must_use]
1228 pub const fn emitted() -> Self {
1229 Self { location: ProofLocation::Emitted, data: Vec::new() }
1230 }
1231
1232 #[must_use]
1238 pub const fn with_location(mut self, location: ProofLocation) -> Self {
1239 self.location = location;
1240 self
1241 }
1242
1243 #[must_use]
1249 pub fn with_data(mut self, data: Vec<u8>) -> Self {
1250 self.data = data;
1251 self
1252 }
1253
1254 #[must_use]
1260 pub const fn is_private(&self) -> bool {
1261 self.location.is_private()
1262 }
1263
1264 #[must_use]
1270 pub const fn is_emitted(&self) -> bool {
1271 self.location.is_emitted()
1272 }
1273
1274 #[must_use]
1280 pub const fn is_swarm(&self) -> bool {
1281 self.location.is_swarm()
1282 }
1283
1284 #[must_use]
1290 pub const fn is_waku(&self) -> bool {
1291 self.location.is_waku()
1292 }
1293
1294 #[must_use]
1300 pub const fn is_ipfs(&self) -> bool {
1301 self.location.is_ipfs()
1302 }
1303
1304 #[must_use]
1310 pub const fn is_reserved(&self) -> bool {
1311 self.location.is_reserved()
1312 }
1313
1314 #[must_use]
1319 pub const fn has_data(&self) -> bool {
1320 !self.data.is_empty()
1321 }
1322
1323 #[must_use]
1325 pub const fn is_empty(&self) -> bool {
1326 self.data.is_empty()
1327 }
1328
1329 #[must_use]
1331 pub const fn data_len(&self) -> usize {
1332 self.data.len()
1333 }
1334}
1335
1336impl fmt::Display for ProofStruct {
1337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1338 write!(f, "proof({})", self.location)
1339 }
1340}
1341
1342#[cfg(test)]
1345mod tests {
1346 use super::*;
1347
1348 #[test]
1351 fn composable_cow_address_matches() {
1352 assert_eq!(
1353 format!("{COMPOSABLE_COW_ADDRESS:#x}"),
1354 "0xfdafc9d1902f4e0b84f65f49f244b32b31013b74"
1355 );
1356 }
1357
1358 #[test]
1359 fn twap_handler_address_matches() {
1360 assert_eq!(
1361 format!("{TWAP_HANDLER_ADDRESS:#x}"),
1362 "0x6cf1e9ca41f7611def408122793c358a3d11e5a5"
1363 );
1364 }
1365
1366 #[test]
1367 fn current_block_timestamp_factory_address_matches() {
1368 assert_eq!(
1369 format!("{CURRENT_BLOCK_TIMESTAMP_FACTORY_ADDRESS:#x}"),
1370 "0x52ed56da04309aca4c3fecc595298d80c2f16bac"
1371 );
1372 }
1373
1374 #[test]
1375 fn max_frequency_is_one_year() {
1376 assert_eq!(MAX_FREQUENCY, 365 * 24 * 60 * 60);
1377 assert_eq!(MAX_FREQUENCY, 31_536_000);
1378 }
1379
1380 #[test]
1383 fn conditional_order_params_new() {
1384 let p = ConditionalOrderParams::new(Address::ZERO, B256::ZERO, vec![1, 2, 3]);
1385 assert_eq!(p.handler, Address::ZERO);
1386 assert_eq!(p.salt, B256::ZERO);
1387 assert_eq!(p.static_input, vec![1, 2, 3]);
1388 }
1389
1390 #[test]
1391 fn conditional_order_params_with_handler() {
1392 let p = ConditionalOrderParams::new(Address::ZERO, B256::ZERO, vec![])
1393 .with_handler(TWAP_HANDLER_ADDRESS);
1394 assert_eq!(p.handler, TWAP_HANDLER_ADDRESS);
1395 }
1396
1397 #[test]
1398 fn conditional_order_params_with_salt() {
1399 let salt = B256::repeat_byte(0xAB);
1400 let p = ConditionalOrderParams::new(Address::ZERO, B256::ZERO, vec![]).with_salt(salt);
1401 assert_eq!(p.salt, salt);
1402 }
1403
1404 #[test]
1405 fn conditional_order_params_with_static_input() {
1406 let p = ConditionalOrderParams::new(Address::ZERO, B256::ZERO, vec![])
1407 .with_static_input(vec![0xDE, 0xAD]);
1408 assert_eq!(p.static_input, vec![0xDE, 0xAD]);
1409 }
1410
1411 #[test]
1412 fn conditional_order_params_empty_static_input() {
1413 let empty = ConditionalOrderParams::new(Address::ZERO, B256::ZERO, vec![]);
1414 assert!(empty.is_empty_static_input());
1415 assert_eq!(empty.static_input_len(), 0);
1416
1417 let non_empty = empty.with_static_input(vec![1]);
1418 assert!(!non_empty.is_empty_static_input());
1419 assert_eq!(non_empty.static_input_len(), 1);
1420 }
1421
1422 #[test]
1423 fn conditional_order_params_salt_ref() {
1424 let salt = B256::repeat_byte(0x42);
1425 let p = ConditionalOrderParams::new(Address::ZERO, salt, vec![]);
1426 assert_eq!(p.salt_ref(), &salt);
1427 }
1428
1429 #[test]
1430 fn conditional_order_params_display() {
1431 let p = ConditionalOrderParams::new(TWAP_HANDLER_ADDRESS, B256::ZERO, vec![]);
1432 let s = p.to_string();
1433 assert!(s.starts_with("params(handler=0x"));
1434 }
1435
1436 #[test]
1439 fn twap_start_time_as_str() {
1440 assert_eq!(TwapStartTime::AtMiningTime.as_str(), "at-mining-time");
1441 assert_eq!(TwapStartTime::At(100).as_str(), "at-unix");
1442 }
1443
1444 #[test]
1445 fn twap_start_time_is_at_mining_time() {
1446 assert!(TwapStartTime::AtMiningTime.is_at_mining_time());
1447 assert!(!TwapStartTime::At(42).is_at_mining_time());
1448 }
1449
1450 #[test]
1451 fn twap_start_time_is_fixed() {
1452 assert!(TwapStartTime::At(42).is_fixed());
1453 assert!(!TwapStartTime::AtMiningTime.is_fixed());
1454 }
1455
1456 #[test]
1457 fn twap_start_time_timestamp() {
1458 assert_eq!(TwapStartTime::AtMiningTime.timestamp(), None);
1459 assert_eq!(TwapStartTime::At(1_000).timestamp(), Some(1_000));
1460 }
1461
1462 #[test]
1463 fn twap_start_time_display() {
1464 assert_eq!(TwapStartTime::AtMiningTime.to_string(), "at-mining-time");
1465 assert_eq!(TwapStartTime::At(1_700_000_000).to_string(), "at-unix-1700000000");
1466 }
1467
1468 #[test]
1469 fn twap_start_time_from_u32() {
1470 assert_eq!(TwapStartTime::from(0u32), TwapStartTime::AtMiningTime);
1471 assert_eq!(TwapStartTime::from(42u32), TwapStartTime::At(42));
1472 }
1473
1474 #[test]
1475 fn twap_start_time_into_u32() {
1476 let zero: u32 = TwapStartTime::AtMiningTime.into();
1477 assert_eq!(zero, 0);
1478 let ts: u32 = TwapStartTime::At(999).into();
1479 assert_eq!(ts, 999);
1480 }
1481
1482 #[test]
1483 fn twap_start_time_from_option_u32() {
1484 assert_eq!(TwapStartTime::from(None), TwapStartTime::AtMiningTime);
1485 assert_eq!(TwapStartTime::from(Some(123)), TwapStartTime::At(123));
1486 }
1487
1488 #[test]
1491 fn duration_of_part_auto_defaults() {
1492 let d = DurationOfPart::default();
1493 assert!(d.is_auto());
1494 assert!(!d.is_limit_duration());
1495 assert_eq!(d.duration(), None);
1496 }
1497
1498 #[test]
1499 fn duration_of_part_limit() {
1500 let d = DurationOfPart::limit(1_800);
1501 assert!(!d.is_auto());
1502 assert!(d.is_limit_duration());
1503 assert_eq!(d.duration(), Some(1_800));
1504 }
1505
1506 #[test]
1507 fn duration_of_part_display() {
1508 assert_eq!(DurationOfPart::Auto.to_string(), "auto");
1509 assert_eq!(DurationOfPart::limit(600).to_string(), "limit-duration(600s)");
1510 }
1511
1512 #[test]
1513 fn duration_of_part_from_option() {
1514 assert_eq!(DurationOfPart::from(None), DurationOfPart::Auto);
1515 assert_eq!(
1516 DurationOfPart::from(Some(300)),
1517 DurationOfPart::LimitDuration { duration: 300 }
1518 );
1519 }
1520
1521 #[test]
1524 fn twap_data_sell_constructor() {
1525 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::from(1000u64), 4, 3600);
1526 assert!(t.is_sell());
1527 assert!(!t.is_buy());
1528 assert_eq!(t.sell_amount, U256::from(1000u64));
1529 assert_eq!(t.buy_amount, U256::ZERO);
1530 assert_eq!(t.receiver, Address::ZERO);
1531 assert_eq!(t.num_parts, 4);
1532 assert_eq!(t.part_duration, 3600);
1533 assert!(t.start_time.is_at_mining_time());
1534 assert!(!t.partially_fillable);
1535 assert!(t.duration_of_part.is_auto());
1536 assert!(!t.has_app_data());
1537 }
1538
1539 #[test]
1540 fn twap_data_buy_constructor() {
1541 let t = TwapData::buy(Address::ZERO, Address::ZERO, U256::from(500u64), 2, 1800);
1542 assert!(t.is_buy());
1543 assert!(!t.is_sell());
1544 assert_eq!(t.sell_amount, U256::MAX);
1545 assert_eq!(t.buy_amount, U256::from(500u64));
1546 assert_eq!(t.num_parts, 2);
1547 assert_eq!(t.part_duration, 1800);
1548 }
1549
1550 #[test]
1553 fn twap_data_total_duration_secs() {
1554 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 4, 3600);
1555 assert_eq!(t.total_duration_secs(), 14_400);
1556 }
1557
1558 #[test]
1559 fn twap_data_end_time_fixed() {
1560 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 4, 3600)
1561 .with_start_time(TwapStartTime::At(1_000_000));
1562 assert_eq!(t.end_time(), Some(1_000_000 + 14_400));
1563 }
1564
1565 #[test]
1566 fn twap_data_end_time_at_mining() {
1567 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 4, 3600);
1568 assert_eq!(t.end_time(), None);
1569 }
1570
1571 #[test]
1572 fn twap_data_is_expired() {
1573 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 4, 3600)
1574 .with_start_time(TwapStartTime::At(1_000_000));
1575 assert!(!t.is_expired(1_014_399));
1577 assert!(t.is_expired(1_014_400));
1578 assert!(t.is_expired(2_000_000));
1579 }
1580
1581 #[test]
1582 fn twap_data_is_expired_at_mining_time_always_false() {
1583 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 4, 3600);
1584 assert!(!t.is_expired(u64::MAX));
1585 }
1586
1587 #[test]
1590 fn twap_data_with_receiver() {
1591 let recv = Address::repeat_byte(0x01);
1592 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1).with_receiver(recv);
1593 assert_eq!(t.receiver, recv);
1594 }
1595
1596 #[test]
1597 fn twap_data_with_buy_amount() {
1598 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1)
1599 .with_buy_amount(U256::from(42u64));
1600 assert_eq!(t.buy_amount, U256::from(42u64));
1601 }
1602
1603 #[test]
1604 fn twap_data_with_sell_amount() {
1605 let t = TwapData::buy(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1)
1606 .with_sell_amount(U256::from(99u64));
1607 assert_eq!(t.sell_amount, U256::from(99u64));
1608 }
1609
1610 #[test]
1611 fn twap_data_with_start_time() {
1612 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1)
1613 .with_start_time(TwapStartTime::At(12345));
1614 assert_eq!(t.start_time, TwapStartTime::At(12345));
1615 }
1616
1617 #[test]
1618 fn twap_data_with_app_data() {
1619 let hash = B256::repeat_byte(0xAA);
1620 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1).with_app_data(hash);
1621 assert!(t.has_app_data());
1622 assert_eq!(t.app_data, hash);
1623 }
1624
1625 #[test]
1626 fn twap_data_has_app_data_zero_is_false() {
1627 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1);
1628 assert!(!t.has_app_data());
1629 }
1630
1631 #[test]
1632 fn twap_data_with_partially_fillable() {
1633 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1)
1634 .with_partially_fillable(true);
1635 assert!(t.partially_fillable);
1636 }
1637
1638 #[test]
1639 fn twap_data_with_duration_of_part() {
1640 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::ZERO, 1, 1)
1641 .with_duration_of_part(DurationOfPart::limit(900));
1642 assert!(t.duration_of_part.is_limit_duration());
1643 assert_eq!(t.duration_of_part.duration(), Some(900));
1644 }
1645
1646 #[test]
1649 fn twap_data_display_at_mining_time() {
1650 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::from(24_000u64), 24, 3_600)
1651 .with_buy_amount(U256::from(1_000u64));
1652 let s = t.to_string();
1653 assert!(s.contains("24 × 3600s"), "got: {s}");
1654 assert!(s.contains("at-mining-time"), "got: {s}");
1655 assert!(s.contains("24000"), "got: {s}");
1656 assert!(s.contains("1000"), "got: {s}");
1657 }
1658
1659 #[test]
1660 fn twap_data_display_fixed_start() {
1661 let t = TwapData::sell(Address::ZERO, Address::ZERO, U256::from(1_000u64), 6, 7_200)
1662 .with_start_time(TwapStartTime::At(1_700_000_000));
1663 let s = t.to_string();
1664 assert!(s.contains("at-unix-1700000000"), "got: {s}");
1665 }
1666
1667 fn make_twap_struct() -> TwapStruct {
1670 TwapStruct {
1671 sell_token: Address::ZERO,
1672 buy_token: Address::ZERO,
1673 receiver: Address::ZERO,
1674 part_sell_amount: U256::from(250u64),
1675 min_part_limit: U256::from(100u64),
1676 t0: 0,
1677 n: 4,
1678 t: 3600,
1679 span: 0,
1680 app_data: B256::ZERO,
1681 }
1682 }
1683
1684 #[test]
1685 fn twap_struct_has_app_data() {
1686 let mut s = make_twap_struct();
1687 assert!(!s.has_app_data());
1688 s.app_data = B256::repeat_byte(0x01);
1689 assert!(s.has_app_data());
1690 }
1691
1692 #[test]
1693 fn twap_struct_has_custom_receiver() {
1694 let mut s = make_twap_struct();
1695 assert!(!s.has_custom_receiver());
1696 s.receiver = Address::repeat_byte(0x01);
1697 assert!(s.has_custom_receiver());
1698 }
1699
1700 #[test]
1701 fn twap_struct_start_is_fixed() {
1702 let mut s = make_twap_struct();
1703 assert!(!s.start_is_fixed());
1704 s.t0 = 1_000_000;
1705 assert!(s.start_is_fixed());
1706 }
1707
1708 #[test]
1709 fn twap_struct_display() {
1710 let s = make_twap_struct();
1711 let d = s.to_string();
1712 assert!(d.contains("twap-struct"), "got: {d}");
1713 assert!(d.contains("4 × 3600s"), "got: {d}");
1714 }
1715
1716 #[test]
1719 fn twap_struct_try_from_twap_data() {
1720 let data = TwapData::sell(Address::ZERO, Address::ZERO, U256::from(1000u64), 4, 3600)
1721 .with_buy_amount(U256::from(400u64))
1722 .with_start_time(TwapStartTime::At(5000))
1723 .with_duration_of_part(DurationOfPart::limit(1800));
1724 let s = TwapStruct::try_from(&data).unwrap();
1725 assert_eq!(s.part_sell_amount, U256::from(250u64));
1726 assert_eq!(s.min_part_limit, U256::from(100u64));
1727 assert_eq!(s.t0, 5000);
1728 assert_eq!(s.n, 4);
1729 assert_eq!(s.t, 3600);
1730 assert_eq!(s.span, 1800);
1731 }
1732
1733 #[test]
1734 fn twap_struct_try_from_twap_data_zero_parts_errors() {
1735 let mut data = TwapData::sell(Address::ZERO, Address::ZERO, U256::from(1000u64), 4, 3600);
1736 data.num_parts = 0;
1737 assert!(TwapStruct::try_from(&data).is_err());
1738 }
1739
1740 #[test]
1741 fn twap_data_from_twap_struct() {
1742 let s = TwapStruct {
1743 sell_token: Address::ZERO,
1744 buy_token: Address::ZERO,
1745 receiver: Address::ZERO,
1746 part_sell_amount: U256::from(250u64),
1747 min_part_limit: U256::from(100u64),
1748 t0: 5000,
1749 n: 4,
1750 t: 3600,
1751 span: 1800,
1752 app_data: B256::ZERO,
1753 };
1754 let data = TwapData::from(&s);
1755 assert_eq!(data.sell_amount, U256::from(1000u64));
1756 assert_eq!(data.buy_amount, U256::from(400u64));
1757 assert_eq!(data.start_time, TwapStartTime::At(5000));
1758 assert_eq!(data.num_parts, 4);
1759 assert_eq!(data.part_duration, 3600);
1760 assert!(data.duration_of_part.is_limit_duration());
1761 assert_eq!(data.duration_of_part.duration(), Some(1800));
1762 }
1763
1764 #[test]
1765 fn twap_data_from_twap_struct_at_mining_time() {
1766 let mut s = make_twap_struct();
1767 s.t0 = 0;
1768 s.span = 0;
1769 let data = TwapData::from(&s);
1770 assert!(data.start_time.is_at_mining_time());
1771 assert!(data.duration_of_part.is_auto());
1772 }
1773
1774 fn make_gpv2_order() -> GpV2OrderStruct {
1777 GpV2OrderStruct {
1778 sell_token: Address::ZERO,
1779 buy_token: Address::ZERO,
1780 receiver: Address::ZERO,
1781 sell_amount: U256::from(1000u64),
1782 buy_amount: U256::from(500u64),
1783 valid_to: 1_700_000_000,
1784 app_data: B256::ZERO,
1785 fee_amount: U256::ZERO,
1786 kind: B256::ZERO,
1787 partially_fillable: false,
1788 sell_token_balance: B256::ZERO,
1789 buy_token_balance: B256::ZERO,
1790 }
1791 }
1792
1793 #[test]
1794 fn gpv2_order_has_custom_receiver() {
1795 let mut o = make_gpv2_order();
1796 assert!(!o.has_custom_receiver());
1797 o.receiver = Address::repeat_byte(0x01);
1798 assert!(o.has_custom_receiver());
1799 }
1800
1801 #[test]
1802 fn gpv2_order_is_partially_fillable() {
1803 let mut o = make_gpv2_order();
1804 assert!(!o.is_partially_fillable());
1805 o.partially_fillable = true;
1806 assert!(o.is_partially_fillable());
1807 }
1808
1809 #[test]
1810 fn gpv2_order_display() {
1811 let o = make_gpv2_order();
1812 let s = o.to_string();
1813 assert!(s.contains("gpv2-order"), "got: {s}");
1814 assert!(s.contains("1000"), "got: {s}");
1815 assert!(s.contains("500"), "got: {s}");
1816 }
1817
1818 #[test]
1821 fn poll_result_success() {
1822 let r = PollResult::Success { order: None, signature: None };
1823 assert!(r.is_success());
1824 assert!(!r.is_retryable());
1825 assert!(!r.is_terminal());
1826 assert!(r.order_ref().is_none());
1827 assert!(r.as_error_message().is_none());
1828 }
1829
1830 #[test]
1831 fn poll_result_try_next_block() {
1832 let r = PollResult::TryNextBlock;
1833 assert!(r.is_try_next_block());
1834 assert!(r.is_retryable());
1835 assert!(!r.is_success());
1836 assert_eq!(r.get_block_number(), None);
1837 assert_eq!(r.get_epoch(), None);
1838 }
1839
1840 #[test]
1841 fn poll_result_try_on_block() {
1842 let r = PollResult::TryOnBlock { block_number: 42 };
1843 assert!(r.is_try_on_block());
1844 assert!(r.is_retryable());
1845 assert_eq!(r.get_block_number(), Some(42));
1846 }
1847
1848 #[test]
1849 fn poll_result_try_at_epoch() {
1850 let r = PollResult::TryAtEpoch { epoch: 1_700_000_000 };
1851 assert!(r.is_try_at_epoch());
1852 assert!(r.is_retryable());
1853 assert_eq!(r.get_epoch(), Some(1_700_000_000));
1854 }
1855
1856 #[test]
1857 fn poll_result_unexpected_error() {
1858 let r = PollResult::UnexpectedError { message: "boom".into() };
1859 assert!(r.is_unexpected_error());
1860 assert!(!r.is_retryable());
1861 assert_eq!(r.as_error_message(), Some("boom"));
1862 }
1863
1864 #[test]
1865 fn poll_result_dont_try_again() {
1866 let r = PollResult::DontTryAgain { reason: "expired".into() };
1867 assert!(r.is_dont_try_again());
1868 assert!(r.is_terminal());
1869 assert!(!r.is_retryable());
1870 assert_eq!(r.as_error_message(), Some("expired"));
1871 }
1872
1873 #[test]
1874 fn poll_result_display() {
1875 assert_eq!(PollResult::Success { order: None, signature: None }.to_string(), "success");
1876 assert_eq!(PollResult::TryNextBlock.to_string(), "try-next-block");
1877 assert_eq!(PollResult::TryOnBlock { block_number: 10 }.to_string(), "try-on-block(10)");
1878 assert_eq!(PollResult::TryAtEpoch { epoch: 99 }.to_string(), "try-at-epoch(99)");
1879 assert_eq!(
1880 PollResult::UnexpectedError { message: "x".into() }.to_string(),
1881 "unexpected-error(x)"
1882 );
1883 assert_eq!(
1884 PollResult::DontTryAgain { reason: "y".into() }.to_string(),
1885 "dont-try-again(y)"
1886 );
1887 }
1888
1889 #[test]
1892 fn proof_location_as_str() {
1893 assert_eq!(ProofLocation::Private.as_str(), "private");
1894 assert_eq!(ProofLocation::Emitted.as_str(), "emitted");
1895 assert_eq!(ProofLocation::Swarm.as_str(), "swarm");
1896 assert_eq!(ProofLocation::Waku.as_str(), "waku");
1897 assert_eq!(ProofLocation::Reserved.as_str(), "reserved");
1898 assert_eq!(ProofLocation::Ipfs.as_str(), "ipfs");
1899 }
1900
1901 #[test]
1902 fn proof_location_predicates() {
1903 assert!(ProofLocation::Private.is_private());
1904 assert!(ProofLocation::Emitted.is_emitted());
1905 assert!(ProofLocation::Swarm.is_swarm());
1906 assert!(ProofLocation::Waku.is_waku());
1907 assert!(ProofLocation::Reserved.is_reserved());
1908 assert!(ProofLocation::Ipfs.is_ipfs());
1909 assert!(!ProofLocation::Private.is_emitted());
1911 assert!(!ProofLocation::Ipfs.is_private());
1912 }
1913
1914 #[test]
1915 fn proof_location_default_is_private() {
1916 assert_eq!(ProofLocation::default(), ProofLocation::Private);
1917 }
1918
1919 #[test]
1920 fn proof_location_display() {
1921 assert_eq!(ProofLocation::Ipfs.to_string(), "ipfs");
1922 assert_eq!(ProofLocation::Waku.to_string(), "waku");
1923 }
1924
1925 #[test]
1926 fn proof_location_try_from_u8() {
1927 assert_eq!(ProofLocation::try_from(0u8).unwrap(), ProofLocation::Private);
1928 assert_eq!(ProofLocation::try_from(1u8).unwrap(), ProofLocation::Emitted);
1929 assert_eq!(ProofLocation::try_from(5u8).unwrap(), ProofLocation::Ipfs);
1930 assert!(ProofLocation::try_from(6u8).is_err());
1931 assert!(ProofLocation::try_from(255u8).is_err());
1932 }
1933
1934 #[test]
1935 fn proof_location_try_from_str() {
1936 assert_eq!(ProofLocation::try_from("private").unwrap(), ProofLocation::Private);
1937 assert_eq!(ProofLocation::try_from("ipfs").unwrap(), ProofLocation::Ipfs);
1938 assert!(ProofLocation::try_from("unknown").is_err());
1939 }
1940
1941 #[test]
1942 fn proof_location_into_u8() {
1943 let v: u8 = ProofLocation::Private.into();
1944 assert_eq!(v, 0);
1945 let v: u8 = ProofLocation::Ipfs.into();
1946 assert_eq!(v, 5);
1947 }
1948
1949 #[test]
1952 fn proof_struct_new() {
1953 let p = ProofStruct::new(ProofLocation::Swarm, vec![1, 2, 3]);
1954 assert!(p.is_swarm());
1955 assert!(p.has_data());
1956 assert_eq!(p.data_len(), 3);
1957 }
1958
1959 #[test]
1960 fn proof_struct_private() {
1961 let p = ProofStruct::private();
1962 assert!(p.is_private());
1963 assert!(p.is_empty());
1964 assert!(!p.has_data());
1965 assert_eq!(p.data_len(), 0);
1966 }
1967
1968 #[test]
1969 fn proof_struct_emitted() {
1970 let p = ProofStruct::emitted();
1971 assert!(p.is_emitted());
1972 assert!(p.is_empty());
1973 }
1974
1975 #[test]
1976 fn proof_struct_with_location() {
1977 let p = ProofStruct::private().with_location(ProofLocation::Ipfs);
1978 assert!(p.is_ipfs());
1979 }
1980
1981 #[test]
1982 fn proof_struct_with_data() {
1983 let p = ProofStruct::private().with_data(vec![0xCA, 0xFE]);
1984 assert!(p.has_data());
1985 assert_eq!(p.data_len(), 2);
1986 }
1987
1988 #[test]
1989 fn proof_struct_delegated_predicates() {
1990 assert!(ProofStruct::new(ProofLocation::Waku, vec![]).is_waku());
1991 assert!(ProofStruct::new(ProofLocation::Reserved, vec![]).is_reserved());
1992 }
1993
1994 #[test]
1995 fn proof_struct_display() {
1996 let p = ProofStruct::private();
1997 assert_eq!(p.to_string(), "proof(private)");
1998 let p = ProofStruct::new(ProofLocation::Ipfs, vec![1]);
1999 assert_eq!(p.to_string(), "proof(ipfs)");
2000 }
2001
2002 #[test]
2005 fn proof_location_try_from_str_all() {
2006 for (s, expected) in [
2007 ("emitted", ProofLocation::Emitted),
2008 ("swarm", ProofLocation::Swarm),
2009 ("waku", ProofLocation::Waku),
2010 ("reserved", ProofLocation::Reserved),
2011 ] {
2012 assert_eq!(ProofLocation::try_from(s).unwrap(), expected);
2013 }
2014 }
2015
2016 #[test]
2017 fn proof_location_try_from_u8_all() {
2018 assert_eq!(ProofLocation::try_from(2u8).unwrap(), ProofLocation::Swarm);
2019 assert_eq!(ProofLocation::try_from(3u8).unwrap(), ProofLocation::Waku);
2020 assert_eq!(ProofLocation::try_from(4u8).unwrap(), ProofLocation::Reserved);
2021 }
2022
2023 #[test]
2026 fn twap_data_serde_roundtrip() {
2027 let data = TwapData::sell(
2028 Address::repeat_byte(0x11),
2029 Address::repeat_byte(0x22),
2030 U256::from(1000u64),
2031 4,
2032 3600,
2033 )
2034 .with_buy_amount(U256::from(800u64))
2035 .with_start_time(TwapStartTime::At(1_000_000))
2036 .with_duration_of_part(DurationOfPart::limit(900));
2037
2038 let json = serde_json::to_string(&data).unwrap();
2039 let back: TwapData = serde_json::from_str(&json).unwrap();
2040 assert_eq!(back.sell_amount, data.sell_amount);
2041 assert_eq!(back.buy_amount, data.buy_amount);
2042 assert_eq!(back.num_parts, data.num_parts);
2043 assert_eq!(back.part_duration, data.part_duration);
2044 }
2045
2046 #[test]
2049 fn conditional_order_params_serde_roundtrip() {
2050 let params = ConditionalOrderParams::new(
2051 TWAP_HANDLER_ADDRESS,
2052 B256::repeat_byte(0xAB),
2053 vec![0xDE, 0xAD, 0xBE, 0xEF],
2054 );
2055 let json = serde_json::to_string(¶ms).unwrap();
2056 let back: ConditionalOrderParams = serde_json::from_str(&json).unwrap();
2057 assert_eq!(back.handler, params.handler);
2058 assert_eq!(back.salt, params.salt);
2059 assert_eq!(back.static_input, params.static_input);
2060 }
2061
2062 #[test]
2065 fn block_info_new() {
2066 let b = BlockInfo { block_number: 100, block_timestamp: 1_700_000_000 };
2067 assert_eq!(b.block_number, 100);
2068 assert_eq!(b.block_timestamp, 1_700_000_000);
2069 }
2070
2071 #[test]
2074 fn gpv2_order_try_from_bad_kind_fails() {
2075 let o = make_gpv2_order();
2076 let result = crate::order_signing::types::UnsignedOrder::try_from(&o);
2078 assert!(result.is_err());
2079 }
2080}
2081
2082#[derive(Debug, Clone)]
2090pub struct ProofStruct {
2091 pub location: ProofLocation,
2093 pub data: Vec<u8>,
2095}
2096
2097#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2103pub struct BlockInfo {
2104 pub block_number: u64,
2106 pub block_timestamp: u64,
2108}
2109
2110impl BlockInfo {
2111 #[must_use]
2122 pub const fn new(block_number: u64, block_timestamp: u64) -> Self {
2123 Self { block_number, block_timestamp }
2124 }
2125}
2126
2127impl fmt::Display for BlockInfo {
2128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2129 write!(f, "block(#{}, ts={})", self.block_number, self.block_timestamp)
2130 }
2131}
2132
2133#[derive(Debug, Clone, PartialEq, Eq)]
2139pub enum IsValidResult {
2140 Valid,
2142 Invalid {
2144 reason: String,
2146 },
2147}
2148
2149pub type IsValid = ();
2151
2152pub type IsNotValid = String;
2154
2155impl IsValidResult {
2156 #[must_use]
2162 pub const fn is_valid(&self) -> bool {
2163 matches!(self, Self::Valid)
2164 }
2165
2166 #[must_use]
2173 pub fn reason(&self) -> Option<&str> {
2174 match self {
2175 Self::Valid => None,
2176 Self::Invalid { reason } => Some(reason),
2177 }
2178 }
2179
2180 #[must_use]
2186 pub const fn valid() -> Self {
2187 Self::Valid
2188 }
2189
2190 #[must_use]
2200 pub fn invalid(reason: impl Into<String>) -> Self {
2201 Self::Invalid { reason: reason.into() }
2202 }
2203}
2204
2205impl fmt::Display for IsValidResult {
2206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2207 match self {
2208 Self::Valid => f.write_str("valid"),
2209 Self::Invalid { reason } => write!(f, "invalid: {reason}"),
2210 }
2211 }
2212}
2213
2214pub const DEFAULT_TEST_HANDLER: &str = "0x910d00a310f7Dc5B29FE73458F47f519be547D3d";
2220
2221pub const DEFAULT_TEST_SALT: &str =
2223 "0x9379a0bf532ff9a66ffde940f94b1a025d6f18803054c1aef52dc94b15255bbe";
2224
2225#[derive(Debug, Clone)]
2229pub struct TestConditionalOrderParams {
2230 pub handler: Address,
2232 pub salt: B256,
2234 pub static_input: Vec<u8>,
2236 pub is_single_order: bool,
2238}
2239
2240impl Default for TestConditionalOrderParams {
2241 fn default() -> Self {
2242 Self {
2243 handler: DEFAULT_TEST_HANDLER.parse().map_or(Address::ZERO, |a| a),
2244 salt: DEFAULT_TEST_SALT.parse().map_or(B256::ZERO, |s| s),
2245 static_input: Vec::new(),
2246 is_single_order: true,
2247 }
2248 }
2249}
2250
2251#[must_use]
2265pub fn create_test_conditional_order(
2266 overrides: Option<TestConditionalOrderParams>,
2267) -> ConditionalOrderParams {
2268 let test = overrides.unwrap_or_default();
2269 ConditionalOrderParams {
2270 handler: test.handler,
2271 salt: test.salt,
2272 static_input: test.static_input,
2273 }
2274}