Skip to content

Commit d9c88ab

Browse files
104 quote intent generation (#136)
1 parent bffbc10 commit d9c88ab

18 files changed

Lines changed: 448 additions & 76 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/solver-discovery/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ hex = "0.4"
2121
reqwest = "0.12"
2222
serde = { version = "1.0", features = ["derive"] }
2323
serde_json = "1.0"
24-
solver-types = { path = "../solver-types" }
24+
solver-types = { path = "../solver-types", features = ["oif-interfaces"] }
2525
thiserror = "1.0"
2626
tokio = { version = "1.0", features = ["sync", "rt-multi-thread"] }
2727
toml = { workspace = true }

crates/solver-discovery/src/implementations/offchain/_7683.rs

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
use crate::{DiscoveryError, DiscoveryInterface};
4545
use alloy_primitives::{Address, Bytes, U256};
4646
use alloy_provider::RootProvider;
47-
use alloy_sol_types::sol;
47+
use alloy_sol_types::SolType;
4848
use alloy_transport_http::Http;
4949
use async_trait::async_trait;
5050
use axum::{
@@ -59,7 +59,10 @@ use serde::{Deserialize, Serialize};
5959
use serde_json;
6060
use solver_types::{
6161
bytes32_to_address, current_timestamp, normalize_bytes32_address,
62-
standards::eip7683::{GasLimitOverrides, LockType, MandateOutput},
62+
standards::eip7683::{
63+
interfaces::{IInputSettlerCompact, IInputSettlerEscrow, SolMandateOutput, StandardOrder},
64+
GasLimitOverrides, LockType, MandateOutput,
65+
},
6366
with_0x_prefix, ConfigSchema, Eip7683OrderData, Field, FieldType, ImplementationRegistry,
6467
Intent, IntentMetadata, NetworksConfig, Schema,
6568
};
@@ -70,44 +73,6 @@ use std::sync::Arc;
7073
use tokio::sync::{mpsc, Mutex};
7174
use tower_http::cors::CorsLayer;
7275

73-
// Import the Solidity types for the OIF contracts
74-
sol! {
75-
#[sol(rpc)]
76-
interface IInputSettlerEscrow {
77-
function orderIdentifier(bytes calldata order) external view returns (bytes32);
78-
function openFor(bytes calldata order, address sponsor, bytes calldata signature) external;
79-
}
80-
81-
#[sol(rpc)]
82-
interface IInputSettlerCompact {
83-
function orderIdentifier(StandardOrder calldata order) external view returns (bytes32);
84-
}
85-
86-
#[derive(Debug)]
87-
struct StandardOrder {
88-
address user;
89-
uint256 nonce;
90-
uint256 originChainId;
91-
uint32 expires;
92-
uint32 fillDeadline;
93-
address inputOracle;
94-
uint256[2][] inputs;
95-
SolMandateOutput[] outputs;
96-
}
97-
98-
#[derive(Debug)]
99-
struct SolMandateOutput {
100-
bytes32 oracle;
101-
bytes32 settler;
102-
uint256 chainId;
103-
bytes32 token;
104-
uint256 amount;
105-
bytes32 recipient;
106-
bytes call;
107-
bytes context;
108-
}
109-
}
110-
11176
/// API representation of StandardOrder for JSON deserialization.
11277
///
11378
/// This struct represents the order format for the OIF contracts.
@@ -471,10 +436,8 @@ impl Eip7683OffchainDiscovery {
471436
///
472437
/// Returns `DiscoveryError::ParseError` if the order data cannot be decoded.
473438
fn parse_standard_order(order_bytes: &Bytes) -> Result<StandardOrder, DiscoveryError> {
474-
use alloy_sol_types::SolValue;
475-
476439
// Decode the StandardOrder struct from the order data
477-
let order = StandardOrder::abi_decode(order_bytes, true).map_err(|e| {
440+
let order = <StandardOrder as SolType>::abi_decode(order_bytes, true).map_err(|e| {
478441
DiscoveryError::ParseError(format!("Failed to decode StandardOrder: {}", e))
479442
})?;
480443

@@ -707,14 +670,13 @@ impl Eip7683OffchainDiscovery {
707670
settler_address: Address,
708671
lock_type: LockType,
709672
) -> Result<[u8; 32], DiscoveryError> {
710-
use alloy_sol_types::SolValue;
711-
712673
match lock_type {
713674
LockType::ResourceLock => {
714675
// Resource Lock (TheCompact) - use IInputSettlerCompact
715-
let std_order = StandardOrder::abi_decode(order_bytes, true).map_err(|e| {
716-
DiscoveryError::ParseError(format!("Failed to decode StandardOrder: {}", e))
717-
})?;
676+
let std_order =
677+
<StandardOrder as SolType>::abi_decode(order_bytes, true).map_err(|e| {
678+
DiscoveryError::ParseError(format!("Failed to decode StandardOrder: {}", e))
679+
})?;
718680
let compact = IInputSettlerCompact::new(settler_address, provider);
719681
let resp = compact
720682
.orderIdentifier(std_order)
@@ -806,7 +768,6 @@ impl Eip7683OffchainDiscovery {
806768
Ok(())
807769
}
808770
}
809-
810771
/// Handles intent submission requests.
811772
///
812773
/// This is the main request handler for the POST /intent endpoint.

crates/solver-order/src/implementations/standards/_7683.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ impl OrderInterface for Eip7683OrderImpl {
394394
if matches!(order_data.lock_type, Some(LockType::ResourceLock)) {
395395
return Ok(None);
396396
}
397+
397398
let raw_order_data = order_data.raw_order_data.as_ref().ok_or_else(|| {
398399
OrderError::ValidationFailed("Missing raw order data for off-chain order".to_string())
399400
})?;
@@ -405,7 +406,6 @@ impl OrderInterface for Eip7683OrderImpl {
405406
let signature = order_data.signature.as_ref().ok_or_else(|| {
406407
OrderError::ValidationFailed("Missing signature for off-chain order".to_string())
407408
})?;
408-
409409
// For the OIF contracts, we need to use the StandardOrder openFor
410410
// The raw_order_data contains the encoded StandardOrder
411411
// We just need to pass the order bytes, sponsor, and signature

crates/solver-service/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@ name = "solver"
99
path = "src/main.rs"
1010

1111
[dependencies]
12+
alloy-sol-types = "0.8"
1213
alloy-primitives = { version = "0.8", features = ["std", "serde"] }
1314
async-trait = "0.1"
1415
axum = "0.8"
1516
chrono = { version = "0.4", features = ["serde"] }
1617
clap = { version = "4.5", features = ["derive"] }
1718
env_logger = "0.11"
1819
futures = "0.3"
20+
hex = "0.4"
1921
jsonwebtoken = "9.3"
2022
once_cell = "1.20"
2123
reqwest = "0.12"
@@ -31,7 +33,7 @@ solver-order = { path = "../solver-order" }
3133
solver-pricing = { path = "../solver-pricing" }
3234
solver-settlement = { path = "../solver-settlement" }
3335
solver-storage = { path = "../solver-storage" }
34-
solver-types = { path = "../solver-types" }
36+
solver-types = { path = "../solver-types", features = ["oif-interfaces"] }
3537
thiserror = "1.0"
3638
tokio = { version = "1.0", features = ["full"] }
3739
toml = { workspace = true }
@@ -46,4 +48,4 @@ mockall = "0.13"
4648
solver-settlement = { path = "../solver-settlement", features = ["testing"] }
4749
solver-storage = { path = "../solver-storage", features = ["testing"] }
4850
tempfile = { workspace = true }
49-
tokio = { workspace = true }
51+
tokio = { workspace = true }

crates/solver-service/src/apis/quote/generation.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ impl QuoteGenerator {
122122
available_inputs: request.available_inputs.clone(),
123123
};
124124
let eta = self.calculate_eta(&request.preference);
125+
let lock_type = match custody_decision {
126+
CustodyDecision::ResourceLock { .. } => "resource_lock".to_string(),
127+
CustodyDecision::Escrow { kind } => match kind {
128+
EscrowKind::Permit2 => "permit2_escrow".to_string(),
129+
EscrowKind::Erc3009 => "erc3009_escrow".to_string(),
130+
},
131+
};
125132
let validity_seconds = self.get_quote_validity_seconds(config);
126133
Ok(Quote {
127134
orders: vec![order],
@@ -131,6 +138,7 @@ impl QuoteGenerator {
131138
quote_id,
132139
provider: "oif-solver".to_string(),
133140
cost: None,
141+
lock_type,
134142
})
135143
}
136144

@@ -330,7 +338,7 @@ impl QuoteGenerator {
330338
.as_ref()
331339
.and_then(|api| api.quote.as_ref())
332340
.map(|quote| quote.validity_seconds)
333-
.unwrap_or_default()
341+
.unwrap_or_default() // Default QuoteConfig validity_seconds
334342
}
335343
}
336344

@@ -662,6 +670,7 @@ mod tests {
662670
quote_id: "quote1".to_string(),
663671
provider: "test".to_string(),
664672
cost: None,
673+
lock_type: "permit2_escrow".to_string(),
665674
},
666675
Quote {
667676
orders: vec![],
@@ -674,6 +683,7 @@ mod tests {
674683
quote_id: "quote2".to_string(),
675684
provider: "test".to_string(),
676685
cost: None,
686+
lock_type: "permit2_escrow".to_string(),
677687
},
678688
Quote {
679689
orders: vec![],
@@ -686,6 +696,7 @@ mod tests {
686696
quote_id: "quote3".to_string(),
687697
provider: "test".to_string(),
688698
cost: None,
699+
lock_type: "permit2_escrow".to_string(),
689700
},
690701
];
691702

@@ -714,6 +725,7 @@ mod tests {
714725
quote_id: "quote1".to_string(),
715726
provider: "test".to_string(),
716727
cost: None,
728+
lock_type: "permit2_escrow".to_string(),
717729
},
718730
Quote {
719731
orders: vec![],
@@ -726,6 +738,7 @@ mod tests {
726738
quote_id: "quote2".to_string(),
727739
provider: "test".to_string(),
728740
cost: None,
741+
lock_type: "permit2_escrow".to_string(),
729742
},
730743
];
731744

@@ -763,7 +776,7 @@ mod tests {
763776
let mut config_no_api = ConfigBuilder::new().build();
764777
config_no_api.api = None;
765778
let validity_default = generator.get_quote_validity_seconds(&config_no_api);
766-
assert_eq!(validity_default, 20); // Default QuoteConfig has validity_seconds: 20
779+
assert_eq!(validity_default, 0); // if API none, use default 0
767780
}
768781

769782
#[test]

0 commit comments

Comments
 (0)