Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 6 additions & 7 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,23 @@ jobs:
runs-on: ubuntu-latest
# container: michaelfbryan/mdbook-docker-image:latest


steps:
- name: Checkout 🛎
uses: actions/checkout@v4

- name: Setup | Rust
id: rustup
uses: ATiltedTree/setup-rust@v1
uses: dtolnay/rust-toolchain@stable
with:
rust-version: stable
components: rustfmt

- name: Setup | Just
id: just
uses: extractions/setup-just@v1

- name: Setup PATH # For using the pre-built mdbook
run: echo $GITHUB_WORKSPACE/bin >> $GITHUB_PATH

- name: Install dependencies 🔧
run: just install-docs-fast && just setup-docs

Expand All @@ -55,7 +54,7 @@ jobs:
uses: actions/upload-pages-artifact@v3
with:
# Upload book repository
path: './docs/book/html'
path: "./docs/book/html"

# Deploy job
deploy:
Expand All @@ -65,8 +64,8 @@ jobs:

# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
permissions:
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source
pages: write # to deploy to Pages
id-token: write # to verify the deployment originates from an appropriate source

# Deploy to the github-pages environment
environment:
Expand Down
127 changes: 127 additions & 0 deletions cw-orch-daemon/src/env.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//! This regroups all env variables used by cw-orch-daemon. It allows for easier documentation and env variable management
//! This is used to import environment variables with safe names (and at a centralized location)
//! To get the env variable parsed value, you can use
//! ```rust,no_run
//! use cw_orch_daemon::env::DaemonEnvVars;
//! let env_variable = DaemonEnvVars::state_file();
//! ```

use std::{env, path::PathBuf, str::FromStr};

use cosmwasm_std::StdError;

const DEFAULT_TX_QUERY_RETRIES: usize = 50;

pub const STATE_FILE_ENV_NAME: &str = "STATE_FILE";
pub const GAS_BUFFER_ENV_NAME: &str = "CW_ORCH_GAS_BUFFER";
pub const MIN_GAS_ENV_NAME: &str = "CW_ORCH_MIN_GAS";
pub const MAX_TX_QUERIES_RETRY_ENV_NAME: &str = "CW_ORCH_MAX_TX_QUERY_RETRIES";
pub const MIN_BLOCK_SPEED_ENV_NAME: &str = "CW_ORCH_MIN_BLOCK_SPEED";
pub const WALLET_BALANCE_ASSERTION_ENV_NAME: &str = "CW_ORCH_WALLET_BALANCE_ASSERTION";
pub const LOGS_ACTIVATION_MESSAGE_ENV_NAME: &str = "CW_ORCH_LOGS_ACTIVATION_MESSAGE";

pub struct DaemonEnvVars {}
impl DaemonEnvVars {
/// Optional - Path
/// This is the path to the state file
/// `folder/file.json` will resolve to `~/.cw-orchestrator/folder/file.json`
/// `./folder/file.json` will resolve `$pwd/folder/file.json`
/// `../folder/file.json` will resolve `$pwd/../folder/file.json`
/// `/usr/var/file.json` will resolve to `/usr/var/file.json`
/// Defaults to "~./cw-orchestrator/state.json"
pub fn state_file() -> PathBuf {
let state_file_string = env::var(STATE_FILE_ENV_NAME).unwrap_or("state.json".to_string());
parse_with_log(state_file_string, STATE_FILE_ENV_NAME)
}

/// Optional - Float
/// This allows changing the gas buffer applied after tx simulation
/// If not specified, a more complex algorithm is applied for dealing with small gas fee cases
pub fn gas_buffer() -> Option<f64> {
if let Ok(str_value) = env::var(GAS_BUFFER_ENV_NAME) {
Some(parse_with_log(str_value, GAS_BUFFER_ENV_NAME))
} else {
None
}
}

/// Optional - Integer
/// Defaults to None
/// Minimum gas amount. Useful when transaction still won't pass even when setting a high gas_buffer or for mixed transaction scripts
pub fn min_gas() -> Option<u64> {
if let Ok(str_value) = env::var(MIN_GAS_ENV_NAME) {
Some(parse_with_log(str_value, MIN_GAS_ENV_NAME))
} else {
None
}
}

/// Optional - Integer
/// Defaults to [`DEFAULT_TX_QUERY_RETRIES`]
/// This changes the number of tx queries before it fails if it doesn't find any result
pub fn max_tx_query_retries() -> usize {
if let Ok(str_value) = env::var(MAX_TX_QUERIES_RETRY_ENV_NAME) {
parse_with_log(str_value, MAX_TX_QUERIES_RETRY_ENV_NAME)
} else {
DEFAULT_TX_QUERY_RETRIES
}
}

/// Optional - Integer
/// Defaults to 1
/// Minimum block speed in seconds. Useful when the block speeds are varying a lot
pub fn min_block_speed() -> u64 {
if let Ok(str_value) = env::var(MIN_BLOCK_SPEED_ENV_NAME) {
parse_with_log(str_value, MIN_BLOCK_SPEED_ENV_NAME)
} else {
1
}
}

/// Optional - boolean
/// Defaults to "true"
/// Disable wallet balance assertion.
/// When balance assertion is enabled, it asserts that the balance of the sender is sufficient before submitting any transactions (during the simulation step)
pub fn wallet_balance_assertion() -> bool {
if let Ok(str_value) = env::var(WALLET_BALANCE_ASSERTION_ENV_NAME) {
parse_with_log(str_value, WALLET_BALANCE_ASSERTION_ENV_NAME)
} else {
true
}
}

/// Optional - boolean
/// Defaults to "true"
/// Disable the "Enable Logs" message
/// It allows forcing cw-orch to not output anything
pub fn logs_message() -> bool {
if let Ok(str_value) = env::var(LOGS_ACTIVATION_MESSAGE_ENV_NAME) {
parse_with_log(str_value, LOGS_ACTIVATION_MESSAGE_ENV_NAME)
} else {
true
}
}
}

/// Fetches the default state folder.
/// This function should only error if the home_dir is not set and the `dirs` library is unable to fetch it
/// This happens only in rare cases
pub fn default_state_folder() -> Result<PathBuf, StdError> {
dirs::home_dir().map(|home| home.join(".cw-orchestrator"))
.ok_or( StdError::generic_err(
format!(
"Your machine doesn't have a home folder. You can't use relative path for the state file such as 'state.json'.
Please use an absolute path ('/home/root/state.json') or a dot-prefixed-relative path ('./state.json') in the {} env variable.",
STATE_FILE_ENV_NAME
)))
}

fn parse_with_log<F: FromStr<Err = E>, E: std::fmt::Display>(
value: String,
env_var_name: &str,
) -> F {
match value.parse() {
Ok(parsed) => parsed,
Err(e) => panic!("Couldn't parse content of env var {env_var_name}, error : {e}"),
}
}
1 change: 1 addition & 0 deletions cw-orch-daemon/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ pub mod state;
pub mod sync;
pub mod tx_resp;
// expose these as mods as they can grow
pub mod env;
pub mod keys;
pub mod live_mock;
mod log;
Expand Down
4 changes: 2 additions & 2 deletions cw-orch-daemon/src/log.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cw_orch_core::CwOrchEnvVars;
use crate::env::DaemonEnvVars;

use crate::DaemonError;

Expand All @@ -10,7 +10,7 @@ static LOGS_DISABLED: Once = Once::new();
pub fn print_if_log_disabled() -> Result<(), DaemonError> {
LOGS_DISABLED.call_once(|| {
// Here we check for logging capabilities.
if !log::log_enabled!(log::Level::Info) && !CwOrchEnvVars::load().map(|env|env.disable_logs_message).unwrap_or(false){
if !log::log_enabled!(log::Level::Info) && DaemonEnvVars::logs_message(){
println!(
"Warning: It seems like you haven't enabled logs. In order to do so, you have to :
- use `env_logger::init()` at the start of your script.
Expand Down
15 changes: 8 additions & 7 deletions cw-orch-daemon/src/queriers/node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::{cmp::min, time::Duration};

use crate::{cosmos_modules, error::DaemonError, tx_resp::CosmTxResponse, Daemon};
use crate::{
cosmos_modules, env::DaemonEnvVars, error::DaemonError, tx_resp::CosmTxResponse, Daemon,
};

use cosmrs::{
proto::cosmos::{
Expand All @@ -13,7 +15,6 @@ use cosmwasm_std::BlockInfo;
use cw_orch_core::{
environment::{NodeQuerier, Querier, QuerierGetter},
log::query_target,
CwOrchEnvVars,
};
use tokio::runtime::Handle;
use tonic::transport::Channel;
Expand Down Expand Up @@ -220,7 +221,7 @@ impl Node {

/// Find TX by hash
pub async fn _find_tx(&self, hash: String) -> Result<CosmTxResponse, DaemonError> {
self._find_tx_with_retries(hash, CwOrchEnvVars::load()?.max_tx_query_retries)
self._find_tx_with_retries(hash, DaemonEnvVars::max_tx_query_retries())
.await
}

Expand All @@ -235,7 +236,7 @@ impl Node {

let request = cosmos_modules::tx::GetTxRequest { hash: hash.clone() };
let mut block_speed = self._average_block_speed(Some(0.7)).await?;
block_speed = block_speed.max(CwOrchEnvVars::load()?.min_block_speed);
block_speed = block_speed.max(DaemonEnvVars::min_block_speed());

for _ in 0..retries {
match client.get_tx(request.clone()).await {
Expand Down Expand Up @@ -270,7 +271,7 @@ impl Node {
page,
order_by,
false,
CwOrchEnvVars::load()?.max_tx_query_retries,
DaemonEnvVars::max_tx_query_retries(),
)
.await
}
Expand All @@ -289,7 +290,7 @@ impl Node {
page,
order_by,
true,
CwOrchEnvVars::load()?.max_tx_query_retries,
DaemonEnvVars::max_tx_query_retries(),
)
.await
}
Expand Down Expand Up @@ -344,7 +345,7 @@ impl Node {
// return error if tx not found by now
Err(DaemonError::TXNotFound(
format!("with events {:?}", events),
CwOrchEnvVars::load()?.max_tx_query_retries,
DaemonEnvVars::max_tx_query_retries(),
))
}
}
Expand Down
35 changes: 18 additions & 17 deletions cw-orch-daemon/src/sender.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{
env::DaemonEnvVars,
proto::injective::ETHEREUM_COIN_TYPE,
queriers::Bank,
tx_broadcaster::{
Expand Down Expand Up @@ -30,7 +31,7 @@ use cosmrs::{
AccountId, Any,
};
use cosmwasm_std::{coin, Addr, Coin};
use cw_orch_core::{log::local_target, CwOrchEnvVars};
use cw_orch_core::{log::local_target, CoreEnvVars};

use bitcoin::secp256k1::{All, Context, Secp256k1, Signing};
use std::{str::FromStr, sync::Arc};
Expand Down Expand Up @@ -221,15 +222,15 @@ impl Sender<All> {
/// Compute the gas fee from the expected gas in the transaction
/// Applies a Gas Buffer for including signature verification
pub(crate) fn get_fee_from_gas(&self, gas: u64) -> Result<(u64, u128), DaemonError> {
let mut gas_expected = if let Some(gas_buffer) = CwOrchEnvVars::load()?.gas_buffer {
let mut gas_expected = if let Some(gas_buffer) = DaemonEnvVars::gas_buffer() {
gas as f64 * gas_buffer
} else if gas < BUFFER_THRESHOLD {
gas as f64 * SMALL_GAS_BUFFER
} else {
gas as f64 * GAS_BUFFER
};

if let Some(min_gas) = CwOrchEnvVars::load()?.min_gas {
if let Some(min_gas) = DaemonEnvVars::min_gas() {
gas_expected = (min_gas as f64).max(gas_expected);
}
let fee_amount = gas_expected * (self.daemon_state.chain_data.gas_price + 0.00001);
Expand Down Expand Up @@ -291,7 +292,7 @@ impl Sender<All> {
let expected_fee = coin(fee_amount, self.get_fee_token());
// During simulation, we also make sure the account has enough balance to submit the transaction
// This is disabled by an env variable
if !CwOrchEnvVars::load()?.disable_wallet_balance_assertion {
if DaemonEnvVars::wallet_balance_assertion() {
self.assert_wallet_balance(&expected_fee).await?;
}

Expand Down Expand Up @@ -460,24 +461,24 @@ impl Sender<All> {
parsed_balance
);

if !CwOrchEnvVars::load()?.disable_manual_interaction {
if CoreEnvVars::manual_interaction() {
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.to_lowercase().contains('y') {
// We retry asserting the balance
self.assert_wallet_balance(fee).await
} else {
Err(DaemonError::NotEnoughBalance {
expected: fee.clone(),
current: parsed_balance,
})
}
} else {
println!("No Manual Interactions, defaulting to 'no'");
return Err(DaemonError::NotEnoughBalance {
expected: fee.clone(),
current: parsed_balance,
});
}

let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
if input.to_lowercase().contains('y') {
// We retry asserting the balance
self.assert_wallet_balance(fee).await
} else {
Err(DaemonError::NotEnoughBalance {
expected: fee.clone(),
current: parsed_balance,
})
}
}
}
13 changes: 6 additions & 7 deletions cw-orch-daemon/src/state.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use super::error::DaemonError;
use crate::{channel::GrpcChannel, networks::ChainKind};
use crate::{
channel::GrpcChannel, env::default_state_folder, env::DaemonEnvVars, networks::ChainKind,
};

use cosmwasm_std::Addr;
use cw_orch_core::{
env::default_state_folder,
environment::StateInterface,
log::{connectivity_target, local_target},
CwEnvError, CwOrchEnvVars,
CwEnvError,
};
use cw_orch_networks::ChainInfoOwned;
use serde::Serialize;
Expand Down Expand Up @@ -101,7 +102,7 @@ impl DaemonState {
/// Returns the path of the file where the state of `cw-orchestrator` is stored.
pub fn state_file_path() -> Result<String, DaemonError> {
// check if STATE_FILE en var is configured, default to state.json
let env_file_path = CwOrchEnvVars::load()?.state_file;
let env_file_path = DaemonEnvVars::state_file();
let state_file_path = if env_file_path.is_relative() {
// If it's relative, we check if it start with "."
let first_path_component = env_file_path
Expand Down Expand Up @@ -225,9 +226,7 @@ impl StateInterface for DaemonState {
pub mod test {
use std::env;

use cw_orch_core::env::STATE_FILE_ENV_NAME;

use crate::DaemonState;
use crate::{env::STATE_FILE_ENV_NAME, DaemonState};

#[test]
fn test_env_variable_state_path() -> anyhow::Result<()> {
Expand Down
Loading