diff --git a/.github/workflows/Basic.yml b/.github/workflows/Basic.yml index 736bc3bd..2ce5628a 100644 --- a/.github/workflows/Basic.yml +++ b/.github/workflows/Basic.yml @@ -63,9 +63,21 @@ jobs: with: command: clippy args: -- -D warnings - + + - name: Set latest just version + run: echo "JUST_VERSION=$(cargo search just -q | sed -n -e '/^just[[:space:]]/p' | cut -d '"' -f 2)" >> $GITHUB_ENV + + - name: Get cached just + uses: actions/cache@v3 + with: + path: ~/.cargo/bin/just + key: ${{ runner.os }}-just-${{ env.JUST_VERSION }} + + - name: Install just + run: cargo install just || true + - name: Generate Schema - run: ./scripts/schema.sh + run: just schema - name: Show Schema changes run: git status --porcelain diff --git a/.github/workflows/checksum.yml b/.github/workflows/checksum.yml index 4a3ffe0b..7f4209b8 100644 --- a/.github/workflows/checksum.yml +++ b/.github/workflows/checksum.yml @@ -47,7 +47,7 @@ jobs: run: just optimize - name: Generate Checksum - run: ./scripts/update-checksum.sh + run: just checksum shell: bash - name: Show checksum changes diff --git a/.rusty-hook.toml b/.rusty-hook.toml new file mode 100644 index 00000000..582f635e --- /dev/null +++ b/.rusty-hook.toml @@ -0,0 +1,5 @@ +[hooks] +pre-commit = "just lint" + +[logging] +verbose = true diff --git a/Cargo.lock b/Cargo.lock index 6db54a58..1231ff6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -296,6 +296,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ci_info" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24f638c70e8c5753795cc9a8c07c44da91554a09e4cf11a7326e8161b0a3c45e" +dependencies = [ + "envmnt", +] + [[package]] name = "cipher" version = "0.3.0" @@ -477,7 +486,7 @@ dependencies = [ "hex", "schemars", "serde", - "serde-json-wasm 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde-json-wasm 0.4.1", "thiserror", "uint", ] @@ -669,6 +678,7 @@ dependencies = [ "cwd-voting-cw20-staked", "generic-query", "hex", + "rusty-hook", "schemars", "serde", "sha2 0.10.6", @@ -691,10 +701,11 @@ dependencies = [ "cw20-base", "generic-query", "hex", + "rusty-hook", "schemars", "serde", "serde-cw-value", - "serde-json-wasm 0.4.1 (git+https://github.com/CyberHoward/serde-json-wasm?rev=cdc78130b25d65981b74a5e4a10a9f8667292d36)", + "serde-json-wasm 0.5.0", "sha2 0.10.6", "thiserror", ] @@ -801,10 +812,11 @@ dependencies = [ "cwd-voting", "cwd-voting-cw20-staked", "generic-query", + "rusty-hook", "schemars", "serde", "serde-cw-value", - "serde-json-wasm 0.4.1 (git+https://github.com/CyberHoward/serde-json-wasm?rev=cdc78130b25d65981b74a5e4a10a9f8667292d36)", + "serde-json-wasm 0.5.0", "serde_json", "smart-query", "thiserror", @@ -818,6 +830,7 @@ dependencies = [ "cosmwasm-std", "cw20", "generic-query", + "rusty-hook", "schemars", "serde", "serde-cw-value", @@ -1517,6 +1530,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "envmnt" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2d328fc287c61314c4a61af7cfdcbd7e678e39778488c7cb13ec133ce0f4059" +dependencies = [ + "fsio", + "indexmap", +] + [[package]] name = "eyre" version = "0.6.8" @@ -1577,6 +1600,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8cbd1169bd7b4a0a20d92b9af7a7e0422888bd38a6f5ec29c1fd8c1558a272e" +[[package]] +name = "fsio" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd087255f739f4f1aeea69f11b72f8080e9c2e7645cd06955dad4a178a49e3" + [[package]] name = "futures" version = "0.3.25" @@ -1719,6 +1748,15 @@ dependencies = [ "serde-cw-value", ] +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -2198,6 +2236,12 @@ dependencies = [ "socket2", ] +[[package]] +name = "nias" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab250442c86f1850815b5d268639dff018c0627022bc1940eb2d642ca1ce12f0" + [[package]] name = "nix" version = "0.22.3" @@ -2783,6 +2827,18 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rusty-hook" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cee9be61be7e1cbadd851e58ed7449c29c620f00b23df937cb9cbc04ac21a3" +dependencies = [ + "ci_info", + "getopts", + "nias", + "toml", +] + [[package]] name = "ryu" version = "1.0.11" @@ -2946,8 +3002,9 @@ dependencies = [ [[package]] name = "serde-json-wasm" -version = "0.4.1" -source = "git+https://github.com/CyberHoward/serde-json-wasm?rev=cdc78130b25d65981b74a5e4a10a9f8667292d36#cdc78130b25d65981b74a5e4a10a9f8667292d36" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15bee9b04dd165c3f4e142628982ddde884c2022a89e8ddf99c4829bf2c3a58" dependencies = [ "serde", ] diff --git a/checksum b/checksum index f311d653..2ec67374 100644 --- a/checksum +++ b/checksum @@ -1,2 +1,2 @@ -e841b8f67c8209ade26674edd432bb1d7dc9dcaa470651ebf379c62d41c294c8 cw_croncat.wasm -de2d1a0c648e41760020dd261f818da085c358240059acf85128f60eb0e05db2 cw_rules.wasm +fc76a0e370c9e947d6e33d018585137d566f32d1a1fb06b1b49e695e5984a57e cw_croncat.wasm +348ce203ce7a18c2e28f001139c1f7a215f7a569c735825dc819dc79692aaffb cw_rules.wasm diff --git a/ci/gas-benchmark/src/helpers.rs b/ci/gas-benchmark/src/helpers.rs index f93b3804..e943fe4f 100644 --- a/ci/gas-benchmark/src/helpers.rs +++ b/ci/gas-benchmark/src/helpers.rs @@ -13,12 +13,15 @@ use cosm_orc::{ }; use cosmwasm_std::Binary; use cw20::Cw20Coin; -use cw_croncat::contract::{GAS_ACTION_FEE_JUNO, GAS_BASE_FEE_JUNO, GAS_DENOMINATOR_DEFAULT_JUNO}; +use cw_croncat::contract::{ + GAS_ACTION_FEE, GAS_ADJUSTMENT_NUMERATOR_DEFAULT, GAS_BASE_FEE, GAS_DENOMINATOR, + GAS_NUMERATOR_DEFAULT, GAS_QUERY_FEE, GAS_WASM_QUERY_FEE, +}; use cw_croncat_core::{ msg::{TaskRequest, TaskResponse, TaskWithQueriesResponse}, - types::Action, + types::{Action, GasPrice}, }; -use cw_rules_core::msg::QueryResponse; +use cw_rules_core::{msg::QueryResponse, types::CroncatQuery}; const fn add_agent_fee(num: u64) -> u64 { num + (num * 5 / 100) @@ -26,10 +29,23 @@ const fn add_agent_fee(num: u64) -> u64 { fn min_gas_for_actions(actions: &[Action]) -> u64 { actions.iter().fold(0, |acc, action| { - acc + action.gas_limit.unwrap_or(GAS_ACTION_FEE_JUNO) + acc + action.gas_limit.unwrap_or(GAS_ACTION_FEE) }) } +fn min_gas_for_queries(queries: Option<&Vec>) -> u64 { + if let Some(queries) = queries { + queries.iter().fold(GAS_WASM_QUERY_FEE, |acc, query| { + acc + match query { + CroncatQuery::HasBalanceGte(_) => GAS_QUERY_FEE, + _ => GAS_WASM_QUERY_FEE, + } + }) + } else { + 0 + } +} + pub(crate) fn init_contracts( orc: &mut CosmOrc, key: &SigningKey, @@ -71,7 +87,9 @@ pub(crate) fn init_contracts( cw_rules_addr: rules_res.address, owner_id: Some(admin_addr.to_owned()), gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: None, gas_base_fee: None, }; @@ -175,8 +193,16 @@ where .map(|(_, _, prefix)| (*prefix).to_owned()) .collect(); for (task, extra_funds, prefix) in tasks { - let gas_for_task = GAS_BASE_FEE_JUNO + min_gas_for_actions(&task.actions); - let gas_to_attached_deposit = add_agent_fee(gas_for_task) / GAS_DENOMINATOR_DEFAULT_JUNO; + let gas_for_task = GAS_BASE_FEE + + min_gas_for_actions(&task.actions) + + min_gas_for_queries(task.queries.as_ref()); + let gas_to_attached_deposit = GasPrice { + numerator: GAS_NUMERATOR_DEFAULT, + denominator: GAS_DENOMINATOR, + gas_adjustment_numerator: GAS_ADJUSTMENT_NUMERATOR_DEFAULT, + } + .calculate(add_agent_fee(gas_for_task)) + .unwrap() as u64; let amount = (gas_to_attached_deposit + extra_funds) * 3; create_task(task, orc, user_key, prefix, &denom, amount)?; } diff --git a/ci/gas-benchmark/src/main.rs b/ci/gas-benchmark/src/main.rs index a77ff9bb..3045a6a2 100644 --- a/ci/gas-benchmark/src/main.rs +++ b/ci/gas-benchmark/src/main.rs @@ -201,7 +201,9 @@ fn main() -> Result<()> { agent_fee: None, gas_base_fee: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, proxy_callback_gas: None, min_tasks_per_agent: None, agents_eject_threshold: None, diff --git a/ci/local_config.yaml b/ci/local_config.yaml index 71630659..ec4dc483 100644 --- a/ci/local_config.yaml +++ b/ci/local_config.yaml @@ -4,5 +4,5 @@ chain_cfg: chain_id: "testing" rpc_endpoint: "http://localhost:26657/" grpc_endpoint: "http://localhost:9090/" - gas_prices: 0.1 - gas_adjustment: 1.2 + gas_prices: 0.04 + gas_adjustment: 1.5 diff --git a/contracts/cw-croncat/Cargo.toml b/contracts/cw-croncat/Cargo.toml index ee797ee1..00d58288 100644 --- a/contracts/cw-croncat/Cargo.toml +++ b/contracts/cw-croncat/Cargo.toml @@ -60,3 +60,4 @@ cwd-core = { version = "0.2.0", git = "https://github.com/DA0-DA0/dao-contracts" cwd-interface = { version = "0.2.0", git = "https://github.com/DA0-DA0/dao-contracts" } cwd-proposal-single = { version = "0.2.0", git = "https://github.com/DA0-DA0/dao-contracts" } cwd-voting = { version = "0.2.0", git = "https://github.com/DA0-DA0/dao-contracts.git" } +rusty-hook = "0.11.2" diff --git a/contracts/cw-croncat/src/agent.rs b/contracts/cw-croncat/src/agent.rs index 07a37970..4283a4a3 100644 --- a/contracts/cw-croncat/src/agent.rs +++ b/contracts/cw-croncat/src/agent.rs @@ -11,7 +11,7 @@ use std::ops::Div; use crate::ContractError::*; use cw_croncat_core::msg::{AgentResponse, AgentTaskResponse, GetAgentIdsResponse}; -use cw_croncat_core::types::{calculate_required_amount, Agent, AgentStatus}; +use cw_croncat_core::types::{gas_amount_with_agent_fee, Agent, AgentStatus}; impl<'a> CwCroncat<'a> { /// Get a single agent details @@ -140,10 +140,9 @@ impl<'a> CwCroncat<'a> { // REF: https://github.com/CosmWasm/cw-tokens/tree/main/contracts/cw20-escrow // Check if native token balance is sufficient for a few txns, in this case 4 txns - // TODO: Adjust gas & costs based on real usage cost let agent_wallet_balances = deps.querier.query_all_balances(account.clone())?; - let gas_cost = calculate_required_amount(c.gas_action_fee, c.agent_fee)?; - let unit_cost = c.gas_fraction.calculate(4 * gas_cost, 1)?; + let gas_amount_with_agent_fee = gas_amount_with_agent_fee(c.gas_action_fee, c.agent_fee)?; + let unit_cost = c.gas_price.calculate(4 * gas_amount_with_agent_fee)?; if !has_coins( &agent_wallet_balances, &Coin::new(unit_cost, c.native_denom), diff --git a/contracts/cw-croncat/src/contract.rs b/contracts/cw-croncat/src/contract.rs index 62efb809..9de92081 100644 --- a/contracts/cw-croncat/src/contract.rs +++ b/contracts/cw-croncat/src/contract.rs @@ -7,7 +7,7 @@ use cosmwasm_std::{ }; use cw2::set_contract_version; use cw_croncat_core::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; -use cw_croncat_core::types::{GasFraction, SlotType}; +use cw_croncat_core::types::{GasPrice, SlotType}; // version info for migration info const CONTRACT_NAME: &str = "crates.io:cw-croncat"; @@ -16,13 +16,22 @@ const DEFAULT_NOMINATION_DURATION: u16 = 360; /// default for juno /// This based on non-wasm operations, wasm ops seem impossible to predict -pub const GAS_BASE_FEE_JUNO: u64 = 300_000; -/// Gas cost per single action -pub const GAS_ACTION_FEE_JUNO: u64 = 130_000; +pub const GAS_BASE_FEE: u64 = 300_000; +/// Gas needed for single action +pub const GAS_ACTION_FEE: u64 = 130_000; +/// Gas needed for single non-wasm query +pub const GAS_QUERY_FEE: u64 = 5_000; +/// Gas needed for single wasm query +pub const GAS_WASM_QUERY_FEE: u64 = 60_000; /// We can't store gas_price as floats inside cosmwasm -/// so insted of something like 0.1 we use GasFraction{1/10} -pub const GAS_DENOMINATOR_DEFAULT_JUNO: u64 = 9; - +/// so insted of having 0.04 we use GasFraction{4/100} +/// and after that multiply Gas by `gas_adjustment` {150/100} (1.5) +pub mod gas_price_defaults { + pub const GAS_NUMERATOR_DEFAULT: u64 = 4; + pub const GAS_ADJUSTMENT_NUMERATOR_DEFAULT: u64 = 150; + pub const GAS_DENOMINATOR: u64 = 100; +} +pub use gas_price_defaults::*; // #[cfg(not(feature = "library"))] impl<'a> CwCroncat<'a> { pub fn instantiate( @@ -44,18 +53,6 @@ impl<'a> CwCroncat<'a> { info.sender }; - let gas_action_fee = if let Some(action_fee) = msg.gas_action_fee { - action_fee.u64() - } else { - GAS_ACTION_FEE_JUNO - }; - - let gas_base_fee = if let Some(base_fee) = msg.gas_base_fee { - base_fee.u64() - } else { - GAS_BASE_FEE_JUNO - }; - let config = Config { paused: false, owner_id, @@ -66,13 +63,19 @@ impl<'a> CwCroncat<'a> { available_balance, staked_balance: GenericBalance::default(), agent_fee: 5, - gas_fraction: GasFraction { - numerator: 1, - denominator: GAS_DENOMINATOR_DEFAULT_JUNO, - }, + gas_price: msg.gas_price.unwrap_or(GasPrice { + numerator: GAS_NUMERATOR_DEFAULT, + denominator: GAS_DENOMINATOR, + gas_adjustment_numerator: GAS_ADJUSTMENT_NUMERATOR_DEFAULT, + }), proxy_callback_gas: 3, - gas_base_fee, - gas_action_fee, + gas_base_fee: msg.gas_base_fee.map(Into::into).unwrap_or(GAS_BASE_FEE), + gas_action_fee: msg.gas_action_fee.map(Into::into).unwrap_or(GAS_ACTION_FEE), + gas_query_fee: msg.gas_query_fee.map(Into::into).unwrap_or(GAS_QUERY_FEE), + gas_wasm_query_fee: msg + .gas_wasm_query_fee + .map(Into::into) + .unwrap_or(GAS_WASM_QUERY_FEE), slot_granularity_time: 10_000_000_000, // 10 seconds native_denom: msg.denom, cw20_whitelist: vec![], @@ -123,7 +126,6 @@ impl<'a> CwCroncat<'a> { ) .add_attribute("native_denom", config.native_denom) .add_attribute("agent_fee", config.agent_fee.to_string()) - //.add_attribute("gas_fraction", config.gas_fraction.to_string()) .add_attribute("proxy_callback_gas", config.proxy_callback_gas.to_string()) .add_attribute( "slot_granularity_time", @@ -209,9 +211,7 @@ impl<'a> CwCroncat<'a> { QueryMsg::GetWalletBalances { wallet } => { to_binary(&self.query_wallet_balances(deps, wallet)?) } - QueryMsg::GetState { from_index, limit } => { - to_binary(&self.get_state(deps, env, from_index, limit)?) - } + QueryMsg::GetTaskHash { task } => to_binary(&self.query_get_task_hash(*task)?), } } diff --git a/contracts/cw-croncat/src/helpers.rs b/contracts/cw-croncat/src/helpers.rs index 16eaabe2..e39dadaf 100644 --- a/contracts/cw-croncat/src/helpers.rs +++ b/contracts/cw-croncat/src/helpers.rs @@ -11,7 +11,7 @@ use cosmwasm_std::{ use cw20::{Cw20CoinVerified, Cw20ExecuteMsg}; use cw_croncat_core::msg::ExecuteMsg; use cw_croncat_core::traits::{BalancesOperations, FindAndMutate}; -use cw_croncat_core::types::{calculate_required_amount, AgentStatus}; +use cw_croncat_core::types::{gas_amount_with_agent_fee, AgentStatus}; pub use cw_croncat_core::types::{GenericBalance, Task}; //use regex::Regex; use schemars::JsonSchema; @@ -224,10 +224,15 @@ pub(crate) fn proxy_call_submsgs_price( cfg: Config, next_idx: u64, ) -> Result<(Vec, Coin), ContractError> { - let (sub_msgs, gas_total) = - task.get_submsgs_with_total_gas(cfg.gas_base_fee, cfg.gas_action_fee, next_idx)?; - let gas_amount = calculate_required_amount(gas_total, cfg.agent_fee)?; - let price_amount = cfg.gas_fraction.calculate(gas_amount, 1)?; + let (sub_msgs, gas_total) = task.get_submsgs_with_total_gas( + cfg.gas_base_fee, + cfg.gas_action_fee, + cfg.gas_query_fee, + cfg.gas_wasm_query_fee, + next_idx, + )?; + let gas_amount_with_agent_fee = gas_amount_with_agent_fee(gas_total, cfg.agent_fee)?; + let price_amount = cfg.gas_price.calculate(gas_amount_with_agent_fee)?; let price = coin(price_amount, cfg.native_denom); Ok((sub_msgs, price)) } diff --git a/contracts/cw-croncat/src/owner.rs b/contracts/cw-croncat/src/owner.rs index f1951e18..4a77b751 100644 --- a/contracts/cw-croncat/src/owner.rs +++ b/contracts/cw-croncat/src/owner.rs @@ -1,16 +1,13 @@ -use crate::balancer::BalancerMode; use crate::error::ContractError; use crate::helpers::has_cw_coins; use crate::state::{Config, CwCroncat}; use cosmwasm_std::{ - has_coins, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Order, Response, - StdResult, SubMsg, Uint64, WasmMsg, + has_coins, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, Response, StdResult, + SubMsg, WasmMsg, }; use cw20::{Balance, Cw20ExecuteMsg}; use cw_croncat_core::msg::{ - BalancesResponse, CwCroncatResponse, ExecuteMsg, GetBalancesResponse, GetConfigResponse, - GetWalletBalancesResponse, RoundRobinBalancerModeResponse, SlotResponse, - SlotWithQueriesResponse, + ExecuteMsg, GetBalancesResponse, GetConfigResponse, GetWalletBalancesResponse, }; use cw_croncat_core::traits::FindAndMutate; @@ -26,7 +23,7 @@ impl<'a> CwCroncat<'a> { agents_eject_threshold: c.agents_eject_threshold, native_denom: c.native_denom, agent_fee: c.agent_fee, - gas_fraction: c.gas_fraction, + gas_price: c.gas_price, proxy_callback_gas: c.proxy_callback_gas, slot_granularity_time: c.slot_granularity_time, cw_rules_addr: c.cw_rules_addr, @@ -85,53 +82,60 @@ impl<'a> CwCroncat<'a> { agent_fee, gas_base_fee, gas_action_fee, - gas_fraction, + gas_query_fee, + gas_wasm_query_fee, + gas_price, proxy_callback_gas, min_tasks_per_agent, agents_eject_threshold, // treasury_id, } => { + let owner_id = if let Some(addr) = owner_id { + Some(api.addr_validate(&addr)?) + } else { + None + }; self.config - .update(deps.storage, |mut config| -> Result<_, ContractError> { - if info.sender != config.owner_id { + .update(deps.storage, |old_config| -> Result<_, ContractError> { + if info.sender != old_config.owner_id { return Err(ContractError::Unauthorized {}); } - if let Some(owner_id) = owner_id { - let owner_id = api.addr_validate(&owner_id)?; - config.owner_id = owner_id; - } - // if let Some(treasury_id) = treasury_id { - // config.treasury_id = Some(treasury_id); - // } - if let Some(slot_granularity_time) = slot_granularity_time { - config.slot_granularity_time = slot_granularity_time; - } - if let Some(paused) = paused { - config.paused = paused; - } - if let Some(gas_base_fee) = gas_base_fee { - config.gas_base_fee = gas_base_fee.u64(); - } - if let Some(gas_action_fee) = gas_action_fee { - config.gas_action_fee = gas_action_fee.u64(); - } - if let Some(gas_fraction) = gas_fraction { - config.gas_fraction = gas_fraction; - } - if let Some(proxy_callback_gas) = proxy_callback_gas { - config.proxy_callback_gas = proxy_callback_gas; - } - if let Some(agent_fee) = agent_fee { - config.agent_fee = agent_fee; - } - if let Some(min_tasks_per_agent) = min_tasks_per_agent { - config.min_tasks_per_agent = min_tasks_per_agent; - } - if let Some(agents_eject_threshold) = agents_eject_threshold { - config.agents_eject_threshold = agents_eject_threshold; - } - Ok(config) + let new_config = Config { + paused: paused.unwrap_or(old_config.paused), + owner_id: owner_id.unwrap_or(old_config.owner_id), + min_tasks_per_agent: min_tasks_per_agent + .unwrap_or(old_config.min_tasks_per_agent), + agent_active_indices: old_config.agent_active_indices, + agents_eject_threshold: agents_eject_threshold + .unwrap_or(old_config.agents_eject_threshold), + agent_nomination_duration: old_config.agent_nomination_duration, + cw_rules_addr: old_config.cw_rules_addr, + agent_fee: agent_fee.unwrap_or(old_config.agent_fee), + gas_price: gas_price.unwrap_or(old_config.gas_price), + gas_base_fee: gas_base_fee + .map(Into::into) + .unwrap_or(old_config.gas_base_fee), + gas_action_fee: gas_action_fee + .map(Into::into) + .unwrap_or(old_config.gas_action_fee), + gas_query_fee: gas_query_fee + .map(Into::into) + .unwrap_or(old_config.gas_query_fee), + gas_wasm_query_fee: gas_wasm_query_fee + .map(Into::into) + .unwrap_or(old_config.gas_wasm_query_fee), + proxy_callback_gas: proxy_callback_gas + .unwrap_or(old_config.proxy_callback_gas), + slot_granularity_time: slot_granularity_time + .unwrap_or(old_config.slot_granularity_time), + cw20_whitelist: old_config.cw20_whitelist, + native_denom: old_config.native_denom, + available_balance: old_config.available_balance, + staked_balance: old_config.staked_balance, + limit: old_config.limit, + }; + Ok(new_config) })?; } _ => unreachable!(), @@ -161,7 +165,6 @@ impl<'a> CwCroncat<'a> { ) .add_attribute("native_denom", c.native_denom) .add_attribute("agent_fee", c.agent_fee.to_string()) - //.add_attribute("gas_price", c.gas_fraction.to_string()) .add_attribute("proxy_callback_gas", c.proxy_callback_gas.to_string()) .add_attribute("slot_granularity_time", c.slot_granularity_time.to_string())) } @@ -275,134 +278,4 @@ impl<'a> CwCroncat<'a> { .add_attribute("account_id", account_id.to_string()) .add_submessages(messages?)) } - - pub(crate) fn get_state( - &self, - deps: Deps, - env: Env, - from_index: Option, - limit: Option, - ) -> StdResult { - let default_limit = self.config.load(deps.storage)?.limit; - let size: u64 = self.task_total.load(deps.storage)?.min(default_limit); - let from_index_unwrap = from_index.unwrap_or_default(); - let limit_unwrap = limit.unwrap_or(default_limit).min(size) as usize; - - let mut agents = Vec::with_capacity(limit_unwrap); - for agent in self - .agents - .keys(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - { - let agent_info = self.query_get_agent(deps, env.clone(), agent?.to_string())?; - agents.push(agent_info.unwrap()); - } - - let time_slots: Vec = self - .time_slots - .range(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - .map(|res| { - let res = res.unwrap(); - SlotResponse { - slot: res.0.into(), - tasks: res.1, - } - }) - .collect(); - - let block_slots: Vec = self - .block_slots - .range(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - .map(|res| { - let res = res.unwrap(); - SlotResponse { - slot: res.0.into(), - tasks: res.1, - } - }) - .collect(); - - let balances: Vec = self - .balances - .range(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - .map(|res| { - let res = res.unwrap(); - BalancesResponse { - address: res.0, - balances: res.1, - } - }) - .collect(); - - let balancer_mode = match self.balancer.mode { - BalancerMode::ActivationOrder => RoundRobinBalancerModeResponse::ActivationOrder, - BalancerMode::Equalizer => RoundRobinBalancerModeResponse::Equalizer, - }; - - let time_slots_queries: Vec = self - .time_map_queries - .range(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - .map(|res| { - let res = res.unwrap(); - SlotWithQueriesResponse { - task_hash: res.0, - slot: res.1.into(), - } - }) - .collect(); - - let block_slots_queries: Vec = self - .block_map_queries - .range(deps.storage, None, None, Order::Ascending) - .skip(from_index_unwrap as usize) - .take(limit_unwrap) - .map(|res| { - let res = res.unwrap(); - SlotWithQueriesResponse { - task_hash: res.0, - slot: res.1.into(), - } - }) - .collect(); - - Ok(CwCroncatResponse { - config: self.query_config(deps)?, - - agent_active_queue: self.agent_active_queue.load(deps.storage)?, - agent_pending_queue: self - .agent_pending_queue - .iter(deps.storage)? - .take(50) - .collect::>>()?, - agents, - - tasks: self.query_get_tasks(deps, None, None)?, - task_total: Uint64::from(self.task_total.load(deps.storage)?), - - time_slots, - block_slots, - - tasks_with_queries: self.query_get_tasks_with_queries(deps, from_index, limit)?, - tasks_with_queries_total: Uint64::from( - self.tasks_with_queries_total.load(deps.storage)?, - ), - time_slots_queries, - block_slots_queries, - - reply_index: Uint64::from(self.reply_index.load(deps.storage)?), - agent_nomination_begin_time: self.agent_nomination_begin_time.load(deps.storage)?, - - balances, - balancer_mode, - }) - } } diff --git a/contracts/cw-croncat/src/state.rs b/contracts/cw-croncat/src/state.rs index 745b7bfa..c087f08d 100644 --- a/contracts/cw-croncat/src/state.rs +++ b/contracts/cw-croncat/src/state.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::helpers::Task; use cw_croncat_core::{ query::CroncatQuerier, - types::{Agent, GasFraction, GenericBalance, SlotType}, + types::{Agent, GasPrice, GenericBalance, SlotType}, }; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] @@ -38,9 +38,11 @@ pub struct Config { // Economics pub agent_fee: u64, - pub gas_fraction: GasFraction, + pub gas_price: GasPrice, pub gas_base_fee: u64, pub gas_action_fee: u64, + pub gas_query_fee: u64, + pub gas_wasm_query_fee: u64, pub proxy_callback_gas: u32, pub slot_granularity_time: u64, diff --git a/contracts/cw-croncat/src/tasks.rs b/contracts/cw-croncat/src/tasks.rs index 9d2769ae..625ae7f9 100644 --- a/contracts/cw-croncat/src/tasks.rs +++ b/contracts/cw-croncat/src/tasks.rs @@ -13,7 +13,7 @@ use cw_croncat_core::msg::{ }; use cw_croncat_core::traits::{BalancesOperations, FindAndMutate, Intervals}; use cw_croncat_core::types::{ - calculate_required_amount, BoundaryValidated, GenericBalance, SlotType, Task, + gas_amount_with_agent_fee, BoundaryValidated, GenericBalance, SlotType, Task, }; impl<'a> CwCroncat<'a> { @@ -262,9 +262,11 @@ impl<'a> CwCroncat<'a> { &cfg.owner_id, cfg.gas_base_fee, cfg.gas_action_fee, + cfg.gas_query_fee, + cfg.gas_wasm_query_fee, )?; - let gas_price = calculate_required_amount(gas_amount, cfg.agent_fee)?; - let price = cfg.gas_fraction.calculate(gas_price, 1)?; + let gas_amount_with_agent_fee = gas_amount_with_agent_fee(gas_amount, cfg.agent_fee)?; + let price = cfg.gas_price.calculate(gas_amount_with_agent_fee)?; amount_for_one_task .native .find_checked_add(&coin(price, &cfg.native_denom))?; @@ -396,8 +398,6 @@ impl<'a> CwCroncat<'a> { None => Ok(vec![hash]), } }; - - // Based on slot kind, put into block or cron slots match slot_kind { SlotType::Block => { self.block_slots diff --git a/contracts/cw-croncat/src/tests/agent.rs b/contracts/cw-croncat/src/tests/agent.rs index ced94dd8..9bd4a9e3 100644 --- a/contracts/cw-croncat/src/tests/agent.rs +++ b/contracts/cw-croncat/src/tests/agent.rs @@ -11,7 +11,7 @@ use cw_croncat_core::msg::{ AgentResponse, AgentTaskResponse, ExecuteMsg, GetAgentIdsResponse, InstantiateMsg, QueryMsg, TaskRequest, TaskResponse, }; -use cw_croncat_core::types::{Action, Agent, AgentStatus, GasFraction, GenericBalance, Interval}; +use cw_croncat_core::types::{Action, Agent, AgentStatus, GasPrice, GenericBalance, Interval}; use cw_multi_test::{App, AppResponse, BankSudo, Executor, SudoMsg}; use super::helpers::{ @@ -256,7 +256,9 @@ fn test_instantiate_sets_balance() { cw_rules_addr: "grapestem".to_string(), owner_id: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: None, gas_base_fee: None, }, @@ -309,10 +311,12 @@ fn register_agent_fail_cases() { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, slot_granularity_time: None, }; app.execute_contract( @@ -341,14 +345,17 @@ fn register_agent_fail_cases() { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: Some(GasFraction { + gas_price: Some(GasPrice { numerator: 1, denominator: 1, + gas_adjustment_numerator: 1, }), proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; app.execute_contract( Addr::unchecked(ADMIN), @@ -612,7 +619,7 @@ fn accept_nomination_agent() { let res = add_task_exec(&mut app, &contract_addr, PARTICIPANT0); let task_hash = res.events[1].attributes[4].clone().value; assert_eq!( - "7ea9a6d5ef5c78cb168afa96b43b5843b8f880627aa0580f4311403f907cbf93", task_hash, + "c2c2867b1833b35632ff663cd6dbaf4860b35cada0433699eaaeda90e6010297", task_hash, "Unexpected task hash" ); @@ -751,7 +758,9 @@ fn test_get_agent_status() { denom: NATIVE_DENOM.to_string(), owner_id: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: Some(360), cw_rules_addr: "todo".to_string(), gas_base_fee: None, diff --git a/contracts/cw-croncat/src/tests/balance.rs b/contracts/cw-croncat/src/tests/balance.rs index 12796102..83816c3f 100644 --- a/contracts/cw-croncat/src/tests/balance.rs +++ b/contracts/cw-croncat/src/tests/balance.rs @@ -1,10 +1,13 @@ use crate::balancer::{Balancer, BalancerMode, RoundRobinBalancer}; -use crate::contract::{GAS_ACTION_FEE_JUNO, GAS_BASE_FEE_JUNO, GAS_DENOMINATOR_DEFAULT_JUNO}; +use crate::contract::{ + GAS_ACTION_FEE, GAS_ADJUSTMENT_NUMERATOR_DEFAULT, GAS_BASE_FEE, GAS_DENOMINATOR, + GAS_NUMERATOR_DEFAULT, GAS_QUERY_FEE, GAS_WASM_QUERY_FEE, +}; use crate::state::{Config, TaskInfo}; use crate::tests::helpers::{default_task, AGENT0, AGENT1, AGENT2, AGENT3, AGENT4}; use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env}; use cosmwasm_std::{coins, Addr}; -use cw_croncat_core::types::{GasFraction, GenericBalance, SlotType}; +use cw_croncat_core::types::{GasPrice, GenericBalance, SlotType}; use crate::CwCroncat; @@ -21,11 +24,14 @@ fn mock_config() -> Config { available_balance: GenericBalance::default(), staked_balance: GenericBalance::default(), agent_fee: 5, - gas_fraction: GasFraction { - numerator: 1, - denominator: GAS_DENOMINATOR_DEFAULT_JUNO, + gas_price: GasPrice { + numerator: GAS_NUMERATOR_DEFAULT, + denominator: GAS_DENOMINATOR, + gas_adjustment_numerator: GAS_ADJUSTMENT_NUMERATOR_DEFAULT, }, - gas_action_fee: GAS_ACTION_FEE_JUNO, + gas_action_fee: GAS_ACTION_FEE, + gas_query_fee: GAS_QUERY_FEE, + gas_wasm_query_fee: GAS_WASM_QUERY_FEE, proxy_callback_gas: 3, slot_granularity_time: 60_000_000_000, native_denom: NATIVE_DENOM.to_owned(), @@ -33,7 +39,7 @@ fn mock_config() -> Config { agent_nomination_duration: 9, limit: 100, cw_rules_addr: Addr::unchecked("todo"), - gas_base_fee: GAS_BASE_FEE_JUNO, + gas_base_fee: GAS_BASE_FEE, } } #[test] diff --git a/contracts/cw-croncat/src/tests/contract.rs b/contracts/cw-croncat/src/tests/contract.rs index d64c4ae8..6ff7be21 100644 --- a/contracts/cw-croncat/src/tests/contract.rs +++ b/contracts/cw-croncat/src/tests/contract.rs @@ -1,4 +1,6 @@ -use crate::contract::GAS_DENOMINATOR_DEFAULT_JUNO; +use crate::contract::GAS_ADJUSTMENT_NUMERATOR_DEFAULT; +use crate::contract::GAS_DENOMINATOR; +use crate::contract::GAS_NUMERATOR_DEFAULT; use crate::state::QueueItem; use crate::tests::helpers::mock_init; use crate::tests::helpers::AGENT0; @@ -11,7 +13,7 @@ use cosmwasm_std::testing::{ }; use cosmwasm_std::{coins, from_binary, Addr, Binary, Event, Reply, SubMsgResponse, SubMsgResult}; use cw_croncat_core::msg::{GetConfigResponse, QueryMsg}; -use cw_croncat_core::types::GasFraction; +use cw_croncat_core::types::GasPrice; use cw_croncat_core::types::SlotType; #[test] @@ -23,7 +25,9 @@ fn configure() { denom: NATIVE_DENOM.to_string(), owner_id: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: Some(360), cw_rules_addr: "todo".to_string(), gas_base_fee: None, @@ -53,11 +57,12 @@ fn configure() { assert_eq!("atom", value.native_denom); assert_eq!(5, value.agent_fee); assert_eq!( - GasFraction { - numerator: 1, - denominator: GAS_DENOMINATOR_DEFAULT_JUNO + GasPrice { + numerator: GAS_NUMERATOR_DEFAULT, + denominator: GAS_DENOMINATOR, + gas_adjustment_numerator: GAS_ADJUSTMENT_NUMERATOR_DEFAULT, }, - value.gas_fraction + value.gas_price ); assert_eq!(3, value.proxy_callback_gas); assert_eq!(10_000_000_000, value.slot_granularity_time); diff --git a/contracts/cw-croncat/src/tests/helpers.rs b/contracts/cw-croncat/src/tests/helpers.rs index 929f3b88..898315a1 100644 --- a/contracts/cw-croncat/src/tests/helpers.rs +++ b/contracts/cw-croncat/src/tests/helpers.rs @@ -38,7 +38,9 @@ pub fn mock_init(store: &CwCroncat, deps: DepsMut) -> Result (App, CwTemplateContract, Addr) { owner_id: Some(owner_addr.to_string()), gas_base_fee: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: None, }; let cw_template_contract_addr = app @@ -330,6 +334,7 @@ pub fn default_task() -> Task { boundary: BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, stop_on_fail: Default::default(), total_deposit: Default::default(), diff --git a/contracts/cw-croncat/src/tests/manager.rs b/contracts/cw-croncat/src/tests/manager.rs index 0a669587..c18a6268 100644 --- a/contracts/cw-croncat/src/tests/manager.rs +++ b/contracts/cw-croncat/src/tests/manager.rs @@ -1,4 +1,8 @@ -use crate::contract::{GAS_ACTION_FEE_JUNO, GAS_BASE_FEE_JUNO, GAS_DENOMINATOR_DEFAULT_JUNO}; +use crate::contract::{ + GAS_ACTION_FEE, GAS_ADJUSTMENT_NUMERATOR_DEFAULT, GAS_BASE_FEE, GAS_DENOMINATOR, + GAS_NUMERATOR_DEFAULT, +}; + use crate::tests::helpers::{ add_1000_blocks, add_little_time, add_one_duration_of_time, cw4_template, proper_instantiate, AGENT1, AGENT2, AGENT3, @@ -8,6 +12,7 @@ use cosmwasm_std::{ coin, coins, to_binary, Addr, BankMsg, Coin, CosmosMsg, StakingMsg, StdResult, Uint128, WasmMsg, }; use cw20::Cw20Coin; +use cw_croncat_core::error::CoreError; use cw_croncat_core::msg::{ AgentResponse, AgentTaskResponse, ExecuteMsg, GetAgentIdsResponse, QueryMsg, TaskRequest, TaskResponse, TaskWithQueriesResponse, @@ -50,8 +55,6 @@ fn proxy_call_fail_cases() -> StdResult<()> { cw20_coins: vec![], }, }; - let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); // Must attach funds let res_err = app @@ -98,11 +101,13 @@ fn proxy_call_fail_cases() -> StdResult<()> { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; app.execute_contract( Addr::unchecked(ADMIN), @@ -164,11 +169,13 @@ fn proxy_call_fail_cases() -> StdResult<()> { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }, &vec![], ) @@ -187,7 +194,7 @@ fn proxy_call_fail_cases() -> StdResult<()> { let mut has_created_hash: bool = false; for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; } } @@ -249,7 +256,7 @@ fn proxy_call_success() -> StdResult<()> { let contract_addr = cw_template_contract.addr(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; let task_id_str = - "1032a37c92801f73c75816bddb4f0db8516baeeeacd6a2c225f0a6a54c96732e".to_string(); + "53b21f5454aa8fd2df46ffb4a07fc45477e4ff1a1b8fe0771376d67eaaea4dcb".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -289,7 +296,7 @@ fn proxy_call_success() -> StdResult<()> { let mut has_created_hash: bool = false; for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; } } @@ -430,8 +437,10 @@ fn proxy_call_no_task_and_withdraw() -> StdResult<()> { cw20_coins: vec![], }, }; - let gas_for_one = GAS_BASE_FEE_JUNO + gas_limit; - let amount_for_one_task = gas_for_one / GAS_DENOMINATOR_DEFAULT_JUNO; + let gas_for_one = GAS_BASE_FEE + gas_limit; + let amount_for_one_task = gas_for_one * GAS_ADJUSTMENT_NUMERATOR_DEFAULT / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR; let agent_fee = amount_for_one_task * 5 / 100; let amount_with_fee = gas_limit + agent_fee + 1000; // create a task @@ -506,7 +515,7 @@ fn proxy_callback_fail_cases() -> StdResult<()> { let contract_addr = cw_template_contract.addr(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; let task_id_str = - "96003a7938c1ac9566fec1be9b0cfa97a56626a574940ef5968364ef4d30c15a".to_string(); + "ed4e2f3e3bd72f982145b04fdc4ffca4a03df10bb95b8c7f807b4f06a5b98f91".to_string(); // Doing this msg since its the easiest to guarantee success in reply let validator = String::from("you"); @@ -545,7 +554,7 @@ fn proxy_callback_fail_cases() -> StdResult<()> { let mut has_created_hash: bool = false; for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; } } @@ -598,7 +607,7 @@ fn proxy_callback_fail_cases() -> StdResult<()> { attr_key = Some(a.clone().key); attr_value = Some(a.clone().value); } - if e.ty == "transfer" && a.clone().key == "amount" && a.clone().value == "64172atom" + if e.ty == "transfer" && a.clone().key == "amount" && a.clone().value == "93688atom" // task didn't pay for the failed execution { has_submsg_method = true; @@ -614,7 +623,6 @@ fn proxy_callback_fail_cases() -> StdResult<()> { if let Some(_key) = attr_key { if let Some(value) = attr_value { if v.to_string() != value { - println!("v: {v}, value: {value}"); has_required_attributes = false; } } else { @@ -697,7 +705,7 @@ fn proxy_callback_fail_cases() -> StdResult<()> { } if e.ty == "transfer" && a.clone().key == "amount" - && a.clone().value == "460840atom" + && a.clone().value == "490356atom" // task didn't pay for the failed execution { has_submsg_method = true; @@ -735,7 +743,7 @@ fn proxy_callback_block_slots() -> StdResult<()> { let contract_addr = cw_template_contract.addr(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; let task_id_str = - "1032a37c92801f73c75816bddb4f0db8516baeeeacd6a2c225f0a6a54c96732e".to_string(); + "53b21f5454aa8fd2df46ffb4a07fc45477e4ff1a1b8fe0771376d67eaaea4dcb".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -772,7 +780,7 @@ fn proxy_callback_block_slots() -> StdResult<()> { let mut has_created_hash: bool = false; for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; } } @@ -864,7 +872,7 @@ fn proxy_callback_time_slots() -> StdResult<()> { let contract_addr = cw_template_contract.addr(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; let task_id_str = - "164329dc48b4d81075f82c823108d1f1f435af952d4697583b99a9f35962e211".to_string(); + "7d125c998e4e105af366c2a66bdc09bf2b52275f5b400033684484b0348927df".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -897,11 +905,12 @@ fn proxy_callback_time_slots() -> StdResult<()> { &coins(525000, NATIVE_DENOM), ) .unwrap(); + // Assert task hash is returned as part of event attributes let mut has_created_hash: bool = false; for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; } } @@ -1292,7 +1301,7 @@ fn test_multi_action() { cw20_coins: vec![], }, }; - let gas_limit = GAS_ACTION_FEE_JUNO; + let gas_limit = GAS_ACTION_FEE; let agent_fee = gas_limit.checked_mul(5).unwrap().checked_div(100).unwrap(); let amount_for_one_task = (gas_limit * 2) + agent_fee * 2 + 3 + 4; // + 3 + 4 atoms sent @@ -1364,11 +1373,16 @@ fn test_balance_changes() { cw20_coins: vec![], }, }; - let gas_for_one = GAS_BASE_FEE_JUNO + (GAS_ACTION_FEE_JUNO * 2); + let gas_for_one = GAS_BASE_FEE + (GAS_ACTION_FEE * 2); let agent_fee = gas_for_one * 5 / 100; let extra = 50; // extra for checking refunds at task removal - let amount_for_one_task = - (gas_for_one + agent_fee) / GAS_DENOMINATOR_DEFAULT_JUNO + 3 + 4 + extra; // + 3 + 4 atoms sent + let amount_for_one_task = (gas_for_one + agent_fee) * GAS_ADJUSTMENT_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + + 3 + + 4 + + extra; // + 3 + 4 atoms sent // create a task app.execute_contract( @@ -1498,19 +1512,33 @@ fn test_no_reschedule_if_lack_balance() { }, }; - let gas_for_one = GAS_BASE_FEE_JUNO + GAS_ACTION_FEE_JUNO; + let gas_for_one = GAS_BASE_FEE + GAS_ACTION_FEE; let agent_fee = gas_for_one * 5 / 100; let extra = 50; // extra for checking nonzero task balance - let amount_for_one_task = (gas_for_one + agent_fee) / GAS_DENOMINATOR_DEFAULT_JUNO + 3; // + 3 atoms sent + let amount_for_one_task = (gas_for_one + agent_fee) * GAS_ADJUSTMENT_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + + 3; // + 3 atoms sent // create a task - app.execute_contract( - Addr::unchecked(ADMIN), - contract_addr.clone(), - &create_task_msg, - &coins(u128::from(amount_for_one_task * 2 + extra - 3), "atom"), - ) - .unwrap(); + let resp = app + .execute_contract( + Addr::unchecked(ADMIN), + contract_addr.clone(), + &create_task_msg, + &coins(u128::from(amount_for_one_task * 2 + extra - 3), "atom"), + ) + .unwrap(); + + let mut hash = String::new(); + for e in resp.events { + for a in e.attributes { + if a.key == "task_hash" && a.value.len() > 0 { + hash = a.value; + } + } + } // quick agent register let msg = ExecuteMsg::RegisterAgent { @@ -1541,15 +1569,17 @@ fn test_no_reschedule_if_lack_balance() { .wrap() .query_wasm_smart( contract_addr.clone(), - &QueryMsg::GetTask { - task_hash: "65237042c224447b7d6d7cdfd6515af3e76cb3270ce6d5ed989a6babc12f1026" - .to_string(), - }, + &QueryMsg::GetTask { task_hash: hash }, ) .unwrap(); assert_eq!( task.unwrap().total_deposit[0].amount, - Uint128::from((gas_for_one + agent_fee) / GAS_DENOMINATOR_DEFAULT_JUNO + extra) + Uint128::from( + (gas_for_one + agent_fee) * GAS_ADJUSTMENT_NUMERATOR_DEFAULT / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + + extra + ) ); app.update_block(add_little_time); @@ -1574,7 +1604,7 @@ fn test_no_reschedule_if_lack_balance() { .query_wasm_smart( contract_addr.clone(), &QueryMsg::GetTask { - task_hash: "65237042c224447b7d6d7cdfd6515af3e76cb3270ce6d5ed989a6babc12f1026" + task_hash: "8fad55a869f129ba363786bd7f0ec698f1a59e2553ba7fdec408f1cd82326cd3" .to_string(), }, ) @@ -1599,7 +1629,6 @@ fn test_no_reschedule_if_lack_balance() { fn test_complete_task_with_query() { let (mut app, cw_template_contract, _) = proper_instantiate(); let contract_addr = cw_template_contract.addr(); - let task_hash = "259f4b3122822233bee9bc6ec8d38184e4b6ce0908decd68d972639aa92199c7"; let addr1 = String::from("addr1"); let amount = coins(3, NATIVE_DENOM); @@ -1626,14 +1655,23 @@ fn test_complete_task_with_query() { }; let attached_balance = 900058; - app.execute_contract( - Addr::unchecked(ADMIN), - contract_addr.clone(), - &create_task_msg, - &coins(attached_balance, NATIVE_DENOM), - ) - .unwrap(); + let resp = app + .execute_contract( + Addr::unchecked(ADMIN), + contract_addr.clone(), + &create_task_msg, + &coins(attached_balance, NATIVE_DENOM), + ) + .unwrap(); + let mut task_hash = String::new(); + for e in resp.events { + for a in e.attributes { + if a.key == "task_hash" && a.value.len() > 0 { + task_hash = a.value; + } + } + } // quick agent register let msg = ExecuteMsg::RegisterAgent { payable_account_id: Some(AGENT_BENEFICIARY.to_string()), @@ -1677,7 +1715,7 @@ fn test_complete_task_with_query() { Addr::unchecked(AGENT0), contract_addr.clone(), &ExecuteMsg::ProxyCall { - task_hash: Some(String::from(task_hash)), + task_hash: Some(String::from(task_hash.clone())), }, &[], ) @@ -1709,7 +1747,6 @@ fn test_complete_task_with_query() { fn test_reschedule_task_with_queries() { let (mut app, cw_template_contract, _) = proper_instantiate(); let contract_addr = cw_template_contract.addr(); - let task_hash = "4e74864be3956efe77bafac50944995290a32507bbd4509dd8ff21d3fdfdfec3"; let addr1 = String::from("addr1"); let amount = coins(3, NATIVE_DENOM); @@ -1736,13 +1773,22 @@ fn test_reschedule_task_with_queries() { }; let attached_balance = 100338 * 4; - app.execute_contract( - Addr::unchecked(ADMIN), - contract_addr.clone(), - &create_task_msg, - &coins(attached_balance, NATIVE_DENOM), - ) - .unwrap(); + let create_task_resp = app + .execute_contract( + Addr::unchecked(ADMIN), + contract_addr.clone(), + &create_task_msg, + &coins(attached_balance, NATIVE_DENOM), + ) + .unwrap(); + let mut task_hash = String::new(); + for e in create_task_resp.events { + for a in e.attributes { + if a.key == "task_hash" && a.value.len() > 0 { + task_hash = a.value; + } + } + } // quick agent register let msg = ExecuteMsg::RegisterAgent { @@ -1788,7 +1834,7 @@ fn test_reschedule_task_with_queries() { Addr::unchecked(AGENT0), contract_addr.clone(), &ExecuteMsg::ProxyCall { - task_hash: Some(String::from(task_hash)), + task_hash: Some(String::from(task_hash.clone())), }, &[], ) @@ -1796,7 +1842,7 @@ fn test_reschedule_task_with_queries() { assert!(res.events.iter().any(|ev| ev .attributes .iter() - .any(|attr| attr.key == "task_hash" && attr.value == task_hash))); + .any(|attr| attr.key == "task_hash" && attr.value == task_hash.clone()))); assert!(res.events.iter().any(|ev| ev .attributes .iter() @@ -1816,17 +1862,17 @@ fn test_reschedule_task_with_queries() { assert!(tasks_response.is_empty()); // Run it a bunch of times successfully, until it's removed because the balance falls too low - for _ in 1..8 { - assert!(app + for _ in 1..12 { + let _ = app .execute_contract( Addr::unchecked(AGENT0), contract_addr.clone(), &ExecuteMsg::ProxyCall { - task_hash: Some(String::from(task_hash)), + task_hash: Some(task_hash.clone()), }, &[], ) - .is_ok()); + .is_ok(); } let tasks_with_queries: Vec = app @@ -1839,7 +1885,7 @@ fn test_reschedule_task_with_queries() { }, ) .unwrap(); - println!("{:?}", tasks_with_queries); + assert!(tasks_with_queries.is_empty()); } @@ -1856,10 +1902,12 @@ fn tick() { min_tasks_per_agent: None, agents_eject_threshold: Some(1000), // allow to miss 1000 slots gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, - gas_fraction: None, + gas_price: None, }; app.execute_contract( Addr::unchecked(ADMIN), @@ -2051,7 +2099,9 @@ fn tick_task() -> StdResult<()> { slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, }; app.execute_contract( Addr::unchecked(ADMIN), @@ -2238,8 +2288,9 @@ fn testing_fee_works() { cw20_coins: vec![], }, }; - let total_gas = GAS_BASE_FEE_JUNO + GAS_ACTION_FEE_JUNO; - let attach_per_action = (total_gas + (total_gas * 5 / 100)) / GAS_DENOMINATOR_DEFAULT_JUNO; + let total_gas = GAS_BASE_FEE + GAS_ACTION_FEE; + let attach_per_action = + (total_gas + (total_gas * 5 / 100)) * GAS_NUMERATOR_DEFAULT / GAS_DENOMINATOR; let extra = 100; let amount_for_three = (attach_per_action * 3) as u128 + extra; @@ -2268,21 +2319,20 @@ fn testing_fee_works() { app.update_block(add_little_time); - let tasks: Vec = app - .wrap() - .query_wasm_smart( - contract_addr.clone(), - &QueryMsg::GetTasks { - from_index: None, - limit: None, - }, - ) - .unwrap(); - let tasks: Vec<(Vec, Vec)> = tasks - .into_iter() - .map(|task| (task.total_deposit, task.actions)) - .collect(); - println!("tasks: {tasks:?}"); + // let tasks: Vec = app + // .wrap() + // .query_wasm_smart( + // contract_addr.clone(), + // &QueryMsg::GetTasks { + // from_index: None, + // limit: None, + // }, + // ) + // .unwrap(); + // let tasks: Vec<(Vec, Vec)> = tasks + // .into_iter() + // .map(|task| (task.total_deposit, task.actions)) + // .collect(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; app.execute_contract( @@ -2294,21 +2344,20 @@ fn testing_fee_works() { .unwrap(); app.update_block(add_little_time); - let tasks: Vec = app - .wrap() - .query_wasm_smart( - contract_addr.clone(), - &QueryMsg::GetTasks { - from_index: None, - limit: None, - }, - ) - .unwrap(); - let tasks: Vec<(Vec, Vec)> = tasks - .into_iter() - .map(|task| (task.total_deposit, task.actions)) - .collect(); - println!("tasks: {tasks:?}"); + // let tasks: Vec = app + // .wrap() + // .query_wasm_smart( + // contract_addr.clone(), + // &QueryMsg::GetTasks { + // from_index: None, + // limit: None, + // }, + // ) + // .unwrap(); + // let tasks: Vec<(Vec, Vec)> = tasks + // .into_iter() + // .map(|task| (task.total_deposit, task.actions)) + // .collect(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; app.execute_contract( @@ -2320,21 +2369,20 @@ fn testing_fee_works() { .unwrap(); app.update_block(add_little_time); - let tasks: Vec = app - .wrap() - .query_wasm_smart( - contract_addr.clone(), - &QueryMsg::GetTasks { - from_index: None, - limit: None, - }, - ) - .unwrap(); - let tasks: Vec<(Vec, Vec)> = tasks - .into_iter() - .map(|task| (task.total_deposit, task.actions)) - .collect(); - println!("tasks: {tasks:?}"); + // let tasks: Vec = app + // .wrap() + // .query_wasm_smart( + // contract_addr.clone(), + // &QueryMsg::GetTasks { + // from_index: None, + // limit: None, + // }, + // ) + // .unwrap(); + // let tasks: Vec<(Vec, Vec)> = tasks + // .into_iter() + // .map(|task| (task.total_deposit, task.actions)) + // .collect(); let proxy_call_msg = ExecuteMsg::ProxyCall { task_hash: None }; app.execute_contract( @@ -3013,7 +3061,6 @@ fn test_error_in_reply() { &vec![], ) .unwrap(); - print!("{:#?}", res); // Check attributes, should have an error since we can't execute proposal yet let mut without_failure: bool = false; @@ -3026,3 +3073,37 @@ fn test_error_in_reply() { } assert!(without_failure); } + +#[test] +fn empty_actions_not_allowed() { + let (mut app, cw_template_contract, _) = proper_instantiate(); + let contract_addr = cw_template_contract.addr(); + + let empty_actions = ExecuteMsg::CreateTask { + task: TaskRequest { + interval: Interval::Once, + boundary: None, + stop_on_fail: false, + actions: vec![], + queries: None, + transforms: None, + cw20_coins: vec![], + }, + }; + + let total_gas = GAS_BASE_FEE + GAS_ACTION_FEE; + let attach_per_action = (total_gas + (total_gas * 5 / 100)) / GAS_NUMERATOR_DEFAULT; + let amount_for_three = (attach_per_action) as u128; + + let res: ContractError = app + .execute_contract( + Addr::unchecked(ADMIN), + contract_addr.clone(), + &empty_actions, + &coins(amount_for_three, NATIVE_DENOM), + ) + .unwrap_err() + .downcast() + .unwrap(); + assert_eq!(res, ContractError::CoreError(CoreError::InvalidAction {})); +} diff --git a/contracts/cw-croncat/src/tests/owner.rs b/contracts/cw-croncat/src/tests/owner.rs index 4faa27da..80e5721f 100644 --- a/contracts/cw-croncat/src/tests/owner.rs +++ b/contracts/cw-croncat/src/tests/owner.rs @@ -1,19 +1,12 @@ use crate::error::ContractError; use crate::state::CwCroncat; -use crate::tests::helpers::{ - add_little_time, proper_instantiate, ADMIN, AGENT0, AGENT_BENEFICIARY, ANYONE, NATIVE_DENOM, -}; +use crate::tests::helpers::NATIVE_DENOM; use cosmwasm_std::testing::{mock_dependencies_with_balance, mock_env, mock_info}; -use cosmwasm_std::{ - coin, coins, from_binary, to_binary, Addr, CosmosMsg, MessageInfo, StdResult, Uint64, WasmMsg, -}; +use cosmwasm_std::{coin, coins, from_binary, Addr, MessageInfo}; use cw20::Balance; use cw_croncat_core::msg::{ - CwCroncatResponse, ExecuteMsg, GetBalancesResponse, GetConfigResponse, InstantiateMsg, - QueryMsg, RoundRobinBalancerModeResponse, TaskRequest, + ExecuteMsg, GetBalancesResponse, GetConfigResponse, InstantiateMsg, QueryMsg, }; -use cw_croncat_core::types::{Action, Boundary, Interval}; -use cw_multi_test::Executor; #[test] fn update_settings() { @@ -26,7 +19,9 @@ fn update_settings() { owner_id: None, gas_base_fee: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: Some(360), }; let info = MessageInfo { @@ -46,11 +41,13 @@ fn update_settings() { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; // non-owner fails @@ -106,7 +103,9 @@ fn move_balances_auth_checks() { denom: NATIVE_DENOM.to_string(), owner_id: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: Some(360), cw_rules_addr: "todo".to_string(), gas_base_fee: None, @@ -123,11 +122,13 @@ fn move_balances_auth_checks() { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; let info_setting = mock_info("owner_id", &coins(0, "meow")); let res_exec = store @@ -175,7 +176,9 @@ fn move_balances_native() { denom: NATIVE_DENOM.to_string(), owner_id: None, gas_action_fee: None, - gas_fraction: None, + gas_query_fee: None, + gas_wasm_query_fee: None, + gas_price: None, agent_nomination_duration: Some(360), cw_rules_addr: "todo".to_string(), gas_base_fee: None, @@ -192,11 +195,13 @@ fn move_balances_native() { agent_fee: None, min_tasks_per_agent: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; let info_settings = mock_info("owner_id", &coins(0, "meow")); let res_exec = store @@ -285,122 +290,3 @@ fn move_balances_native() { // // assert_eq!(true, value.paused); // // assert_eq!(info.sender, value.owner_id); // } - -#[test] -fn test_get_state() { - let (mut app, cw_template_contract, _) = proper_instantiate(); - let contract_addr = cw_template_contract.addr(); - - let state: StdResult = app.wrap().query_wasm_smart( - &contract_addr.clone(), - &QueryMsg::GetState { - from_index: None, - limit: None, - }, - ); - assert!(state.is_ok()); - let state = state.unwrap(); - - assert_eq!(state.config.paused, false); - assert_eq!(state.config.owner_id.as_str(), ADMIN); - assert_eq!(state.config.agent_fee, 5); - assert_eq!(state.config.gas_base_fee, 300_000); - assert_eq!(state.config.gas_action_fee, 130_000); - assert_eq!(state.config.proxy_callback_gas, 3); - assert!(state.agent_active_queue.is_empty()); - assert!(state.agent_pending_queue.is_empty()); - assert!(state.agents.is_empty()); - assert!(state.tasks.is_empty()); - assert_eq!(state.task_total, Uint64::zero()); - assert!(state.time_slots.is_empty()); - assert!(state.block_slots.is_empty()); - assert!(state.tasks_with_queries.is_empty()); - assert_eq!(state.tasks_with_queries_total, Uint64::zero()); - assert!(state.time_slots_queries.is_empty()); - assert!(state.block_slots_queries.is_empty()); - assert_eq!(state.reply_index, Uint64::zero()); - assert_eq!(state.agent_nomination_begin_time, None); - assert_eq!( - state.balancer_mode, - RoundRobinBalancerModeResponse::ActivationOrder - ); - assert!(state.balances.is_empty()); - - // Create a task - let msg = CosmosMsg::Wasm(WasmMsg::Execute { - contract_addr: contract_addr.to_string(), - msg: to_binary(&ExecuteMsg::WithdrawReward {}).unwrap(), - funds: coins(1, NATIVE_DENOM), - }); - - let create_task_msg = ExecuteMsg::CreateTask { - task: TaskRequest { - interval: Interval::Immediate, - boundary: Some(Boundary::Height { - start: None, - end: None, - }), - stop_on_fail: false, - actions: vec![Action { - msg, - gas_limit: Some(250_000), - }], - queries: None, - transforms: None, - cw20_coins: vec![], - }, - }; - - // create a task - app.execute_contract( - Addr::unchecked(ADMIN), - contract_addr.clone(), - &create_task_msg, - &coins(525000, NATIVE_DENOM), - ) - .unwrap(); - - // quick agent register - let msg = ExecuteMsg::RegisterAgent { - payable_account_id: Some(AGENT_BENEFICIARY.to_string()), - }; - app.execute_contract(Addr::unchecked(AGENT0), contract_addr.clone(), &msg, &[]) - .unwrap(); - // in pending queue - app.execute_contract(Addr::unchecked(ANYONE), contract_addr.clone(), &msg, &[]) - .unwrap(); - - // might need block advancement - app.update_block(add_little_time); - - let state: StdResult = app.wrap().query_wasm_smart( - &contract_addr.clone(), - &QueryMsg::GetState { - from_index: None, - limit: None, - }, - ); - assert!(state.is_ok()); - let state = state.unwrap(); - - let task_id_str = - "1032a37c92801f73c75816bddb4f0db8516baeeeacd6a2c225f0a6a54c96732e".to_string(); - - assert_eq!(state.agent_active_queue.len(), 1); - assert_eq!(state.agent_active_queue[0].as_str(), AGENT0); - assert_eq!(state.agent_pending_queue.len(), 1); - assert_eq!(state.agent_pending_queue[0].as_str(), ANYONE); - assert_eq!(state.agents.len(), 1); - assert_eq!(state.tasks.len(), 1); - assert_eq!(state.tasks[0].task_hash, task_id_str); - assert_eq!(state.task_total, Uint64::from(1u64)); - assert!(state.time_slots.is_empty()); - assert_eq!(state.block_slots.len(), 1); - assert!(state.tasks_with_queries.is_empty()); - assert_eq!(state.tasks_with_queries_total, Uint64::zero()); - assert!(state.time_slots_queries.is_empty()); - assert!(state.block_slots_queries.is_empty()); - assert_eq!(state.reply_index, Uint64::zero()); - assert!(state.agent_nomination_begin_time.is_some()); - assert!(state.balances.is_empty()); -} diff --git a/contracts/cw-croncat/src/tests/receiver.rs b/contracts/cw-croncat/src/tests/receiver.rs index 42f351b5..2ac8fa37 100644 --- a/contracts/cw-croncat/src/tests/receiver.rs +++ b/contracts/cw-croncat/src/tests/receiver.rs @@ -335,7 +335,6 @@ fn test_cw20_negative() { .unwrap_err() .downcast() .unwrap(); - println!("resp: {resp:?}"); assert!(matches!( resp, ContractError::CoreError(CoreError::NotEnoughCw20 { lack, .. }) if lack == Uint128::from(10_u128))); diff --git a/contracts/cw-croncat/src/tests/slots.rs b/contracts/cw-croncat/src/tests/slots.rs index 70d4ad60..0d0c98a7 100644 --- a/contracts/cw-croncat/src/tests/slots.rs +++ b/contracts/cw-croncat/src/tests/slots.rs @@ -21,6 +21,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 12346, SlotType::Block, @@ -30,6 +31,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: Some(12348), end: None, + is_block_boundary: Some(true), }, 12348, SlotType::Block, @@ -39,6 +41,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: Some(12346), + is_block_boundary: Some(true), }, 12346, SlotType::Block, @@ -48,6 +51,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: Some(12340), + is_block_boundary: Some(true), }, 0, SlotType::Block, @@ -58,6 +62,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 12346, SlotType::Block, @@ -67,6 +72,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: Some(12348), end: None, + is_block_boundary: Some(true), }, 12348, SlotType::Block, @@ -76,6 +82,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: Some(12346), + is_block_boundary: Some(true), }, 12346, SlotType::Block, @@ -85,6 +92,7 @@ fn interval_get_next_block_limited() { BoundaryValidated { start: None, end: Some(12340), + is_block_boundary: Some(true), }, 0, SlotType::Block, @@ -109,6 +117,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 12346, SlotType::Block, @@ -118,6 +127,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 12350, SlotType::Block, @@ -127,6 +137,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 12400, SlotType::Block, @@ -136,6 +147,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 13000, SlotType::Block, @@ -145,6 +157,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 20000, SlotType::Block, @@ -154,6 +167,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(true), }, 100000, SlotType::Block, @@ -164,6 +178,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: Some(12348), end: None, + is_block_boundary: Some(true), }, 12348, SlotType::Block, @@ -173,6 +188,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: Some(12360), end: None, + is_block_boundary: Some(true), }, 12360, SlotType::Block, @@ -182,6 +198,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: Some(12364), end: None, + is_block_boundary: Some(true), }, 12370, SlotType::Block, @@ -191,6 +208,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: Some(12364), end: None, + is_block_boundary: Some(true), }, 12400, SlotType::Block, @@ -201,6 +219,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: Some(12345), + is_block_boundary: Some(true), }, 12345, SlotType::Block, @@ -210,6 +229,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: Some(12355), + is_block_boundary: Some(true), }, 12350, SlotType::Block, @@ -219,6 +239,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: Some(12355), + is_block_boundary: Some(true), }, 12300, SlotType::Block, @@ -228,6 +249,7 @@ fn interval_get_next_block_by_offset() { BoundaryValidated { start: None, end: Some(12300), + is_block_boundary: Some(true), }, 0, SlotType::Block, @@ -252,6 +274,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_797_420_000_000_000, // current time in nanos is 1_571_797_419_879_305_533 SlotType::Cron, @@ -261,6 +284,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_797_441_000_000_000, SlotType::Cron, @@ -270,6 +294,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_799_600_000_000_000, SlotType::Cron, @@ -279,6 +304,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_799_615_000_000_000, SlotType::Cron, @@ -289,6 +315,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_471_799_600_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_799_615_000_000_000, SlotType::Cron, @@ -298,6 +325,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_571_799_600_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_799_615_000_000_000, SlotType::Cron, @@ -307,6 +335,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_571_799_700_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_803_215_000_000_000, SlotType::Cron, @@ -318,6 +347,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_419_879_305_533), + is_block_boundary: Some(false), }, 1_571_797_419_879_305_533, SlotType::Cron, @@ -328,6 +358,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_419_879_305_535), + is_block_boundary: Some(false), }, 1_571_797_419_879_305_535, SlotType::Cron, @@ -338,6 +369,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_420_000_000_000), + is_block_boundary: Some(false), }, 1_571_797_420_000_000_000, SlotType::Cron, @@ -348,6 +380,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_419_879_305_532), + is_block_boundary: Some(false), }, 0, SlotType::Cron, @@ -368,6 +401,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, // the timestamp is in the current slot, so we take the next slot 1_571_797_420_000_000_000_u64.saturating_sub(1_571_797_420_000_000_000 % TWO_MINUTES) @@ -379,6 +413,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_797_440_000_000_000, SlotType::Cron, @@ -388,6 +423,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_799_600_000_000_000, SlotType::Cron, @@ -397,6 +433,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: None, + is_block_boundary: Some(false), }, 1_571_799_600_000_000_000, SlotType::Cron, @@ -407,6 +444,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_471_799_600_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_799_600_000_000_000, SlotType::Cron, @@ -416,6 +454,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_571_799_600_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_799_600_000_000_000, SlotType::Cron, @@ -425,6 +464,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: Some(1_571_799_700_000_000_000), end: None, + is_block_boundary: Some(false), }, 1_571_803_200_000_000_000, SlotType::Cron, @@ -436,6 +476,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_419_879_305_535), + is_block_boundary: Some(false), }, 1_571_797_320_000_000_000, SlotType::Cron, @@ -446,6 +487,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_560_000_000_000), + is_block_boundary: Some(false), }, 1_571_797_440_000_000_000, SlotType::Cron, @@ -456,6 +498,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_420_000_000_000), + is_block_boundary: Some(false), }, 1_571_797_320_000_000_000, SlotType::Cron, @@ -466,6 +509,7 @@ fn interval_get_next_cron_time() { BoundaryValidated { start: None, end: Some(1_571_797_419_879_305_532), + is_block_boundary: Some(false), }, 0, SlotType::Cron, diff --git a/contracts/cw-croncat/src/tests/state.rs b/contracts/cw-croncat/src/tests/state.rs index 38eeb3a7..9e85afe8 100644 --- a/contracts/cw-croncat/src/tests/state.rs +++ b/contracts/cw-croncat/src/tests/state.rs @@ -25,6 +25,7 @@ fn check_task_storage_structure() -> StdResult<()> { boundary: BoundaryValidated { start: None, end: None, + is_block_boundary: None, }, stop_on_fail: false, total_deposit: Default::default(), @@ -37,7 +38,7 @@ fn check_task_storage_structure() -> StdResult<()> { transforms: None, version: version.version, }; - let task_id_str = "69217dd2b6334abe2544a12fcb89588f9cc5c62a298b8720706d9befa3d736d3"; + let task_id_str = "74b918b7c8ff739ff30e47e2053b2be194b365de2825eaa21c37b349871db9bb"; let task_id = task_id_str.to_string().into_bytes(); // create a task diff --git a/contracts/cw-croncat/src/tests/tasks.rs b/contracts/cw-croncat/src/tests/tasks.rs index 7983bca1..8191993d 100644 --- a/contracts/cw-croncat/src/tests/tasks.rs +++ b/contracts/cw-croncat/src/tests/tasks.rs @@ -1,5 +1,8 @@ use super::helpers::{ADMIN, ANYONE, NATIVE_DENOM, VERY_RICH}; -use crate::contract::{GAS_ACTION_FEE_JUNO, GAS_BASE_FEE_JUNO, GAS_DENOMINATOR_DEFAULT_JUNO}; +use crate::contract::{ + GAS_ACTION_FEE, GAS_ADJUSTMENT_NUMERATOR_DEFAULT, GAS_BASE_FEE, GAS_DENOMINATOR, + GAS_NUMERATOR_DEFAULT, +}; use crate::tests::helpers::proper_instantiate; use crate::ContractError; use cosmwasm_std::{ @@ -36,6 +39,7 @@ fn query_task_hash_success() { boundary: BoundaryValidated { start: None, end: None, + is_block_boundary: None, }, stop_on_fail: false, total_deposit: GenericBalance { @@ -63,7 +67,7 @@ fn query_task_hash_success() { ) .unwrap(); assert_eq!( - "69217dd2b6334abe2544a12fcb89588f9cc5c62a298b8720706d9befa3d736d3", + "74b918b7c8ff739ff30e47e2053b2be194b365de2825eaa21c37b349871db9bb", task_hash ); } @@ -216,18 +220,6 @@ fn query_get_tasks_pagination() { let expected_amnt: usize = (tasks_amnt - from_index).try_into().unwrap(); assert_eq!(part_of_tasks.len(), expected_amnt); - println!( - "half_tasks: {:?}\n hash_vec:{:?}", - part_of_tasks - .iter() - .map(|t| t.task_hash.clone()) - .collect::>(), - all_tasks - .iter() - .map(|t| t.task_hash.clone()) - .collect::>(), - ); - // Check it's in right order for i in 0..expected_amnt { assert_eq!( @@ -356,12 +348,14 @@ fn check_task_create_fail_cases() -> StdResult<()> { // treasury_id: None, agent_fee: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, min_tasks_per_agent: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }; app.execute_contract( Addr::unchecked(ADMIN), @@ -394,12 +388,14 @@ fn check_task_create_fail_cases() -> StdResult<()> { // treasury_id: None, agent_fee: None, agents_eject_threshold: None, - gas_fraction: None, + gas_price: None, proxy_callback_gas: None, slot_granularity_time: None, min_tasks_per_agent: None, gas_base_fee: None, gas_action_fee: None, + gas_query_fee: None, + gas_wasm_query_fee: None, }, &vec![], ) @@ -578,8 +574,6 @@ fn check_task_create_success() -> StdResult<()> { cw20_coins: vec![], }, }; - let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); // create a task let res = app @@ -592,10 +586,12 @@ fn check_task_create_success() -> StdResult<()> { .unwrap(); // Assert task hash is returned as part of event attributes let mut has_created_hash: bool = false; + let mut task_hash = String::new(); for e in res.events { for a in e.attributes { - if a.key == "task_hash" && a.value == task_id_str.clone() { + if a.key == "task_hash" && a.value.len() > 0 { has_created_hash = true; + task_hash = a.value; } } } @@ -607,7 +603,7 @@ fn check_task_create_success() -> StdResult<()> { .query_wasm_smart( &contract_addr.clone(), &QueryMsg::GetTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, ) .unwrap(); @@ -615,10 +611,10 @@ fn check_task_create_success() -> StdResult<()> { if let Some(t) = new_task { assert_eq!(Addr::unchecked(ANYONE), t.owner_id); assert_eq!(Interval::Immediate, t.interval); - assert_eq!(None, t.boundary); + assert!(t.boundary.is_some()); assert_eq!(false, t.stop_on_fail); assert_eq!(coins(315006, NATIVE_DENOM), t.total_deposit); - assert_eq!(task_id_str.clone(), t.task_hash); + assert_eq!(task_hash.clone(), t.task_hash); } // get slot ids @@ -640,7 +636,7 @@ fn check_task_create_success() -> StdResult<()> { .unwrap(); let s_3: Vec = Vec::new(); assert_eq!(12346, slot_info.block_id); - assert_eq!(vec![task_id_str.clone()], slot_info.block_task_hash); + assert_eq!(vec![task_hash], slot_info.block_task_hash); assert_eq!(0, slot_info.time_id); assert_eq!(s_3, slot_info.time_task_hash); @@ -851,25 +847,34 @@ fn check_remove_create() -> StdResult<()> { cw20_coins: vec![], }, }; - let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); // create a task - app.execute_contract( - Addr::unchecked(ANYONE), - contract_addr.clone(), - &create_task_msg, - &coins(315006, NATIVE_DENOM), - ) - .unwrap(); + let create_task_resp = app + .execute_contract( + Addr::unchecked(ANYONE), + contract_addr.clone(), + &create_task_msg, + &coins(315006, NATIVE_DENOM), + ) + .unwrap(); + + let mut task_hash: String = String::new(); + for e in create_task_resp.events { + for a in e.attributes { + if a.key == "task_hash" && a.value.len() > 0 { + task_hash = a.value; + } + } + } + println!("{:?}", task_hash); // check storage DOES have the task let new_task: Option = app .wrap() .query_wasm_smart( &contract_addr.clone(), &QueryMsg::GetTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, ) .unwrap(); @@ -889,7 +894,7 @@ fn check_remove_create() -> StdResult<()> { Addr::unchecked(ADMIN), contract_addr.clone(), &ExecuteMsg::RemoveTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, &vec![], ) @@ -900,7 +905,7 @@ fn check_remove_create() -> StdResult<()> { Addr::unchecked(ANYONE), contract_addr.clone(), &ExecuteMsg::RemoveTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, &vec![], ) @@ -912,7 +917,7 @@ fn check_remove_create() -> StdResult<()> { .query_wasm_smart( &contract_addr.clone(), &QueryMsg::GetTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, ) .unwrap(); @@ -961,24 +966,32 @@ fn check_refill_create() -> StdResult<()> { cw20_coins: vec![], }, }; - let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); // create a task - app.execute_contract( - Addr::unchecked(ANYONE), - contract_addr.clone(), - &create_task_msg, - &coins(315006, NATIVE_DENOM), - ) - .unwrap(); + let create_task_resp = app + .execute_contract( + Addr::unchecked(ANYONE), + contract_addr.clone(), + &create_task_msg, + &coins(315006, NATIVE_DENOM), + ) + .unwrap(); + let mut task_hash: String = String::new(); + for e in create_task_resp.events { + for a in e.attributes { + if a.key == "task_hash" && a.value.len() > 0 { + task_hash = a.value; + } + } + } + // refill task let res = app .execute_contract( Addr::unchecked(ANYONE), contract_addr.clone(), &ExecuteMsg::RefillTaskBalance { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, &coins(3, NATIVE_DENOM), ) @@ -1000,7 +1013,7 @@ fn check_refill_create() -> StdResult<()> { .query_wasm_smart( &contract_addr.clone(), &QueryMsg::GetTask { - task_hash: task_id_str.clone(), + task_hash: task_hash.clone(), }, ) .unwrap(); @@ -1034,7 +1047,7 @@ fn check_gas_minimum() { let stake = StakingMsg::Delegate { validator, amount }; let msg: CosmosMsg = stake.clone().into(); let gas_limit = 150_000; - let base_gas = GAS_BASE_FEE_JUNO; + let base_gas = GAS_BASE_FEE; let create_task_msg = ExecuteMsg::CreateTask { task: TaskRequest { @@ -1052,8 +1065,12 @@ fn check_gas_minimum() { }; // create 1 token off task let gas_for_two = (base_gas + gas_limit) * 2; - let enough_for_two = - u128::from((gas_for_two + gas_for_two * 5 / 100) / GAS_DENOMINATOR_DEFAULT_JUNO + 3 * 2); + let enough_for_two = u128::from( + (gas_for_two + gas_for_two * 5 / 100) * GAS_ADJUSTMENT_NUMERATOR_DEFAULT / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + + 3 * 2, + ); let res: ContractError = app .execute_contract( Addr::unchecked(ANYONE), @@ -1091,8 +1108,8 @@ fn check_gas_default() { let amount = coin(3, NATIVE_DENOM); let stake = StakingMsg::Delegate { validator, amount }; let msg: CosmosMsg = stake.clone().into(); - let gas_limit = GAS_ACTION_FEE_JUNO; - let base_gas = GAS_BASE_FEE_JUNO; + let gas_limit = GAS_ACTION_FEE; + let base_gas = GAS_BASE_FEE; // let send = BankMsg::Send { // to_address: validator, // amount: vec![amount], @@ -1117,7 +1134,12 @@ fn check_gas_default() { let gas_for_one = base_gas + gas_limit; let gas_for_one_with_fee = gas_for_one + gas_for_one * 5 / 100; - let enough_for_two = 2 * u128::from(gas_for_one_with_fee / GAS_DENOMINATOR_DEFAULT_JUNO + 3); + let enough_for_two = 2 * u128::from( + gas_for_one_with_fee * GAS_ADJUSTMENT_NUMERATOR_DEFAULT / GAS_DENOMINATOR + * GAS_NUMERATOR_DEFAULT + / GAS_DENOMINATOR + + 3, + ); let res: ContractError = app .execute_contract( diff --git a/contracts/cw-rules/Cargo.toml b/contracts/cw-rules/Cargo.toml index 867db4eb..3be7286d 100644 --- a/contracts/cw-rules/Cargo.toml +++ b/contracts/cw-rules/Cargo.toml @@ -47,8 +47,7 @@ thiserror = { version = "1.0.31" } # This thing saved our lives thanks @hashedone for implementing it serde-cw-value = "0.7.0" -# TODO: update when this feature is merged -serde-json-wasm = { version = "0.4.1", git = "https://github.com/CyberHoward/serde-json-wasm", rev = "cdc78130b25d65981b74a5e4a10a9f8667292d36" } +serde-json-wasm = { version = "0.5.0" } [dev-dependencies] cw721-base = "0.15.0" @@ -69,3 +68,4 @@ cw4 = "0.16.0" cw4-group = "0.16.0" base64 = "0.13.0" serde_json = { version = "1.0", default-features = false, features = ["alloc"] } +rusty-hook = "0.11.2" diff --git a/justfile b/justfile index 3acd01b8..6af25e8b 100644 --- a/justfile +++ b/justfile @@ -1,15 +1,15 @@ test_addrs := env_var_or_default('TEST_ADDR', `jq -r '.[].address' ci/test_accounts.json | tr '\n' ' '`) set export -check: +lint: cargo fmt --all && cargo clippy -- -D warnings test: #!/bin/bash - set -e - export RUSTFLAGS='-C link-arg=-s' cargo unit-test cargo wasm build: #!/bin/bash + set -e + export RUSTFLAGS='-C link-arg=-s' cargo build --release --lib --target wasm32-unknown-unknown deploy: ./scripts/uni-testnet/start.sh -c -w @@ -24,8 +24,9 @@ schema: gen: #!/usr/bin/env bash cd typescript - yarn --cwd ./typescript install --frozen-lockfile + yarn --cwd ./typescript build yarn --cwd ./typescript codegen + yarn --cwd ./typescript install --frozen-lockfile juno-local: docker kill cosmwasm || true docker volume rm -f junod_data @@ -49,12 +50,31 @@ optimize: --platform linux/amd64 \ cosmwasm/workspace-optimizer:0.12.8 +optimize-m1: + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + --platform linux/arm64 \ + cosmwasm/workspace-optimizer:0.12.8 + +optimize-rs: + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer-arm64:0.12.8 + +optimize-rs-m1: + docker run --rm -v "$(pwd)":/code \ + --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ + --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ + cosmwasm/rust-optimizer-arm64:0.12.8 + download-deps: mkdir -p artifacts target wget https://github.com/CosmWasm/cw-plus/releases/latest/download/cw20_base.wasm -O artifacts/cw20_base.wasm # TODO?: test dao-contracts -all: build test check schema gen optimize checksum +all: lint build test schema gen optimize checksum #!/usr/bin/env bash gas-benchmark: juno-local download-deps optimize diff --git a/packages/cw-croncat-core/Cargo.toml b/packages/cw-croncat-core/Cargo.toml index d9bfcb02..2a36ee8d 100644 --- a/packages/cw-croncat-core/Cargo.toml +++ b/packages/cw-croncat-core/Cargo.toml @@ -23,13 +23,13 @@ cw20 = { version = "0.13.4" } schemars = "0.8" serde = { version = "1.0", default-features = false, features = ["derive"] } thiserror = { version = "1.0" } -hex = "0.4" -sha2 = "0.10.6" +hex = { version = "0.4", default-features = false } +sha2 = { version = "0.10.6", default-features = false } serde-cw-value = "0.7.0" -# TODO: update when this feature is merged -serde-json-wasm = { version = "0.4.1", git = "https://github.com/CyberHoward/serde-json-wasm", rev = "cdc78130b25d65981b74a5e4a10a9f8667292d36" } +serde-json-wasm = { version = "0.5.0" } [dev-dependencies] cosmwasm-schema = { version = "1.0.0" } cw-multi-test = { version = "0.16.0", features = ["staking"] } -cw20-base = { version = "0.13.4", features = ["library"] } \ No newline at end of file +cw20-base = { version = "0.13.4", features = ["library"] } +rusty-hook = "0.11.2" diff --git a/packages/cw-croncat-core/examples/schema.rs b/packages/cw-croncat-core/examples/schema.rs index d2671d43..fdddc0ef 100644 --- a/packages/cw-croncat-core/examples/schema.rs +++ b/packages/cw-croncat-core/examples/schema.rs @@ -3,7 +3,7 @@ use std::fs::create_dir_all; use cosmwasm_schema::{export_schema, export_schema_with_title, remove_schemas, schema_for}; use cw_croncat_core::msg::{ - AgentResponse, Croncat, CwCroncatResponse, ExecuteMsg, InstantiateMsg, QueryMsg, TaskResponse, + AgentResponse, Croncat, ExecuteMsg, InstantiateMsg, QueryMsg, TaskResponse, TaskWithQueriesResponse, }; @@ -51,9 +51,4 @@ fn main() { &out_dir, "GetAgentTasksResponse", ); - export_schema_with_title( - &schema_for!(CwCroncatResponse), - &out_dir, - "GetStateResponse", - ); } diff --git a/packages/cw-croncat-core/schema/croncat.json b/packages/cw-croncat-core/schema/croncat.json index be29fddd..74db5cef 100644 --- a/packages/cw-croncat-core/schema/croncat.json +++ b/packages/cw-croncat-core/schema/croncat.json @@ -477,6 +477,12 @@ "format": "uint64", "minimum": 0.0 }, + "is_block_boundary": { + "type": [ + "boolean", + "null" + ] + }, "start": { "type": [ "integer", @@ -849,10 +855,11 @@ "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", "type": "object" }, - "GasFraction": { + "GasPrice": { "type": "object", "required": [ "denominator", + "gas_adjustment_numerator", "numerator" ], "properties": { @@ -861,6 +868,12 @@ "format": "uint64", "minimum": 0.0 }, + "gas_adjustment_numerator": { + "description": "Note", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "numerator": { "type": "integer", "format": "uint64", @@ -975,7 +988,7 @@ "cw_rules_addr", "gas_action_fee", "gas_base_fee", - "gas_fraction", + "gas_price", "limit", "min_tasks_per_agent", "native_denom", @@ -1046,8 +1059,8 @@ "format": "uint64", "minimum": 0.0 }, - "gas_fraction": { - "$ref": "#/definitions/GasFraction" + "gas_price": { + "$ref": "#/definitions/GasPrice" }, "limit": { "type": "integer", diff --git a/packages/cw-croncat-core/schema/execute_msg.json b/packages/cw-croncat-core/schema/execute_msg.json index 1876b92a..7c8b1476 100644 --- a/packages/cw-croncat-core/schema/execute_msg.json +++ b/packages/cw-croncat-core/schema/execute_msg.json @@ -47,10 +47,30 @@ } ] }, - "gas_fraction": { + "gas_price": { "anyOf": [ { - "$ref": "#/definitions/GasFraction" + "$ref": "#/definitions/GasPrice" + }, + { + "type": "null" + } + ] + }, + "gas_query_fee": { + "anyOf": [ + { + "$ref": "#/definitions/Uint64" + }, + { + "type": "null" + } + ] + }, + "gas_wasm_query_fee": { + "anyOf": [ + { + "$ref": "#/definitions/Uint64" }, { "type": "null" @@ -938,10 +958,11 @@ "description": "An empty struct that serves as a placeholder in different places, such as contracts that don't set a custom message.\n\nIt is designed to be expressable in correct JSON and JSON Schema but contains no meaningful data. Previously we used enums without cases, but those cannot represented as valid JSON Schema (https://github.com/CosmWasm/cosmwasm/issues/451)", "type": "object" }, - "GasFraction": { + "GasPrice": { "type": "object", "required": [ "denominator", + "gas_adjustment_numerator", "numerator" ], "properties": { @@ -950,6 +971,12 @@ "format": "uint64", "minimum": 0.0 }, + "gas_adjustment_numerator": { + "description": "Note", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "numerator": { "type": "integer", "format": "uint64", diff --git a/packages/cw-croncat-core/schema/instantiate_msg.json b/packages/cw-croncat-core/schema/instantiate_msg.json index 8ecab164..ed26bab2 100644 --- a/packages/cw-croncat-core/schema/instantiate_msg.json +++ b/packages/cw-croncat-core/schema/instantiate_msg.json @@ -41,10 +41,30 @@ } ] }, - "gas_fraction": { + "gas_price": { "anyOf": [ { - "$ref": "#/definitions/GasFraction" + "$ref": "#/definitions/GasPrice" + }, + { + "type": "null" + } + ] + }, + "gas_query_fee": { + "anyOf": [ + { + "$ref": "#/definitions/Uint64" + }, + { + "type": "null" + } + ] + }, + "gas_wasm_query_fee": { + "anyOf": [ + { + "$ref": "#/definitions/Uint64" }, { "type": "null" @@ -59,10 +79,11 @@ } }, "definitions": { - "GasFraction": { + "GasPrice": { "type": "object", "required": [ "denominator", + "gas_adjustment_numerator", "numerator" ], "properties": { @@ -71,6 +92,12 @@ "format": "uint64", "minimum": 0.0 }, + "gas_adjustment_numerator": { + "description": "Note", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "numerator": { "type": "integer", "format": "uint64", diff --git a/packages/cw-croncat-core/schema/query_msg.json b/packages/cw-croncat-core/schema/query_msg.json index 6c545a9f..ce0158ea 100644 --- a/packages/cw-croncat-core/schema/query_msg.json +++ b/packages/cw-croncat-core/schema/query_msg.json @@ -271,36 +271,6 @@ } }, "additionalProperties": false - }, - { - "type": "object", - "required": [ - "get_state" - ], - "properties": { - "get_state": { - "type": "object", - "properties": { - "from_index": { - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "limit": { - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false } ], "definitions": { @@ -433,6 +403,12 @@ "format": "uint64", "minimum": 0.0 }, + "is_block_boundary": { + "type": [ + "boolean", + "null" + ] + }, "start": { "type": [ "integer", diff --git a/packages/cw-croncat-core/src/msg.rs b/packages/cw-croncat-core/src/msg.rs index 8e48b06d..6edf6dd5 100644 --- a/packages/cw-croncat-core/src/msg.rs +++ b/packages/cw-croncat-core/src/msg.rs @@ -1,7 +1,7 @@ use crate::error::CoreError; use crate::traits::Intervals; use crate::types::{ - Action, AgentStatus, Boundary, BoundaryValidated, GasFraction, GenericBalance, Interval, Task, + Action, AgentStatus, Boundary, BoundaryValidated, GasPrice, GenericBalance, Interval, Task, Transform, }; use crate::types::{Agent, SlotType}; @@ -64,7 +64,9 @@ pub struct InstantiateMsg { pub owner_id: Option, pub gas_base_fee: Option, pub gas_action_fee: Option, - pub gas_fraction: Option, + pub gas_query_fee: Option, + pub gas_wasm_query_fee: Option, + pub gas_price: Option, pub agent_nomination_duration: Option, } @@ -78,7 +80,9 @@ pub enum ExecuteMsg { agent_fee: Option, gas_base_fee: Option, gas_action_fee: Option, - gas_fraction: Option, + gas_query_fee: Option, + gas_wasm_query_fee: Option, + gas_price: Option, proxy_callback_gas: Option, min_tasks_per_agent: Option, agents_eject_threshold: Option, @@ -164,68 +168,6 @@ pub enum QueryMsg { GetWalletBalances { wallet: String, }, - GetState { - from_index: Option, - limit: Option, - }, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct GetConfigResponse { - pub paused: bool, - pub owner_id: Addr, - // pub treasury_id: Option, - pub min_tasks_per_agent: u64, - pub agents_eject_threshold: u64, - pub agent_active_indices: Vec<(SlotType, u32, u32)>, - pub agent_nomination_duration: u16, - - pub cw_rules_addr: Addr, - - pub agent_fee: u64, - pub gas_fraction: GasFraction, - pub gas_base_fee: u64, - pub gas_action_fee: u64, - pub proxy_callback_gas: u32, - pub slot_granularity_time: u64, - - pub cw20_whitelist: Vec, - pub native_denom: String, - pub available_balance: GenericBalance, // tasks + rewards balances - pub staked_balance: GenericBalance, // surplus that is temporary staking (to be used in conjunction with external treasury) - - // The default amount of tasks to query - pub limit: u64, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct GetBalancesResponse { - pub native_denom: String, - pub available_balance: GenericBalance, - pub staked_balance: GenericBalance, - pub cw20_whitelist: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct GetWalletBalancesResponse { - pub cw20_balances: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct GetAgentIdsResponse { - pub active: Vec, - pub pending: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct AgentResponse { - // This field doesn't exist in the Agent struct and is the only one that differs - pub status: AgentStatus, - pub payable_account_id: Addr, - pub balance: GenericBalance, - pub total_tasks_executed: u64, - pub last_executed_slot: u64, - pub register_start: Timestamp, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] @@ -416,70 +358,32 @@ pub struct TaskWithQueriesResponse { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct CwCroncatResponse { - pub config: GetConfigResponse, - - pub agent_active_queue: Vec, - pub agent_pending_queue: Vec, - pub agents: Vec, - - pub tasks: Vec, - pub task_total: Uint64, - - pub time_slots: Vec, - pub block_slots: Vec, - pub tasks_with_queries: Vec, - pub tasks_with_queries_total: Uint64, - - pub time_slots_queries: Vec, - pub block_slots_queries: Vec, - - pub reply_index: Uint64, - - pub agent_nomination_begin_time: Option, - - pub balancer_mode: RoundRobinBalancerModeResponse, - pub balances: Vec, -} - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct SlotResponse { - pub slot: Uint64, - pub tasks: Vec>, +pub struct GetBalancesResponse { + pub native_denom: String, + pub available_balance: GenericBalance, + pub staked_balance: GenericBalance, + pub cw20_whitelist: Vec, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] -pub struct BalancesResponse { - pub address: Addr, - pub balances: Vec, +pub struct GetWalletBalancesResponse { + pub cw20_balances: Vec, } - #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub enum RoundRobinBalancerModeResponse { - ActivationOrder, - Equalizer, +pub struct GetAgentIdsResponse { + pub active: Vec, + pub pending: Vec, } -// #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -// pub struct ReplyQueueResponse { -// pub index: Uint64, -// pub item: QueueItemResponse, -// } - -// #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -// pub struct QueueItemResponse { -// pub contract_addr: Option, -// pub action_idx: Uint64, -// pub task_hash: Option>, -// pub task_is_extra: Option, -// pub agent_id: Option, -// pub failed: bool, -// } - -#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct SlotWithQueriesResponse { - pub task_hash: Vec, - pub slot: Uint64, +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct AgentResponse { + // This field doesn't exist in the Agent struct and is the only one that differs + pub status: AgentStatus, + pub payable_account_id: Addr, + pub balance: GenericBalance, + pub total_tasks_executed: u64, + pub last_executed_slot: u64, + pub register_start: Timestamp, } impl From for TaskResponse { @@ -489,14 +393,29 @@ impl From for TaskResponse { BoundaryValidated { start: None, end: None, + is_block_boundary: None, }, _, ) => None, - (BoundaryValidated { start, end }, Interval::Cron(_)) => Some(Boundary::Time { + ( + BoundaryValidated { + start, + end, + is_block_boundary: _, + }, + Interval::Cron(_), + ) => Some(Boundary::Time { start: start.map(Timestamp::from_nanos), end: end.map(Timestamp::from_nanos), }), - (BoundaryValidated { start, end }, _) => Some(Boundary::Height { + ( + BoundaryValidated { + start, + end, + is_block_boundary: _, + }, + _, + ) => Some(Boundary::Height { start: start.map(Into::into), end: end.map(Into::into), }), @@ -524,14 +443,29 @@ impl From for TaskWithQueriesResponse { BoundaryValidated { start: None, end: None, + is_block_boundary: None, }, _, ) => None, - (BoundaryValidated { start, end }, Interval::Cron(_)) => Some(Boundary::Time { + ( + BoundaryValidated { + start, + end, + is_block_boundary: _, + }, + Interval::Cron(_), + ) => Some(Boundary::Time { start: start.map(Timestamp::from_nanos), end: end.map(Timestamp::from_nanos), }), - (BoundaryValidated { start, end }, _) => Some(Boundary::Height { + ( + BoundaryValidated { + start, + end, + is_block_boundary: _, + }, + _, + ) => Some(Boundary::Height { start: start.map(Into::into), end: end.map(Into::into), }), @@ -564,3 +498,31 @@ pub struct GetSlotIdsResponse { pub struct QueryConstruct { pub queries: Vec, } + +#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] +pub struct GetConfigResponse { + pub paused: bool, + pub owner_id: Addr, + // pub treasury_id: Option, + pub min_tasks_per_agent: u64, + pub agents_eject_threshold: u64, + pub agent_active_indices: Vec<(SlotType, u32, u32)>, + pub agent_nomination_duration: u16, + + pub cw_rules_addr: Addr, + + pub agent_fee: u64, + pub gas_price: GasPrice, + pub gas_base_fee: u64, + pub gas_action_fee: u64, + pub proxy_callback_gas: u32, + pub slot_granularity_time: u64, + + pub cw20_whitelist: Vec, + pub native_denom: String, + pub available_balance: GenericBalance, // tasks + rewards balances + pub staked_balance: GenericBalance, // surplus that is temporary staking (to be used in conjunction with external treasury) + + // The default amount of tasks to query + pub limit: u64, +} diff --git a/packages/cw-croncat-core/src/tests/msg.rs b/packages/cw-croncat-core/src/tests/msg.rs index 21cdacd1..ec1099bd 100644 --- a/packages/cw-croncat-core/src/tests/msg.rs +++ b/packages/cw-croncat-core/src/tests/msg.rs @@ -9,7 +9,7 @@ use crate::{ TaskRequest, TaskRequestBuilder, TaskResponse, }, types::{ - Action, Agent, AgentStatus, Boundary, BoundaryValidated, GasFraction, GenericBalance, + Action, Agent, AgentStatus, Boundary, BoundaryValidated, GasPrice, GenericBalance, Interval, SlotType, Task, }, }; @@ -44,6 +44,7 @@ fn everything_can_be_de_serialized() { boundary: BoundaryValidated { start: Some(54), end: Some(44), + is_block_boundary: Some(true), }, stop_on_fail: false, total_deposit: Default::default(), @@ -65,9 +66,10 @@ fn everything_can_be_de_serialized() { agent_active_indices: vec![(SlotType::Block, 10, 5)], agents_eject_threshold: 5, agent_fee: 5, - gas_fraction: GasFraction { + gas_price: GasPrice { numerator: 1, denominator: 2, + gas_adjustment_numerator: 3, }, proxy_callback_gas: 3, slot_granularity_time: 60_000_000, diff --git a/packages/cw-croncat-core/src/tests/types.rs b/packages/cw-croncat-core/src/tests/types.rs index 3bfaa88f..b9d2c38c 100644 --- a/packages/cw-croncat-core/src/tests/types.rs +++ b/packages/cw-croncat-core/src/tests/types.rs @@ -40,6 +40,8 @@ fn is_valid_msg_once_block_based() { &Addr::unchecked("bob"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .is_ok()); @@ -74,6 +76,8 @@ fn is_valid_msg_once_time_based() { &Addr::unchecked("bob"), 5, 5, + 5, + 5 ) .is_ok()); } @@ -104,6 +108,8 @@ fn is_valid_msg_recurring() { &Addr::unchecked("bob"), 5, 5, + 5, + 5 ) .is_ok()); } @@ -138,6 +144,8 @@ fn is_valid_msg_wrong_account() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .unwrap_err() @@ -173,6 +181,8 @@ fn is_valid_msg_vote() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .unwrap_err() @@ -210,6 +220,8 @@ fn is_valid_msg_transfer() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .unwrap_err() @@ -244,6 +256,8 @@ fn is_valid_msg_burn() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .unwrap_err() @@ -278,6 +292,8 @@ fn is_valid_msg_send_doesnt_fail() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .is_ok()); @@ -311,11 +327,40 @@ fn is_valid_msg_send_should_success() { &Addr::unchecked("sender"), &Addr::unchecked("bob"), 5, + 5, + 5, 5 ) .is_ok()); } +#[test] +fn is_valid_empty_actions() { + let task = TaskRequest { + interval: Interval::Block(10), + boundary: None, + stop_on_fail: false, + actions: vec![], + queries: None, + transforms: None, + cw20_coins: Default::default(), + }; + assert_eq!( + task.is_valid_msg_calculate_usage( + &mock_dependencies().api, + &Addr::unchecked("alice2"), + &Addr::unchecked("bob"), + &Addr::unchecked("bob"), + 5, + 5, + 5, + 5, + ) + .unwrap_err(), + CoreError::InvalidAction {} + ); +} + #[test] fn test_add_tokens() { let mut coins: GenericBalance = GenericBalance::default(); @@ -483,6 +528,7 @@ fn hashing() { boundary: BoundaryValidated { start: Some(4), end: None, + is_block_boundary: Some(true), }, stop_on_fail: false, total_deposit: Default::default(), @@ -507,8 +553,8 @@ fn hashing() { }; let message = format!( - "{:?}{:?}{:?}{:?}{:?}", - task.owner_id, task.interval, task.boundary, task.actions, task.queries + "{:?}{:?}{:?}{:?}{:?}{:?}", + task.owner_id, task.interval, task.boundary, task.actions, task.queries, task.transforms ); let hash = Sha256::digest(message.as_bytes()); diff --git a/packages/cw-croncat-core/src/types.rs b/packages/cw-croncat-core/src/types.rs index 25028c0d..ce85dff0 100644 --- a/packages/cw-croncat-core/src/types.rs +++ b/packages/cw-croncat-core/src/types.rs @@ -102,30 +102,38 @@ pub enum Boundary { pub struct BoundaryValidated { pub start: Option, pub end: Option, + pub is_block_boundary: Option, } impl BoundaryValidated { + pub fn is_block_boundary(&self) -> bool { + self.is_block_boundary.is_some() && self.is_block_boundary.unwrap() + } pub fn validate_boundary( boundary: Option, interval: &Interval, ) -> Result { if let Some(boundary) = boundary { match (interval, boundary) { - (Interval::Cron(_), Boundary::Time { start, end }) => match (start, end) { - (Some(s), Some(e)) => { - if s.nanos() >= e.nanos() { - return Err(CoreError::InvalidBoundary {}); + (Interval::Once | Interval::Cron(_), Boundary::Time { start, end }) => { + match (start, end) { + (Some(s), Some(e)) => { + if s.nanos() >= e.nanos() { + return Err(CoreError::InvalidBoundary {}); + } + Ok(Self { + start: Some(s.nanos()), + end: Some(e.nanos()), + is_block_boundary: Some(false), + }) } - Ok(Self { - start: Some(s.nanos()), - end: Some(e.nanos()), - }) + _ => Ok(Self { + start: start.map(|start| start.nanos()), + end: end.map(|end| end.nanos()), + is_block_boundary: Some(false), + }), } - _ => Ok(Self { - start: start.map(|start| start.nanos()), - end: end.map(|end| end.nanos()), - }), - }, + } ( Interval::Once | Interval::Immediate | Interval::Block(_), Boundary::Height { start, end }, @@ -137,11 +145,13 @@ impl BoundaryValidated { Ok(Self { start: Some(s.u64()), end: Some(e.u64()), + is_block_boundary: Some(true), }) } _ => Ok(Self { start: start.map(Into::into), end: end.map(Into::into), + is_block_boundary: Some(true), }), }, _ => Err(CoreError::InvalidBoundary {}), @@ -150,6 +160,7 @@ impl BoundaryValidated { Ok(Self { start: None, end: None, + is_block_boundary: Some(true), //Boundary isnt provided, so default is block }) } } @@ -227,6 +238,8 @@ impl TaskRequest { /// Validate the task actions only use the supported messages /// We're iterating over all actions /// so it's a great place for calculaing balance usages + // Consider moving Config to teh cw-croncat-core so this method can take reference of that + #[allow(clippy::too_many_arguments)] pub fn is_valid_msg_calculate_usage( &self, api: &dyn Api, @@ -235,10 +248,15 @@ impl TaskRequest { owner_id: &Addr, base_gas: u64, action_gas: u64, + query_gas: u64, + wasm_query_gas: u64, ) -> Result<(GenericBalance, u64), CoreError> { let mut gas_amount: u64 = base_gas; let mut amount_for_one_task = GenericBalance::default(); + if self.actions.is_empty() { + return Err(CoreError::InvalidAction {}); + } for action in self.actions.iter() { // checked for cases, where task creator intentionaly tries to overflow gas_amount = gas_amount @@ -324,6 +342,27 @@ impl TaskRequest { _ => (), } } + + if let Some(queries) = self.queries.as_ref() { + // If task has queries - Rules contract is queried which is wasm query + gas_amount = gas_amount + .checked_add(wasm_query_gas) + .ok_or(CoreError::InvalidWasmMsg {})?; + for query in queries.iter() { + match query { + CroncatQuery::HasBalanceGte(_) => { + gas_amount = gas_amount + .checked_add(query_gas) + .ok_or(CoreError::InvalidWasmMsg {})?; + } + _ => { + gas_amount = gas_amount + .checked_add(wasm_query_gas) + .ok_or(CoreError::InvalidWasmMsg {})?; + } + } + } + } Ok((amount_for_one_task, gas_amount)) } } @@ -360,8 +399,13 @@ impl Task { /// Get the hash of a task based on parameters pub fn to_hash(&self) -> String { let message = format!( - "{:?}{:?}{:?}{:?}{:?}", - self.owner_id, self.interval, self.boundary, self.actions, self.queries + "{:?}{:?}{:?}{:?}{:?}{:?}", + self.owner_id, + self.interval, + self.boundary, + self.actions, + self.queries, + self.transforms ); let hash = Sha256::digest(message.as_bytes()); @@ -434,6 +478,8 @@ impl Task { &self, base_gas: u64, action_gas: u64, + query_gas: u64, + wasm_query_gas: u64, next_idx: u64, ) -> Result<(Vec>, u64), CoreError> { let mut gas: u64 = base_gas; @@ -449,6 +495,25 @@ impl Task { sub_msgs.push(sub_msg); } } + + if let Some(queries) = self.queries.as_ref() { + // If task has queries - Rules contract is queried which is wasm query + gas = gas + .checked_add(wasm_query_gas) + .ok_or(CoreError::InvalidGas {})?; + for query in queries.iter() { + match query { + CroncatQuery::HasBalanceGte(_) => { + gas = gas.checked_add(query_gas).ok_or(CoreError::InvalidGas {})?; + } + _ => { + gas = gas + .checked_add(wasm_query_gas) + .ok_or(CoreError::InvalidGas {})?; + } + } + } + } Ok((sub_msgs, gas)) } @@ -584,12 +649,12 @@ impl Task { } } -/// Calculate the amount including agent_fee -pub fn calculate_required_amount(amount: u64, agent_fee: u64) -> Result { - amount +/// Calculate the gas amount including agent_fee +pub fn gas_amount_with_agent_fee(gas_amount: u64, agent_fee: u64) -> Result { + gas_amount .checked_mul(agent_fee) .and_then(|n| n.checked_div(100)) - .and_then(|n| n.checked_add(amount)) + .and_then(|n| n.checked_add(gas_amount)) .ok_or(CoreError::InvalidGas {}) } @@ -838,7 +903,13 @@ impl Intervals for Interval { match self { // If Once, return the first block within a specific range that can be triggered 1 time. // If Immediate, return the first block within a specific range that can be triggered immediately, potentially multiple times. - Interval::Once | Interval::Immediate => get_next_block_limited(env, boundary), + Interval::Once | Interval::Immediate => { + if boundary.is_block_boundary() { + get_next_block_limited(env, boundary) + } else { + get_next_cron_time(env, boundary, "0 0 * * * *", slot_granularity_time) + } + } // return the first block within a specific range that can be triggered 1 or more times based on timestamps. // Uses crontab spec Interval::Cron(crontab) => { @@ -867,26 +938,30 @@ impl Intervals for Interval { } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)] -pub struct GasFraction { +pub struct GasPrice { pub numerator: u64, pub denominator: u64, + /// Note + pub gas_adjustment_numerator: u64, } -impl GasFraction { +impl GasPrice { pub fn is_valid(&self) -> bool { - self.denominator != 0 && self.numerator != 0 + self.denominator != 0 && self.numerator != 0 && self.gas_adjustment_numerator != 0 } - pub fn calculate(&self, extra_num: u64, extra_denom: u64) -> Result { - let numerator = self - .numerator - .checked_mul(extra_num) + pub fn calculate(&self, gas_amount: u64) -> Result { + let gas_adjusted = gas_amount + .checked_mul(self.gas_adjustment_numerator) + .and_then(|g| g.checked_div(self.denominator)) .ok_or(CoreError::InvalidGas {})?; - let denominator = self - .denominator - .checked_mul(extra_denom) + + let price = gas_adjusted + .checked_mul(self.numerator) + .and_then(|g| g.checked_div(self.denominator)) .ok_or(CoreError::InvalidGas {})?; - Ok((numerator / denominator) as u128) + + Ok(price as u128) } } diff --git a/packages/cw-rules-core/Cargo.toml b/packages/cw-rules-core/Cargo.toml index f8ea32d2..c2d3855d 100644 --- a/packages/cw-rules-core/Cargo.toml +++ b/packages/cw-rules-core/Cargo.toml @@ -20,3 +20,4 @@ cw20 = { version = "0.13.4" } [dev-dependencies] cosmwasm-schema = { version = "1.0.0" } +rusty-hook = "0.11.2" diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index c9f3f181..00000000 --- a/scripts/build.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -e - -export RUSTFLAGS='-C link-arg=-s' - -cargo fmt --all -cargo clippy -- -D warnings -cargo build --release --lib --target wasm32-unknown-unknown \ No newline at end of file diff --git a/scripts/local/REF.md b/scripts/local/REF.md index 020171dc..bb4b0259 100644 --- a/scripts/local/REF.md +++ b/scripts/local/REF.md @@ -1,7 +1,7 @@ # Build the contract Building: ```bash -sh build.sh +just build ``` Optimizing the binary size: ```bash diff --git a/scripts/optimized-build-m1.sh b/scripts/optimized-build-m1.sh deleted file mode 100755 index fb754078..00000000 --- a/scripts/optimized-build-m1.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -docker run --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer-arm64:0.12.8 \ No newline at end of file diff --git a/scripts/optimized-build.sh b/scripts/optimized-build.sh deleted file mode 100755 index 563f9cc3..00000000 --- a/scripts/optimized-build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -docker run --rm -v "$(pwd)":/code \ - --mount type=volume,source="$(basename "$(pwd)")_cache",target=/code/target \ - --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \ - cosmwasm/rust-optimizer:0.12.8 \ No newline at end of file diff --git a/scripts/schema.sh b/scripts/schema.sh deleted file mode 100755 index fb36b493..00000000 --- a/scripts/schema.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -set -e - -cargo run --example schema -cargo run --example rules_schema \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh deleted file mode 100755 index 2e54fcce..00000000 --- a/scripts/test.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -set -e - -export RUSTFLAGS='-C link-arg=-s' - -cargo unit-test -cargo wasm \ No newline at end of file diff --git a/scripts/uni-testnet/start.sh b/scripts/uni-testnet/start.sh index 382bb847..729746bf 100755 --- a/scripts/uni-testnet/start.sh +++ b/scripts/uni-testnet/start.sh @@ -10,7 +10,6 @@ echo "CONTRACT-DIR: $SC_PATH" echo "SCRIPT-DIR: $SH_DIR" cd $SC_PATH -$SCRIPTS_PATH/build.sh echo "Initializing vars" . $SH_DIR/base/init-vars.sh diff --git a/scripts/update-checksum.sh b/scripts/update-checksum.sh deleted file mode 100755 index 25391304..00000000 --- a/scripts/update-checksum.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -cat artifacts/checksums.txt | grep -e cw_croncat.wasm -e cw_rules.wasm > checksum diff --git a/typescript/build/contracts/cw-croncat-core/CwCroncatCore.client.js b/typescript/build/contracts/cw-croncat-core/CwCroncatCore.client.js index e7ff693c..461fb230 100644 --- a/typescript/build/contracts/cw-croncat-core/CwCroncatCore.client.js +++ b/typescript/build/contracts/cw-croncat-core/CwCroncatCore.client.js @@ -109,14 +109,6 @@ class CwCroncatCoreQueryClient { } }); }); - this.getState = ({ fromIndex, limit }) => __awaiter(this, void 0, void 0, function* () { - return this.client.queryContractSmart(this.contractAddress, { - get_state: { - from_index: fromIndex, - limit - } - }); - }); this.client = client; this.contractAddress = contractAddress; this.getConfig = this.getConfig.bind(this); @@ -133,21 +125,22 @@ class CwCroncatCoreQueryClient { this.getSlotHashes = this.getSlotHashes.bind(this); this.getSlotIds = this.getSlotIds.bind(this); this.getWalletBalances = this.getWalletBalances.bind(this); - this.getState = this.getState.bind(this); } } exports.CwCroncatCoreQueryClient = CwCroncatCoreQueryClient; class CwCroncatCoreClient extends CwCroncatCoreQueryClient { constructor(client, sender, contractAddress) { super(client, contractAddress); - this.updateSettings = ({ agentFee, agentsEjectThreshold, gasActionFee, gasBaseFee, gasFraction, minTasksPerAgent, ownerId, paused, proxyCallbackGas, slotGranularityTime }, fee = "auto", memo, funds) => __awaiter(this, void 0, void 0, function* () { + this.updateSettings = ({ agentFee, agentsEjectThreshold, gasActionFee, gasBaseFee, gasPrice, gasQueryFee, gasWasmQueryFee, minTasksPerAgent, ownerId, paused, proxyCallbackGas, slotGranularityTime }, fee = "auto", memo, funds) => __awaiter(this, void 0, void 0, function* () { return yield this.client.execute(this.sender, this.contractAddress, { update_settings: { agent_fee: agentFee, agents_eject_threshold: agentsEjectThreshold, gas_action_fee: gasActionFee, gas_base_fee: gasBaseFee, - gas_fraction: gasFraction, + gas_price: gasPrice, + gas_query_fee: gasQueryFee, + gas_wasm_query_fee: gasWasmQueryFee, min_tasks_per_agent: minTasksPerAgent, owner_id: ownerId, paused, diff --git a/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts b/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts index b2fddd13..2956f60d 100644 --- a/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts +++ b/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts @@ -6,7 +6,11 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; +<<<<<<< HEAD import { Addr, Uint128, Timestamp, Uint64, SlotType, AgentStatus, CosmosMsgForEmpty, BankMsg, StakingMsg, DistributionMsg, Binary, IbcMsg, WasmMsg, GovMsg, VoteOption, Boundary, Interval, CroncatQuery, Balance, NativeBalance, Status, ValueOrdering, ValueIndex, PathToValue, SmartQueries, Croncat, Agent, GenericBalance, Cw20CoinVerified, Coin, GetBalancesResponse, GetConfigResponse, GasFraction, GetAgentIdsResponse, AgentResponse, AgentTaskResponse, GetSlotHashesResponse, GetSlotIdsResponse, TaskResponse, ActionForEmpty, Empty, IbcTimeout, IbcTimeoutBlock, HasBalanceGte, CheckOwnerOfNft, CheckProposalStatus, CheckPassedProposals, GenericQuery, SmartQueryHead, SmartQuery, GetWalletBalancesResponse, Task, BoundaryValidated, Transform, TaskRequest, Cw20Coin, ExecuteMsg, Cw20ReceiveMsg, GetAgentResponse, GetAgentTasksResponse, RoundRobinBalancerModeResponse, GetStateResponse, BalancesResponse, SlotResponse, SlotWithQueriesResponse, TaskWithQueriesResponse, GetTaskHashResponse, GetTaskResponse, GetTasksByOwnerResponse, GetTasksResponse, GetTasksWithQueriesResponse, InstantiateMsg, QueryMsg, ValidateIntervalResponse } from "./CwCroncatCore.types"; +======= +import { Addr, Uint128, Timestamp, Uint64, SlotType, AgentStatus, CosmosMsgForEmpty, BankMsg, StakingMsg, DistributionMsg, Binary, IbcMsg, WasmMsg, GovMsg, VoteOption, Boundary, Interval, CroncatQuery, Balance, NativeBalance, Status, ValueOrdering, ValueIndex, PathToValue, SmartQueries, Croncat, Agent, GenericBalance, Cw20CoinVerified, Coin, GetBalancesResponse, GetConfigResponse, GasPrice, GetAgentIdsResponse, AgentResponse, AgentTaskResponse, GetSlotHashesResponse, GetSlotIdsResponse, TaskResponse, ActionForEmpty, Empty, IbcTimeout, IbcTimeoutBlock, HasBalanceGte, CheckOwnerOfNft, CheckProposalStatus, GenericQuery, SmartQueryHead, SmartQuery, GetWalletBalancesResponse, Task, BoundaryValidated, Transform, TaskRequest, Cw20Coin, ExecuteMsg, Cw20ReceiveMsg, GetAgentResponse, GetAgentTasksResponse, GetTaskHashResponse, GetTaskResponse, GetTasksByOwnerResponse, GetTasksResponse, GetTasksWithQueriesResponse, TaskWithQueriesResponse, InstantiateMsg, QueryMsg, ValidateIntervalResponse } from "./CwCroncatCore.types"; +>>>>>>> main export interface CwCroncatCoreReadOnlyInterface { contractAddress: string; getConfig: () => Promise; @@ -67,13 +71,6 @@ export interface CwCroncatCoreReadOnlyInterface { }: { wallet: string; }) => Promise; - getState: ({ - fromIndex, - limit - }: { - fromIndex?: number; - limit?: number; - }) => Promise; } export class CwCroncatCoreQueryClient implements CwCroncatCoreReadOnlyInterface { client: CosmWasmClient; @@ -96,7 +93,6 @@ export class CwCroncatCoreQueryClient implements CwCroncatCoreReadOnlyInterface this.getSlotHashes = this.getSlotHashes.bind(this); this.getSlotIds = this.getSlotIds.bind(this); this.getWalletBalances = this.getWalletBalances.bind(this); - this.getState = this.getState.bind(this); } getConfig = async (): Promise => { @@ -235,20 +231,6 @@ export class CwCroncatCoreQueryClient implements CwCroncatCoreReadOnlyInterface } }); }; - getState = async ({ - fromIndex, - limit - }: { - fromIndex?: number; - limit?: number; - }): Promise => { - return this.client.queryContractSmart(this.contractAddress, { - get_state: { - from_index: fromIndex, - limit - } - }); - }; } export interface CwCroncatCoreInterface extends CwCroncatCoreReadOnlyInterface { contractAddress: string; @@ -258,7 +240,9 @@ export interface CwCroncatCoreInterface extends CwCroncatCoreReadOnlyInterface { agentsEjectThreshold, gasActionFee, gasBaseFee, - gasFraction, + gasPrice, + gasQueryFee, + gasWasmQueryFee, minTasksPerAgent, ownerId, paused, @@ -269,7 +253,9 @@ export interface CwCroncatCoreInterface extends CwCroncatCoreReadOnlyInterface { agentsEjectThreshold?: number; gasActionFee?: Uint64; gasBaseFee?: Uint64; - gasFraction?: GasFraction; + gasPrice?: GasPrice; + gasQueryFee?: Uint64; + gasWasmQueryFee?: Uint64; minTasksPerAgent?: number; ownerId?: string; paused?: boolean; @@ -375,7 +361,9 @@ export class CwCroncatCoreClient extends CwCroncatCoreQueryClient implements CwC agentsEjectThreshold, gasActionFee, gasBaseFee, - gasFraction, + gasPrice, + gasQueryFee, + gasWasmQueryFee, minTasksPerAgent, ownerId, paused, @@ -386,7 +374,9 @@ export class CwCroncatCoreClient extends CwCroncatCoreQueryClient implements CwC agentsEjectThreshold?: number; gasActionFee?: Uint64; gasBaseFee?: Uint64; - gasFraction?: GasFraction; + gasPrice?: GasPrice; + gasQueryFee?: Uint64; + gasWasmQueryFee?: Uint64; minTasksPerAgent?: number; ownerId?: string; paused?: boolean; @@ -399,7 +389,9 @@ export class CwCroncatCoreClient extends CwCroncatCoreQueryClient implements CwC agents_eject_threshold: agentsEjectThreshold, gas_action_fee: gasActionFee, gas_base_fee: gasBaseFee, - gas_fraction: gasFraction, + gas_price: gasPrice, + gas_query_fee: gasQueryFee, + gas_wasm_query_fee: gasWasmQueryFee, min_tasks_per_agent: minTasksPerAgent, owner_id: ownerId, paused, diff --git a/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts b/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts index a62c34cd..dd7dc709 100644 --- a/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts +++ b/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts @@ -251,7 +251,7 @@ export interface GetConfigResponse { cw_rules_addr: Addr; gas_action_fee: number; gas_base_fee: number; - gas_fraction: GasFraction; + gas_price: GasPrice; limit: number; min_tasks_per_agent: number; native_denom: string; @@ -262,8 +262,9 @@ export interface GetConfigResponse { staked_balance: GenericBalance; [k: string]: unknown; } -export interface GasFraction { +export interface GasPrice { denominator: number; + gas_adjustment_numerator: number; numerator: number; [k: string]: unknown; } @@ -396,6 +397,7 @@ export interface Task { } export interface BoundaryValidated { end?: number | null; + is_block_boundary?: boolean | null; start?: number | null; [k: string]: unknown; } @@ -427,7 +429,9 @@ export type ExecuteMsg = { agents_eject_threshold?: number | null; gas_action_fee?: Uint64 | null; gas_base_fee?: Uint64 | null; - gas_fraction?: GasFraction | null; + gas_price?: GasPrice | null; + gas_query_fee?: Uint64 | null; + gas_wasm_query_fee?: Uint64 | null; min_tasks_per_agent?: number | null; owner_id?: string | null; paused?: boolean | null; @@ -510,41 +514,11 @@ export interface Cw20ReceiveMsg { } export type GetAgentResponse = AgentResponse | null; export type GetAgentTasksResponse = TaskResponse | null; -export type RoundRobinBalancerModeResponse = "ActivationOrder" | "Equalizer"; -export interface GetStateResponse { - agent_active_queue: Addr[]; - agent_nomination_begin_time?: Timestamp | null; - agent_pending_queue: Addr[]; - agents: AgentResponse[]; - balancer_mode: RoundRobinBalancerModeResponse; - balances: BalancesResponse[]; - block_slots: SlotResponse[]; - block_slots_queries: SlotWithQueriesResponse[]; - config: GetConfigResponse; - reply_index: Uint64; - task_total: Uint64; - tasks: TaskResponse[]; - tasks_with_queries: TaskWithQueriesResponse[]; - tasks_with_queries_total: Uint64; - time_slots: SlotResponse[]; - time_slots_queries: SlotWithQueriesResponse[]; - [k: string]: unknown; -} -export interface BalancesResponse { - address: Addr; - balances: Cw20CoinVerified[]; - [k: string]: unknown; -} -export interface SlotResponse { - slot: Uint64; - tasks: number[][]; - [k: string]: unknown; -} -export interface SlotWithQueriesResponse { - slot: Uint64; - task_hash: number[]; - [k: string]: unknown; -} +export type GetTaskHashResponse = string; +export type GetTaskResponse = TaskResponse | null; +export type GetTasksByOwnerResponse = TaskResponse[]; +export type GetTasksResponse = TaskResponse[]; +export type GetTasksWithQueriesResponse = TaskWithQueriesResponse[]; export interface TaskWithQueriesResponse { boundary?: Boundary | null; interval: Interval; @@ -552,18 +526,15 @@ export interface TaskWithQueriesResponse { task_hash: string; [k: string]: unknown; } -export type GetTaskHashResponse = string; -export type GetTaskResponse = TaskResponse | null; -export type GetTasksByOwnerResponse = TaskResponse[]; -export type GetTasksResponse = TaskResponse[]; -export type GetTasksWithQueriesResponse = TaskWithQueriesResponse[]; export interface InstantiateMsg { agent_nomination_duration?: number | null; cw_rules_addr: string; denom: string; gas_action_fee?: Uint64 | null; gas_base_fee?: Uint64 | null; - gas_fraction?: GasFraction | null; + gas_price?: GasPrice | null; + gas_query_fee?: Uint64 | null; + gas_wasm_query_fee?: Uint64 | null; owner_id?: string | null; [k: string]: unknown; } @@ -635,11 +606,5 @@ export type QueryMsg = { wallet: string; [k: string]: unknown; }; -} | { - get_state: { - from_index?: number | null; - limit?: number | null; - [k: string]: unknown; - }; }; export type ValidateIntervalResponse = boolean; \ No newline at end of file