diff --git a/crates/dex-cli/src/cli/processor.rs b/crates/dex-cli/src/cli/processor.rs index 1712944..8af7312 100644 --- a/crates/dex-cli/src/cli/processor.rs +++ b/crates/dex-cli/src/cli/processor.rs @@ -1,6 +1,6 @@ use crate::cli::helper::HelperCommands; use crate::cli::{DexCommands, MakerCommands, TakerCommands}; -use crate::common::config::AggregatedConfig; +use crate::common::config::{AggregatedConfig, Seed}; use crate::common::{DEFAULT_CLIENT_TIMEOUT_SECS, InitOrderArgs, write_into_stdout}; use crate::contract_handlers; use clap::{Parser, Subcommand}; @@ -30,6 +30,14 @@ pub struct Cli { #[arg(short = 'c', long, default_value = DEFAULT_CONFIG_PATH, env = "DEX_NOSTR_CONFIG_PATH")] pub(crate) nostr_config_path: PathBuf, + /// Hex-encoded 32-byte seed used to derive internal wallet keys + #[arg(short = 's', long, env = "DEX_SEED_HEX")] + pub(crate) seed_hex: Option, + + /// Expiration time for the maker order in seconds + #[arg(short = 'e', long)] + pub(crate) maker_expiration_time: Option, + /// Command to execute #[command(subcommand)] command: Command, @@ -241,6 +249,7 @@ impl Cli { fee_amount, common_options, } => Self::_process_maker_init_order( + cli_app_context, MakerInitCliContext { first_lbtc_utxo, second_lbtc_utxo, @@ -354,6 +363,7 @@ impl Cli { } fn _process_maker_init_order( + cli_app_context: &CliAppContext, MakerInitCliContext { first_lbtc_utxo, second_lbtc_utxo, @@ -368,7 +378,7 @@ impl Cli { ) -> crate::error::Result { use contract_handlers::maker_init::{Utxos, handle, process_args, save_args_to_cache}; - let processed_args = process_args(account_index, init_order_args.into())?; + let processed_args = process_args(account_index, init_order_args.into(), &cli_app_context.agg_config)?; let (tx_res, args_to_save) = handle( processed_args, Utxos { @@ -406,7 +416,7 @@ impl Cli { agg_config.check_nostr_keypair_existence()?; - let processed_args = process_args(account_index, dcd_taproot_pubkey_gen)?; + let processed_args = process_args(account_index, dcd_taproot_pubkey_gen, agg_config)?; let event_to_publish = processed_args.extract_event(); let (tx_id, args_to_save) = handle( processed_args, @@ -420,7 +430,10 @@ impl Cli { fee_amount, is_offline, )?; - let res = relay_processor.place_order(event_to_publish, tx_id).await?; + let expiration_time = agg_config.maker_expiration_time; + let res = relay_processor + .place_order(event_to_publish, tx_id, expiration_time) + .await?; save_args_to_cache(&args_to_save)?; Ok(format!("[Maker] Creating order, tx_id: {tx_id}, event_id: {res:#?}")) } @@ -451,6 +464,7 @@ impl Cli { grantor_collateral_amount_to_burn, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -498,6 +512,7 @@ impl Cli { grantor_settlement_amount_to_burn, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -551,6 +566,7 @@ impl Cli { grantor_amount_to_burn, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -598,6 +614,7 @@ impl Cli { collateral_amount_to_deposit, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -632,6 +649,7 @@ impl Cli { filler_token_amount_to_return, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -671,6 +689,7 @@ impl Cli { oracle_signature, maker_order_event_id, relay_processor, + agg_config, ) .await?; let (tx_id, args_to_save) = handle( @@ -704,7 +723,14 @@ impl Cli { issue_amount, fee_amount, common_options, - } => Self::_process_helper_faucet(fee_utxo_outpoint, asset_name, issue_amount, fee_amount, common_options)?, + } => Self::_process_helper_faucet( + cli_app_context, + fee_utxo_outpoint, + asset_name, + issue_amount, + fee_amount, + common_options, + )?, HelperCommands::MintTokens { reissue_asset_outpoint, fee_utxo_outpoint, @@ -713,6 +739,7 @@ impl Cli { fee_amount, common_options, } => Self::_process_helper_mint_tokens( + cli_app_context, reissue_asset_outpoint, fee_utxo_outpoint, asset_name, @@ -725,13 +752,20 @@ impl Cli { fee_utxo, fee_amount, common_options, - } => Self::_process_helper_split_native_three(split_amount, fee_utxo, fee_amount, common_options)?, - HelperCommands::Address { account_index: index } => Self::_process_helper_address(index)?, + } => Self::_process_helper_split_native_three( + cli_app_context, + split_amount, + fee_utxo, + fee_amount, + common_options, + )?, + HelperCommands::Address { account_index: index } => Self::_process_helper_address(cli_app_context, index)?, HelperCommands::OracleSignature { price_at_current_block_height, settlement_height, oracle_account_index, } => Self::_process_helper_oracle_signature( + cli_app_context, price_at_current_block_height, settlement_height, oracle_account_index, @@ -809,6 +843,7 @@ impl Cli { } fn _process_helper_faucet( + cli_app_context: &CliAppContext, fee_utxo_outpoint: OutPoint, asset_name: String, issue_amount: u64, @@ -825,11 +860,13 @@ impl Cli { fee_amount, issue_amount, is_offline, + &cli_app_context.agg_config, )?; Ok("Asset creation -- done".to_string()) } fn _process_helper_mint_tokens( + cli_app_context: &CliAppContext, reissue_asset_outpoint: OutPoint, fee_utxo_outpoint: OutPoint, asset_name: String, @@ -848,11 +885,13 @@ impl Cli { reissue_amount, fee_amount, is_offline, + &cli_app_context.agg_config, )?; Ok("Asset minting -- done".to_string()) } fn _process_helper_split_native_three( + cli_app_context: &CliAppContext, split_amount: u64, fee_utxo: OutPoint, fee_amount: u64, @@ -861,17 +900,24 @@ impl Cli { is_offline, }: CommonOrderOptions, ) -> crate::error::Result { - let tx_res = - contract_handlers::split_utxo::handle(account_index, split_amount, fee_utxo, fee_amount, is_offline)?; + let tx_res = contract_handlers::split_utxo::handle( + account_index, + split_amount, + fee_utxo, + fee_amount, + is_offline, + &cli_app_context.agg_config, + )?; Ok(format!("Split utxo result tx_id: {tx_res:?}")) } - fn _process_helper_address(index: u32) -> crate::error::Result { - let (x_only_pubkey, addr) = contract_handlers::address::handle(index)?; + fn _process_helper_address(cli_app_context: &CliAppContext, index: u32) -> crate::error::Result { + let (x_only_pubkey, addr) = contract_handlers::address::handle(index, &cli_app_context.agg_config)?; Ok(format!("X Only Public Key: '{x_only_pubkey}', P2PK Address: '{addr}'")) } fn _process_helper_oracle_signature( + cli_app_context: &CliAppContext, price_at_current_block_height: u64, settlement_height: u32, oracle_account_index: Option, @@ -880,6 +926,7 @@ impl Cli { oracle_account_index, price_at_current_block_height, settlement_height, + &cli_app_context.agg_config, )?; Ok(format!( "Oracle signature for msg: '{}', signature: '{}', pubkey used: '{}'", @@ -912,7 +959,7 @@ impl Cli { }; agg_config.check_nostr_keypair_existence()?; - let processed_args = process_args(account_index, maker_order_event_id, relay_processor).await?; + let processed_args = process_args(account_index, maker_order_event_id, relay_processor, agg_config).await?; let (tx_id, args_to_save) = handle( processed_args, Utxos2 { @@ -956,7 +1003,7 @@ impl Cli { }; agg_config.check_nostr_keypair_existence()?; - let processed_args = process_args(account_index, maker_order_event_id, relay_processor).await?; + let processed_args = process_args(account_index, maker_order_event_id, relay_processor, agg_config).await?; let (tx_id, args_to_save) = handle( processed_args, Utxos3 { @@ -1002,7 +1049,7 @@ impl Cli { }; agg_config.check_nostr_keypair_existence()?; - let processed_args = process_args(account_index, maker_order_event_id, relay_processor).await?; + let processed_args = process_args(account_index, maker_order_event_id, relay_processor, agg_config).await?; let (tx_id, args_to_save) = handle( processed_args, Utxos4 { diff --git a/crates/dex-cli/src/common/config.rs b/crates/dex-cli/src/common/config.rs index 7b24ebd..1b29b43 100644 --- a/crates/dex-cli/src/common/config.rs +++ b/crates/dex-cli/src/common/config.rs @@ -12,10 +12,19 @@ use serde::{Deserialize, Deserializer}; use crate::error::CliError; use tracing::instrument; +/// `MAKER_EXPIRATION_TIME` = 31 days +const MAKER_EXPIRATION_TIME: u64 = 2_678_400; + +#[derive(Debug, Clone)] +pub struct Seed(pub SeedInner); +pub type SeedInner = [u8; 32]; + #[derive(Debug)] pub struct AggregatedConfig { pub nostr_keypair: Option, pub relays: Vec, + pub seed_hex: Seed, + pub maker_expiration_time: u64, } #[derive(Debug, Clone)] @@ -32,6 +41,38 @@ impl<'de> Deserialize<'de> for KeysWrapper { } } +impl FromStr for Seed { + type Err = CliError; + fn from_str(s: &str) -> Result { + let bytes = hex::decode(s).map_err(|err| crate::error::CliError::FromHex(err, s.to_string()))?; + if bytes.len() != 32 { + return Err(CliError::InvalidSeedLength { + got: bytes.len(), + expected: 32, + }); + } + let mut inner = [0u8; 32]; + inner.copy_from_slice(&bytes); + Ok(Seed(inner)) + } +} + +impl<'de> Deserialize<'de> for Seed { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Seed::from_str(&s).map_err(serde::de::Error::custom) + } +} + +impl From for ValueKind { + fn from(val: Seed) -> Self { + ValueKind::String(hex::encode(val.0)) + } +} + impl From for ValueKind { fn from(val: KeysWrapper) -> Self { ValueKind::String(val.0.secret_key().to_secret_hex()) @@ -53,20 +94,26 @@ impl AggregatedConfig { pub struct AggregatedConfigInner { pub nostr_keypair: Option, pub relays: Option>, + pub seed_hex: Option, + pub maker_expiration_time: u64, } let Cli { nostr_key, relays_list, nostr_config_path, + seed_hex, + maker_expiration_time, .. } = cli; - let mut config_builder = Config::builder().add_source( - File::from(nostr_config_path.clone()) - .format(FileFormat::Toml) - .required(DEFAULT_CONFIG_PATH != nostr_config_path.to_string_lossy().as_ref()), - ); + let mut config_builder = Config::builder() + .add_source( + File::from(nostr_config_path.clone()) + .format(FileFormat::Toml) + .required(DEFAULT_CONFIG_PATH != nostr_config_path.to_string_lossy().as_ref()), + ) + .set_default("maker_expiration_time", MAKER_EXPIRATION_TIME)?; if let Some(nostr_key) = nostr_key { tracing::debug!("Adding keypair value from CLI"); @@ -87,7 +134,19 @@ impl AggregatedConfig { )?; } - // TODO(Alex): add Liquid private key + if let Some(seed_hex) = seed_hex { + tracing::debug!("Adding SeedHex value from CLI"); + config_builder = config_builder.set_override_option("seed_hex", Some(seed_hex.clone()))?; + } + + if let Some(maker_expiration_time) = maker_expiration_time { + tracing::debug!( + "Adding expiration time from config, expiration_time: '{:?}'", + maker_expiration_time + ); + config_builder = + config_builder.set_override_option("maker_expiration_time", Some(*maker_expiration_time))?; + } let config = match config_builder.build()?.try_deserialize::() { Ok(conf) => Ok(conf), @@ -104,9 +163,15 @@ impl AggregatedConfig { return Err(ConfigExtended("Relays configuration is empty..".to_string())); } + let seed_hex = config + .seed_hex + .ok_or_else(|| ConfigExtended("No seed found in configuration and CLI".to_string()))?; + let aggregated_config = AggregatedConfig { nostr_keypair: config.nostr_keypair.map(|x| x.0), relays, + seed_hex, + maker_expiration_time: config.maker_expiration_time, }; tracing::debug!("Config gathered: '{:?}'", aggregated_config); diff --git a/crates/dex-cli/src/common/keys.rs b/crates/dex-cli/src/common/keys.rs index 679553f..b59c3f8 100644 --- a/crates/dex-cli/src/common/keys.rs +++ b/crates/dex-cli/src/common/keys.rs @@ -1,21 +1,15 @@ -use crate::common::settings::Settings; +use crate::common::config::AggregatedConfig; +use crate::error::CliError; use simplicityhl::elements::secp256k1_zkp as secp256k1; -/// # Panics +/// # Errors /// -/// Will panic if `SEED_HEX` is in incorrect encoding that differs from hex -#[must_use] -pub fn derive_secret_key_from_index(index: u32, settings: Settings) -> secp256k1::SecretKey { - // TODO (Oleks): fix possible panic, propagate error & move this parameter into config - let seed_vec = hex::decode(settings.seed_hex).expect("SEED_HEX must be hex"); - assert_eq!(seed_vec.len(), 32, "SEED_HEX must be 32 bytes hex"); +/// Returns `CliError::EcCurve` if the derived 32 byte array is not a valid secp256k1 secret key +pub fn derive_secret_key_from_index(index: u32, config: &AggregatedConfig) -> Result { + let mut seed = config.seed_hex.0; - let mut seed_bytes = [0u8; 32]; - seed_bytes.copy_from_slice(&seed_vec); - - let mut seed = seed_bytes; for (i, b) in index.to_be_bytes().iter().enumerate() { seed[24 + i] ^= *b; } - secp256k1::SecretKey::from_slice(&seed).unwrap() + secp256k1::SecretKey::from_slice(&seed).map_err(CliError::from) } diff --git a/crates/dex-cli/src/common/mod.rs b/crates/dex-cli/src/common/mod.rs index c7fdbe5..869fdde 100644 --- a/crates/dex-cli/src/common/mod.rs +++ b/crates/dex-cli/src/common/mod.rs @@ -1,6 +1,5 @@ pub mod config; pub mod keys; -pub mod settings; pub(crate) mod store; mod types; mod utils; diff --git a/crates/dex-cli/src/common/settings.rs b/crates/dex-cli/src/common/settings.rs deleted file mode 100644 index 9481494..0000000 --- a/crates/dex-cli/src/common/settings.rs +++ /dev/null @@ -1,45 +0,0 @@ -use config::{Case, Config}; -use tracing::instrument; - -pub struct Seed(pub SeedInner); -pub type SeedInner = [u8; 32]; -pub struct SeedHex { - pub seed_hex: String, -} - -impl SeedHex { - pub const ENV_NAME: &'static str = "SEED_HEX"; -} - -#[derive(Clone, Debug)] -pub struct Settings { - pub seed_hex: String, -} - -impl Settings { - /// Load CLI settings from environment variables. - /// - /// # Errors - /// - /// Returns: - /// - `CliError::Config` if building the configuration from the environment fails. - /// - `CliError::EnvNotSet` if the [`SeedHex::ENV_NAME`] environment variable is not set - /// or cannot be read as a UTF-8 string. - #[instrument(level = "debug", ret)] - pub fn load() -> crate::error::Result { - let cfg = Config::builder() - .add_source( - config::Environment::default() - .separator("__") - .convert_case(Case::ScreamingSnake), - ) - .build() - .map_err(crate::error::CliError::Config)?; - - let seed_hex = cfg - .get_string(SeedHex::ENV_NAME) - .map_err(|_| crate::error::CliError::EnvNotSet(SeedHex::ENV_NAME.to_string()))?; - - Ok(Self { seed_hex }) - } -} diff --git a/crates/dex-cli/src/contract_handlers/address.rs b/crates/dex-cli/src/contract_handlers/address.rs index 5729529..9df8def 100644 --- a/crates/dex-cli/src/contract_handlers/address.rs +++ b/crates/dex-cli/src/contract_handlers/address.rs @@ -1,13 +1,12 @@ +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use elements::bitcoin::{XOnlyPublicKey, secp256k1}; use simplicityhl::elements::{Address, AddressParams}; use simplicityhl_core::get_p2pk_address; -pub fn handle(index: u32) -> crate::error::Result<(XOnlyPublicKey, Address)> { - let settings = Settings::load()?; +pub fn handle(index: u32, config: &AggregatedConfig) -> crate::error::Result<(XOnlyPublicKey, Address)> { let keypair = - secp256k1::Keypair::from_secret_key(secp256k1::SECP256K1, &derive_secret_key_from_index(index, settings)); + secp256k1::Keypair::from_secret_key(secp256k1::SECP256K1, &derive_secret_key_from_index(index, config)?); let public_key = keypair.x_only_public_key().0; let address = get_p2pk_address(&public_key, &AddressParams::LIQUID_TESTNET) .map_err(|err| crate::error::CliError::P2pkAddress(err.to_string()))?; diff --git a/crates/dex-cli/src/contract_handlers/faucet.rs b/crates/dex-cli/src/contract_handlers/faucet.rs index cf5e794..d7cc251 100644 --- a/crates/dex-cli/src/contract_handlers/faucet.rs +++ b/crates/dex-cli/src/contract_handlers/faucet.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::Store; use contracts_adapter::basic::{IssueAssetResponse, ReissueAssetResponse}; use elements::bitcoin::hex::DisplayHex; @@ -18,6 +18,7 @@ pub fn create_asset( fee_amount: u64, issue_amount: u64, is_offline: bool, + config: &AggregatedConfig, ) -> crate::error::Result<()> { let store = Store::load()?; @@ -25,10 +26,9 @@ pub fn create_asset( return Err(crate::error::CliError::AssetNameExists { name: asset_name }); } - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let blinding_key = derive_public_blinder_key(); @@ -61,6 +61,7 @@ pub fn create_asset( Ok(()) } +#[allow(clippy::too_many_arguments)] pub fn mint_asset( account_index: u32, asset_name: String, @@ -69,6 +70,7 @@ pub fn mint_asset( reissue_amount: u64, fee_amount: u64, is_offline: bool, + config: &AggregatedConfig, ) -> crate::error::Result<()> { let store = Store::load()?; @@ -80,10 +82,9 @@ pub fn mint_asset( .map_err(|err| crate::error::CliError::Custom(format!("Failed to convert bytes to string, err: {err}")))?; let asset_entropy = entropy_to_midstate(&asset_entropy)?; - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let blinding_key = derive_public_blinder_key(); let ReissueAssetResponse { diff --git a/crates/dex-cli/src/contract_handlers/maker_funding.rs b/crates/dex-cli/src/contract_handlers/maker_funding.rs index 85d9eba..f4bd2b4 100644 --- a/crates/dex-cli/src/contract_handlers/maker_funding.rs +++ b/crates/dex-cli/src/contract_handlers/maker_funding.rs @@ -1,5 +1,5 @@ +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::{broadcast_tx_inner, decode_hex}; use contracts::DCDArguments; @@ -78,12 +78,11 @@ impl ProcessedArgs { pub fn process_args( account_index: u32, dcd_taproot_pubkey_gen: impl AsRef, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let taproot_pubkey_gen = dcd_taproot_pubkey_gen.as_ref().to_string(); diff --git a/crates/dex-cli/src/contract_handlers/maker_init.rs b/crates/dex-cli/src/contract_handlers/maker_init.rs index be17368..715c41c 100644 --- a/crates/dex-cli/src/contract_handlers/maker_init.rs +++ b/crates/dex-cli/src/contract_handlers/maker_init.rs @@ -1,5 +1,5 @@ +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::{broadcast_tx_inner, entropy_to_asset_id}; use contracts::DCDArguments; use contracts_adapter::dcd::{ @@ -77,12 +77,14 @@ impl TryInto for InnerDcdInitParams { } #[instrument(level = "debug", skip_all, err)] -pub fn process_args(account_index: u32, dcd_init_params: InnerDcdInitParams) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - +pub fn process_args( + account_index: u32, + dcd_init_params: InnerDcdInitParams, + config: &AggregatedConfig, +) -> crate::error::Result { let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let dcd_init_params: DcdInitParams = dcd_init_params .try_into() diff --git a/crates/dex-cli/src/contract_handlers/maker_settlement.rs b/crates/dex-cli/src/contract_handlers/maker_settlement.rs index a57345a..13d2afb 100644 --- a/crates/dex-cli/src/contract_handlers/maker_settlement.rs +++ b/crates/dex-cli/src/contract_handlers/maker_settlement.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -44,12 +44,11 @@ pub async fn process_args( grantor_amount_to_burn: u64, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/maker_termination_collateral.rs b/crates/dex-cli/src/contract_handlers/maker_termination_collateral.rs index 902512c..f07c096 100644 --- a/crates/dex-cli/src/contract_handlers/maker_termination_collateral.rs +++ b/crates/dex-cli/src/contract_handlers/maker_termination_collateral.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -39,12 +39,11 @@ pub async fn process_args( grantor_collateral_amount_to_burn: u64, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/maker_termination_settlement.rs b/crates/dex-cli/src/contract_handlers/maker_termination_settlement.rs index 5a15a89..dee51cb 100644 --- a/crates/dex-cli/src/contract_handlers/maker_termination_settlement.rs +++ b/crates/dex-cli/src/contract_handlers/maker_termination_settlement.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -45,12 +45,11 @@ pub async fn process_args( grantor_settlement_amount_to_burn: u64, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/merge_tokens.rs b/crates/dex-cli/src/contract_handlers/merge_tokens.rs index 8bb476b..83bb7ce 100644 --- a/crates/dex-cli/src/contract_handlers/merge_tokens.rs +++ b/crates/dex-cli/src/contract_handlers/merge_tokens.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -34,12 +34,11 @@ pub async fn process_args( account_index: u32, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/oracle_signature.rs b/crates/dex-cli/src/contract_handlers/oracle_signature.rs index 56610ba..439b39f 100644 --- a/crates/dex-cli/src/contract_handlers/oracle_signature.rs +++ b/crates/dex-cli/src/contract_handlers/oracle_signature.rs @@ -1,6 +1,6 @@ +use crate::common::config::AggregatedConfig; use crate::common::derive_public_oracle_keypair; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use contracts::oracle_msg; use elements::bitcoin::secp256k1; use elements::secp256k1_zkp::Message; @@ -11,12 +11,12 @@ pub fn handle( index: Option, price_at_current_block_height: u64, settlement_height: u32, + config: &AggregatedConfig, ) -> crate::error::Result<(PublicKey, Message, Signature)> { - let settings = Settings::load()?; let keypair = match index { None => derive_public_oracle_keypair()?, Some(index) => { - secp256k1::Keypair::from_secret_key(secp256k1::SECP256K1, &derive_secret_key_from_index(index, settings)) + secp256k1::Keypair::from_secret_key(secp256k1::SECP256K1, &derive_secret_key_from_index(index, config)?) } }; let pubkey = keypair.public_key(); diff --git a/crates/dex-cli/src/contract_handlers/split_utxo.rs b/crates/dex-cli/src/contract_handlers/split_utxo.rs index 360cc17..6b5e4fb 100644 --- a/crates/dex-cli/src/contract_handlers/split_utxo.rs +++ b/crates/dex-cli/src/contract_handlers/split_utxo.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use elements::bitcoin::hex::DisplayHex; use nostr::secp256k1; use simplicityhl::elements::pset::serialize::Serialize; @@ -13,11 +13,11 @@ pub fn handle( fee_utxo: OutPoint, fee_amount: u64, is_offline: bool, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let recipient_addr = get_p2pk_address(&keypair.x_only_public_key().0, &AddressParams::LIQUID_TESTNET).unwrap(); let transaction = contracts_adapter::basic::split_native_three( diff --git a/crates/dex-cli/src/contract_handlers/taker_early_termination.rs b/crates/dex-cli/src/contract_handlers/taker_early_termination.rs index 5429fef..25fe76e 100644 --- a/crates/dex-cli/src/contract_handlers/taker_early_termination.rs +++ b/crates/dex-cli/src/contract_handlers/taker_early_termination.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -45,12 +45,11 @@ pub async fn process_args( filler_token_amount_to_return: u64, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/taker_funding.rs b/crates/dex-cli/src/contract_handlers/taker_funding.rs index bb42638..b6426d9 100644 --- a/crates/dex-cli/src/contract_handlers/taker_funding.rs +++ b/crates/dex-cli/src/contract_handlers/taker_funding.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -41,12 +41,11 @@ pub async fn process_args( collateral_amount_to_deposit: u64, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/contract_handlers/taker_settlement.rs b/crates/dex-cli/src/contract_handlers/taker_settlement.rs index 9d9372c..4d6b28f 100644 --- a/crates/dex-cli/src/contract_handlers/taker_settlement.rs +++ b/crates/dex-cli/src/contract_handlers/taker_settlement.rs @@ -1,6 +1,6 @@ use crate::common::broadcast_tx_inner; +use crate::common::config::AggregatedConfig; use crate::common::keys::derive_secret_key_from_index; -use crate::common::settings::Settings; use crate::common::store::SledError; use crate::common::store::utils::OrderParams; use crate::contract_handlers::common::get_order_params; @@ -49,12 +49,11 @@ pub async fn process_args( oracle_signature: String, maker_order_event_id: EventId, relay_processor: &RelayProcessor, + config: &AggregatedConfig, ) -> crate::error::Result { - let settings = Settings::load().map_err(|err| crate::error::CliError::EnvNotSet(err.to_string()))?; - let keypair = secp256k1::Keypair::from_secret_key( secp256k1::SECP256K1, - &derive_secret_key_from_index(account_index, settings.clone()), + &derive_secret_key_from_index(account_index, config)?, ); let order_params: OrderParams = get_order_params(maker_order_event_id, relay_processor).await?; diff --git a/crates/dex-cli/src/error.rs b/crates/dex-cli/src/error.rs index c0d3ee0..dcd6df4 100644 --- a/crates/dex-cli/src/error.rs +++ b/crates/dex-cli/src/error.rs @@ -33,6 +33,8 @@ pub enum CliError { AssetNameAbsent { name: String }, #[error("Failed to covert value from hex, err: '{0}', value: '{1}'")] FromHex(hex::FromHexError, String), + #[error("Invalid Seed length: expected {expected}, got {got}")] + InvalidSeedLength { got: usize, expected: usize }, #[error("Failed to convert dcd inner params into dcd params, err msg: '{0}'")] InnerDcdConversion(String), #[error("Expected at least {expected} elements, got {got}")] diff --git a/crates/dex-nostr-relay/src/handlers/place_order.rs b/crates/dex-nostr-relay/src/handlers/place_order.rs index 5388486..478d1e7 100644 --- a/crates/dex-nostr-relay/src/handlers/place_order.rs +++ b/crates/dex-nostr-relay/src/handlers/place_order.rs @@ -4,13 +4,24 @@ use crate::types::{BLOCKSTREAM_MAKER_CONTENT, CustomKind, MakerOrderEvent, Maker use nostr::{EventBuilder, EventId, Timestamp}; use simplicity::elements::Txid; -pub async fn handle(client: &RelayClient, tags: OrderPlaceEventTags, tx_id: Txid) -> crate::error::Result { +pub async fn handle( + client: &RelayClient, + tags: OrderPlaceEventTags, + tx_id: Txid, + maker_expiration_time: u64, +) -> crate::error::Result { let client_signer = client.get_signer().await?; let client_pubkey = client_signer.get_public_key().await?; let timestamp_now = Timestamp::now(); - let tags = MakerOrderEvent::form_tags(tags, tx_id, client_pubkey)?; + let tags = MakerOrderEvent::form_tags( + tags, + tx_id, + client_pubkey, + maker_expiration_time, + timestamp_now.as_u64(), + )?; let maker_order = EventBuilder::new(MakerOrderKind::get_kind(), BLOCKSTREAM_MAKER_CONTENT) .tags(tags) .custom_created_at(timestamp_now); diff --git a/crates/dex-nostr-relay/src/relay_processor.rs b/crates/dex-nostr-relay/src/relay_processor.rs index bee1467..622055e 100644 --- a/crates/dex-nostr-relay/src/relay_processor.rs +++ b/crates/dex-nostr-relay/src/relay_processor.rs @@ -82,8 +82,13 @@ impl RelayProcessor { /// /// Returns an error if constructing or publishing the order event fails, /// or if the relay client encounters an error while sending the event. - pub async fn place_order(&self, tags: OrderPlaceEventTags, tx_id: Txid) -> crate::error::Result { - let event_id = handlers::place_order::handle(&self.relay_client, tags, tx_id).await?; + pub async fn place_order( + &self, + tags: OrderPlaceEventTags, + tx_id: Txid, + maker_expiration_time: u64, + ) -> crate::error::Result { + let event_id = handlers::place_order::handle(&self.relay_client, tags, tx_id, maker_expiration_time).await?; Ok(event_id) } diff --git a/crates/dex-nostr-relay/src/types.rs b/crates/dex-nostr-relay/src/types.rs index 0cb4a4f..e302f02 100644 --- a/crates/dex-nostr-relay/src/types.rs +++ b/crates/dex-nostr-relay/src/types.rs @@ -2,7 +2,7 @@ use crate::handlers::common::timestamp_to_chrono_utc; use crate::relay_processor::OrderPlaceEventTags; use chrono::TimeZone; use contracts::DCDArguments; -use nostr::{Event, EventId, Kind, PublicKey, Tag, TagKind, Tags}; +use nostr::{Event, EventId, Kind, PublicKey, Tag, TagKind, Tags, Timestamp}; use simplicity::elements::AssetId; use simplicityhl::elements::Txid; use std::borrow::Cow; @@ -27,9 +27,6 @@ pub const POW_DIFFICULTY: u8 = 1; pub const BLOCKSTREAM_MAKER_CONTENT: &str = "Liquid order [Maker]!"; pub const BLOCKSTREAM_TAKER_REPLY_CONTENT: &str = "Liquid reply [Taker]!"; pub const BLOCKSTREAM_MAKER_REPLY_CONTENT: &str = "Liquid reply [Maker]!"; -/// `MAKER_EXPIRATION_TIME` = 31 days -/// TODO: move to the config -pub const MAKER_EXPIRATION_TIME: u64 = 2_678_400; pub const MAKER_DCD_ARG_TAG: &str = "dcd_arguments_(hex&bincode)"; pub const MAKER_DCD_TAPROOT_TAG: &str = "dcd_taproot_pubkey_gen"; pub const MAKER_FILLER_ASSET_ID_TAG: &str = "filler_asset_id"; @@ -395,6 +392,8 @@ impl MakerOrderEvent { tags: OrderPlaceEventTags, tx_id: Txid, client_pubkey: PublicKey, + maker_expiration_time: u64, + timestamp_now: u64, ) -> crate::error::Result> { let dcd_arguments = { let x = bincode::encode_to_vec(&tags.dcd_arguments, bincode::config::standard()).map_err(|err| { @@ -407,7 +406,7 @@ impl MakerOrderEvent { }; Ok(vec![ Tag::public_key(client_pubkey), - // Tag::expiration(Timestamp::from(timestamp_now.as_u64() + MAKER_EXPIRATION_TIME)), + Tag::expiration(Timestamp::from(timestamp_now + maker_expiration_time)), Tag::custom(TagKind::Custom(Cow::from(MAKER_DCD_ARG_TAG)), [dcd_arguments]), Tag::custom( TagKind::Custom(Cow::from(MAKER_DCD_TAPROOT_TAG)), diff --git a/crates/dex-nostr-relay/tests/test_order_placing.rs b/crates/dex-nostr-relay/tests/test_order_placing.rs index ed76700..6049411 100644 --- a/crates/dex-nostr-relay/tests/test_order_placing.rs +++ b/crates/dex-nostr-relay/tests/test_order_placing.rs @@ -4,13 +4,12 @@ mod tests { use crate::utils::{DEFAULT_CLIENT_TIMEOUT, DEFAULT_RELAY_LIST, TEST_LOGGER}; use std::str::FromStr; - use std::time::Duration; - use dex_nostr_relay::relay_client::ClientConfig; use dex_nostr_relay::relay_processor::{ListOrdersEventFilter, OrderPlaceEventTags, RelayProcessor}; use dex_nostr_relay::types::{CustomKind, MakerOrderKind, ReplyOption, TakerReplyOrderKind}; use nostr::{Keys, ToBech32}; use simplicityhl::elements::Txid; + use std::time::Duration; use tracing::{info, instrument}; @@ -38,6 +37,7 @@ mod tests { .place_order( OrderPlaceEventTags::default(), Txid::from_str("87a4c9b2060ff698d9072d5f95b3dde01efe0994f95c3cd6dd7348cb3a4e4e40").unwrap(), + 1011, ) .await?; info!("=== placed order event id: {}", placed_order_event_id);