Skip to content

Commit 3e266fd

Browse files
committed
feat: add finality status from CLI defaulting to AcceptedOnL2
1 parent c7dab3a commit 3e266fd

File tree

7 files changed

+556
-23
lines changed

7 files changed

+556
-23
lines changed

bin/sozo/src/commands/options/transaction.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::{bail, Result};
22
use clap::Args;
33
use dojo_utils::{FeeConfig, TxnAction, TxnConfig};
4+
use starknet::core::types::TransactionFinalityStatus;
45

56
#[derive(Debug, Clone, Args, Default)]
67
#[command(next_help_heading = "Transaction options")]
@@ -62,6 +63,15 @@ pub struct TransactionOptions {
6263
#[arg(global = true)]
6364
#[arg(default_value = "10")]
6465
pub max_calls: Option<usize>,
66+
67+
#[arg(long)]
68+
#[arg(help = "The finality status to wait for. Since 0.14, the nodes syncing is sometime \
69+
not fast enough to propagate the transaction to the nodes in the \
70+
PRE-CONFIRMED state. The default is ACCEPTED_ON_L2. Available options are: \
71+
PRE-CONFIRMED, ACCEPTED_ON_L2, ACCEPTED_ON_L1.")]
72+
#[arg(global = true)]
73+
#[arg(default_value = "ACCEPTED_ON_L2")]
74+
pub finality_status: Option<String>,
6575
}
6676

6777
impl TransactionOptions {
@@ -89,6 +99,7 @@ impl TransactionOptions {
8999
},
90100
walnut: self.walnut,
91101
max_calls: self.max_calls,
102+
finality_status: parse_finality_status(self.finality_status.clone())?,
92103
}),
93104
}
94105
}
@@ -111,10 +122,33 @@ impl TryFrom<TransactionOptions> for TxnConfig {
111122
l2_gas_price: value.l2_gas_price,
112123
},
113124
max_calls: value.max_calls,
125+
finality_status: parse_finality_status(value.finality_status.clone())?,
114126
})
115127
}
116128
}
117129

130+
/// Parses the finality status from a string.
131+
/// If no status is provided, the default is ACCEPTED_ON_L2.
132+
/// # Arguments
133+
///
134+
/// * `status` - The finality status to parse.
135+
///
136+
/// # Returns
137+
///
138+
/// The parsed finality status.
139+
fn parse_finality_status(status: Option<String>) -> Result<TransactionFinalityStatus> {
140+
if let Some(status) = status {
141+
match status.to_uppercase().as_str() {
142+
"PRE_CONFIRMED" => Ok(TransactionFinalityStatus::PreConfirmed),
143+
"ACCEPTED_ON_L2" => Ok(TransactionFinalityStatus::AcceptedOnL2),
144+
"ACCEPTED_ON_L1" => Ok(TransactionFinalityStatus::AcceptedOnL1),
145+
_ => bail!("Invalid finality status: {}", status),
146+
}
147+
} else {
148+
Ok(TransactionFinalityStatus::AcceptedOnL2)
149+
}
150+
}
151+
118152
#[cfg(test)]
119153
mod tests {
120154
use anyhow::Result;
@@ -134,6 +168,7 @@ mod tests {
134168
l2_gas_price: Some(1_000),
135169
walnut: false,
136170
max_calls: Some(10),
171+
finality_status: Some("PRE_CONFIRMED".to_string()),
137172
};
138173

139174
let config: TxnConfig = opts.try_into()?;
@@ -150,6 +185,32 @@ mod tests {
150185
assert_eq!(config.fee_config.l2_gas, Some(10_000));
151186
assert_eq!(config.fee_config.l2_gas_price, Some(1_000));
152187

188+
assert_eq!(config.finality_status, TransactionFinalityStatus::PreConfirmed);
189+
190+
Ok(())
191+
}
192+
193+
#[test]
194+
fn test_parse_finality_status() -> Result<()> {
195+
matches!(
196+
parse_finality_status(Some("PRE_CONFIRMED".to_string())),
197+
Ok(TransactionFinalityStatus::PreConfirmed)
198+
);
199+
200+
matches!(
201+
parse_finality_status(Some("ACCEPTED_ON_L2".to_string())),
202+
Ok(TransactionFinalityStatus::AcceptedOnL2)
203+
);
204+
205+
matches!(
206+
parse_finality_status(Some("ACCEPTED_ON_L1".to_string())),
207+
Ok(TransactionFinalityStatus::AcceptedOnL1)
208+
);
209+
210+
matches!(parse_finality_status(None), Ok(TransactionFinalityStatus::AcceptedOnL2));
211+
212+
assert!(parse_finality_status(Some("INVALID".to_string())).is_err());
213+
153214
Ok(())
154215
}
155216
}

crates/dojo/utils/src/tx/deployer.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,9 @@ where
8888
);
8989

9090
if self.txn_config.wait {
91-
let receipt =
92-
TransactionWaiter::new(transaction_hash, &self.account.provider()).await?;
91+
let receipt = TransactionWaiter::new(transaction_hash, &self.account.provider())
92+
.with_tx_status(self.txn_config.finality_status)
93+
.await?;
9394

9495
if self.txn_config.receipt {
9596
return Ok((

crates/dojo/utils/src/tx/invoker.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,9 @@ where
6565
trace!(transaction_hash = format!("{:#066x}", tx.transaction_hash), "Invoke contract.");
6666

6767
if self.txn_config.wait {
68-
let receipt =
69-
TransactionWaiter::new(tx.transaction_hash, &self.account.provider()).await?;
68+
let receipt = TransactionWaiter::new(tx.transaction_hash, &self.account.provider())
69+
.with_tx_status(self.txn_config.finality_status)
70+
.await?;
7071

7172
if self.txn_config.receipt {
7273
return Ok(TransactionResult::HashReceipt(tx.transaction_hash, Box::new(receipt)));
@@ -114,6 +115,7 @@ where
114115
if self.txn_config.wait {
115116
let receipt =
116117
TransactionWaiter::new(tx.transaction_hash, &self.account.provider())
118+
.with_tx_status(self.txn_config.finality_status)
117119
.await?;
118120

119121
if self.txn_config.receipt {
@@ -141,8 +143,9 @@ where
141143
);
142144

143145
if self.txn_config.wait {
144-
let receipt =
145-
TransactionWaiter::new(tx.transaction_hash, &self.account.provider()).await?;
146+
let receipt = TransactionWaiter::new(tx.transaction_hash, &self.account.provider())
147+
.with_tx_status(self.txn_config.finality_status)
148+
.await?;
146149

147150
if self.txn_config.receipt {
148151
return Ok(vec![TransactionResult::HashReceipt(

crates/dojo/utils/src/tx/mod.rs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use starknet::accounts::{
1515
};
1616
use starknet::core::types::{
1717
BlockId, BlockTag, DeclareTransactionResult, DeployAccountTransactionResult, Felt,
18-
InvokeTransactionResult, TransactionReceiptWithBlockInfo,
18+
InvokeTransactionResult, TransactionFinalityStatus, TransactionReceiptWithBlockInfo,
1919
};
2020
use starknet::providers::jsonrpc::HttpTransport;
2121
use starknet::providers::{AnyProvider, JsonRpcClient, Provider};
@@ -38,7 +38,7 @@ pub struct FeeConfig {
3838
}
3939

4040
/// The transaction configuration to use when sending a transaction.
41-
#[derive(Debug, Copy, Clone, Default)]
41+
#[derive(Debug, Copy, Clone)]
4242
pub struct TxnConfig {
4343
/// Whether to wait for the transaction to be accepted or reverted on L2.
4444
pub wait: bool,
@@ -52,6 +52,24 @@ pub struct TxnConfig {
5252
/// This number could vary depending on the calls content, and is mostly
5353
/// here to ensure the migration is not stuck if too much resources have to be registered.
5454
pub max_calls: Option<usize>,
55+
/// The finality status to wait for.
56+
/// Since 0.14, the nodes syncing is sometime not fast enough to propagate the transaction to
57+
/// the nodes in the PRE-CONFIRMED state. Exposing the finality status allows to wait for
58+
/// the transaction to be accepted on L2 when a more robust migration is needed.
59+
pub finality_status: TransactionFinalityStatus,
60+
}
61+
62+
impl Default for TxnConfig {
63+
fn default() -> Self {
64+
Self {
65+
wait: true,
66+
receipt: false,
67+
walnut: false,
68+
fee_config: FeeConfig::default(),
69+
max_calls: None,
70+
finality_status: TransactionFinalityStatus::AcceptedOnL2,
71+
}
72+
}
5573
}
5674

5775
#[derive(Debug, Clone)]
@@ -62,6 +80,7 @@ pub enum TxnAction {
6280
fee_config: FeeConfig,
6381
walnut: bool,
6482
max_calls: Option<usize>,
83+
finality_status: TransactionFinalityStatus,
6584
},
6685
Estimate,
6786
Simulate,

0 commit comments

Comments
 (0)