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..873e6b32 100644 --- a/checksum +++ b/checksum @@ -1,2 +1,2 @@ -e841b8f67c8209ade26674edd432bb1d7dc9dcaa470651ebf379c62d41c294c8 cw_croncat.wasm -de2d1a0c648e41760020dd261f818da085c358240059acf85128f60eb0e05db2 cw_rules.wasm +f02ba448d956da4cc508cafdf14dd010e3ac0d37f5d40fa3116d27093d3a6ce1 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 1e6d91df..3d963207 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; @@ -228,10 +228,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 fef6ff55..5c5d28a5 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 as usize) - .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 as usize) - .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 as usize) - .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 as usize) - .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 as usize) - .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..2b6dc969 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))?; diff --git a/contracts/cw-croncat/src/tests/agent.rs b/contracts/cw-croncat/src/tests/agent.rs index ced94dd8..bd20a7b4 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, + "e078693103645f865278562ddb4301ec1f684c7ec4a0bd43907175b00ee8f562", 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..17f5f126 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 diff --git a/contracts/cw-croncat/src/tests/manager.rs b/contracts/cw-croncat/src/tests/manager.rs index 0a669587..faae7d3f 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, @@ -51,7 +56,7 @@ fn proxy_call_fail_cases() -> StdResult<()> { }, }; let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); + "a78a89f0bbcba7d36c50d2b0ea8f3d3f6677b4b4ca76bd650eaf5836bed65b1c".to_string(); // Must attach funds let res_err = app @@ -98,11 +103,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 +171,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![], ) @@ -249,7 +258,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(); + "62c7a2dd020ace2169b3d61ac32a5e5fd98050d73584f121d424a9ebbf32e7a0".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -430,8 +439,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 +517,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(); + "dc8759f300ac55b4d4f0e7fa0fc6727392f55e9f4d132745692eae1da7108cfc".to_string(); // Doing this msg since its the easiest to guarantee success in reply let validator = String::from("you"); @@ -598,7 +609,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; @@ -697,7 +708,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 +746,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(); + "62c7a2dd020ace2169b3d61ac32a5e5fd98050d73584f121d424a9ebbf32e7a0".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -864,7 +875,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(); + "5a9fd1f1506e26cc78816f031ad251729fb2d6979f54639116611cd3d9df9191".to_string(); // Doing this msg since its the easiest to guarantee success in reply let msg = CosmosMsg::Wasm(WasmMsg::Execute { @@ -1292,7 +1303,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 +1375,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,10 +1514,14 @@ 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( @@ -1542,14 +1562,19 @@ fn test_no_reschedule_if_lack_balance() { .query_wasm_smart( contract_addr.clone(), &QueryMsg::GetTask { - task_hash: "65237042c224447b7d6d7cdfd6515af3e76cb3270ce6d5ed989a6babc12f1026" + task_hash: "8fad55a869f129ba363786bd7f0ec698f1a59e2553ba7fdec408f1cd82326cd3" .to_string(), }, ) .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 +1599,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 +1624,7 @@ 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 task_hash = "c2772d2268fa9809f70bb36c15cb33c1f7c6ff458ca2f2a4707b8ae677d53c72"; let addr1 = String::from("addr1"); let amount = coins(3, NATIVE_DENOM); @@ -1709,7 +1734,7 @@ 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 task_hash = "672deeb057ad86ca6c16b7abee1b912b6f737b7eedd4f3fe319d5bd54dc1dbd6"; let addr1 = String::from("addr1"); let amount = coins(3, NATIVE_DENOM); @@ -1735,7 +1760,7 @@ fn test_reschedule_task_with_queries() { }, }; - let attached_balance = 100338 * 4; + let attached_balance = 31188 * 8; app.execute_contract( Addr::unchecked(ADMIN), contract_addr.clone(), @@ -1743,7 +1768,16 @@ fn test_reschedule_task_with_queries() { &coins(attached_balance, NATIVE_DENOM), ) .unwrap(); - + let task: TaskResponse = app + .wrap() + .query_wasm_smart( + contract_addr.clone(), + &QueryMsg::GetTask { + task_hash: task_hash.to_string(), + }, + ) + .unwrap(); + println!("task: {:?}", task); // quick agent register let msg = ExecuteMsg::RegisterAgent { payable_account_id: Some(AGENT_BENEFICIARY.to_string()), @@ -1856,10 +1890,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 +2087,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 +2276,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; @@ -3026,3 +3065,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/state.rs b/contracts/cw-croncat/src/tests/state.rs index 38eeb3a7..21f487f3 100644 --- a/contracts/cw-croncat/src/tests/state.rs +++ b/contracts/cw-croncat/src/tests/state.rs @@ -37,7 +37,7 @@ fn check_task_storage_structure() -> StdResult<()> { transforms: None, version: version.version, }; - let task_id_str = "69217dd2b6334abe2544a12fcb89588f9cc5c62a298b8720706d9befa3d736d3"; + let task_id_str = "85a5729f478d96fbb12eec7886992a53635d22bba4d8d8ef2fde16dc7f1f1605"; 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..a610d6ea 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::{ @@ -63,7 +66,7 @@ fn query_task_hash_success() { ) .unwrap(); assert_eq!( - "69217dd2b6334abe2544a12fcb89588f9cc5c62a298b8720706d9befa3d736d3", + "85a5729f478d96fbb12eec7886992a53635d22bba4d8d8ef2fde16dc7f1f1605", task_hash ); } @@ -356,12 +359,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 +399,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![], ) @@ -579,7 +586,7 @@ fn check_task_create_success() -> StdResult<()> { }, }; let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); + "a78a89f0bbcba7d36c50d2b0ea8f3d3f6677b4b4ca76bd650eaf5836bed65b1c".to_string(); // create a task let res = app @@ -852,7 +859,7 @@ fn check_remove_create() -> StdResult<()> { }, }; let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); + "a78a89f0bbcba7d36c50d2b0ea8f3d3f6677b4b4ca76bd650eaf5836bed65b1c".to_string(); // create a task app.execute_contract( @@ -962,7 +969,7 @@ fn check_refill_create() -> StdResult<()> { }, }; let task_id_str = - "95c916a53fa9d26deef094f7e1ee31c00a2d47b8bf474b2e06d39aebfb1fecc7".to_string(); + "a78a89f0bbcba7d36c50d2b0ea8f3d3f6677b4b4ca76bd650eaf5836bed65b1c".to_string(); // create a task app.execute_contract( @@ -1034,7 +1041,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 +1059,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 +1102,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 +1128,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 65741b34..6af25e8b 100644 --- a/justfile +++ b/justfile @@ -1,7 +1,6 @@ test_addrs := env_var_or_default('TEST_ADDR', `jq -r '.[].address' ci/test_accounts.json | tr '\n' ' '`) set export lint: - #!/bin/bash cargo fmt --all && cargo clippy -- -D warnings test: #!/bin/bash @@ -25,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 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 94a331c6..da1ff1e4 100644 --- a/packages/cw-croncat-core/schema/croncat.json +++ b/packages/cw-croncat-core/schema/croncat.json @@ -826,10 +826,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": { @@ -838,6 +839,12 @@ "format": "uint64", "minimum": 0.0 }, + "gas_adjustment_numerator": { + "description": "Note", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, "numerator": { "type": "integer", "format": "uint64", @@ -952,7 +959,7 @@ "cw_rules_addr", "gas_action_fee", "gas_base_fee", - "gas_fraction", + "gas_price", "limit", "min_tasks_per_agent", "native_denom", @@ -1023,8 +1030,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 4f5d11f4..a582f8c3 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" @@ -915,10 +935,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": { @@ -927,6 +948,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/get_state_response.json b/packages/cw-croncat-core/schema/get_state_response.json deleted file mode 100644 index f72806ec..00000000 --- a/packages/cw-croncat-core/schema/get_state_response.json +++ /dev/null @@ -1,1749 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "GetStateResponse", - "type": "object", - "required": [ - "agent_active_queue", - "agent_pending_queue", - "agents", - "balancer_mode", - "balances", - "block_slots", - "block_slots_queries", - "config", - "reply_index", - "task_total", - "tasks", - "tasks_with_queries", - "tasks_with_queries_total", - "time_slots", - "time_slots_queries" - ], - "properties": { - "agent_active_queue": { - "type": "array", - "items": { - "$ref": "#/definitions/Addr" - } - }, - "agent_nomination_begin_time": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - }, - "agent_pending_queue": { - "type": "array", - "items": { - "$ref": "#/definitions/Addr" - } - }, - "agents": { - "type": "array", - "items": { - "$ref": "#/definitions/AgentResponse" - } - }, - "balancer_mode": { - "$ref": "#/definitions/RoundRobinBalancerModeResponse" - }, - "balances": { - "type": "array", - "items": { - "$ref": "#/definitions/BalancesResponse" - } - }, - "block_slots": { - "type": "array", - "items": { - "$ref": "#/definitions/SlotResponse" - } - }, - "block_slots_queries": { - "type": "array", - "items": { - "$ref": "#/definitions/SlotWithQueriesResponse" - } - }, - "config": { - "$ref": "#/definitions/GetConfigResponse" - }, - "reply_index": { - "$ref": "#/definitions/Uint64" - }, - "task_total": { - "$ref": "#/definitions/Uint64" - }, - "tasks": { - "type": "array", - "items": { - "$ref": "#/definitions/TaskResponse" - } - }, - "tasks_with_queries": { - "type": "array", - "items": { - "$ref": "#/definitions/TaskWithQueriesResponse" - } - }, - "tasks_with_queries_total": { - "$ref": "#/definitions/Uint64" - }, - "time_slots": { - "type": "array", - "items": { - "$ref": "#/definitions/SlotResponse" - } - }, - "time_slots_queries": { - "type": "array", - "items": { - "$ref": "#/definitions/SlotWithQueriesResponse" - } - } - }, - "definitions": { - "Action_for_Empty": { - "type": "object", - "required": [ - "msg" - ], - "properties": { - "gas_limit": { - "description": "The gas needed to safely process the execute msg", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 0.0 - }, - "msg": { - "description": "Supported CosmosMsgs only!", - "allOf": [ - { - "$ref": "#/definitions/CosmosMsg_for_Empty" - } - ] - } - } - }, - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - }, - "AgentResponse": { - "type": "object", - "required": [ - "balance", - "last_executed_slot", - "payable_account_id", - "register_start", - "status", - "total_tasks_executed" - ], - "properties": { - "balance": { - "$ref": "#/definitions/GenericBalance" - }, - "last_executed_slot": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "payable_account_id": { - "$ref": "#/definitions/Addr" - }, - "register_start": { - "$ref": "#/definitions/Timestamp" - }, - "status": { - "$ref": "#/definitions/AgentStatus" - }, - "total_tasks_executed": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "AgentStatus": { - "type": "string", - "enum": [ - "Active", - "Pending", - "Nominated" - ] - }, - "Balance": { - "oneOf": [ - { - "type": "object", - "required": [ - "native" - ], - "properties": { - "native": { - "$ref": "#/definitions/NativeBalance" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "cw20" - ], - "properties": { - "cw20": { - "$ref": "#/definitions/Cw20CoinVerified" - } - }, - "additionalProperties": false - } - ] - }, - "BalancesResponse": { - "type": "object", - "required": [ - "address", - "balances" - ], - "properties": { - "address": { - "$ref": "#/definitions/Addr" - }, - "balances": { - "type": "array", - "items": { - "$ref": "#/definitions/Cw20CoinVerified" - } - } - } - }, - "BankMsg": { - "description": "The message types of the bank module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto", - "oneOf": [ - { - "description": "Sends native tokens from the contract to the given address.\n\nThis is translated to a [MsgSend](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/bank/v1beta1/tx.proto#L19-L28). `from_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "send" - ], - "properties": { - "send": { - "type": "object", - "required": [ - "amount", - "to_address" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "to_address": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will burn the given coins from the contract's account. There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. Important if a contract controls significant token supply that must be retired.", - "type": "object", - "required": [ - "burn" - ], - "properties": { - "burn": { - "type": "object", - "required": [ - "amount" - ], - "properties": { - "amount": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Binary": { - "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", - "type": "string" - }, - "Boundary": { - "oneOf": [ - { - "type": "object", - "required": [ - "Height" - ], - "properties": { - "Height": { - "type": "object", - "properties": { - "end": { - "anyOf": [ - { - "$ref": "#/definitions/Uint64" - }, - { - "type": "null" - } - ] - }, - "start": { - "anyOf": [ - { - "$ref": "#/definitions/Uint64" - }, - { - "type": "null" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "Time" - ], - "properties": { - "Time": { - "type": "object", - "properties": { - "end": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - }, - "start": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - } - }, - "additionalProperties": false - } - ] - }, - "CheckOwnerOfNft": { - "type": "object", - "required": [ - "address", - "nft_address", - "token_id" - ], - "properties": { - "address": { - "type": "string" - }, - "nft_address": { - "type": "string" - }, - "token_id": { - "type": "string" - } - } - }, - "CheckProposalStatus": { - "type": "object", - "required": [ - "dao_address", - "proposal_id", - "status" - ], - "properties": { - "dao_address": { - "type": "string" - }, - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "status": { - "$ref": "#/definitions/Status" - } - } - }, - "Coin": { - "type": "object", - "required": [ - "amount", - "denom" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "denom": { - "type": "string" - } - } - }, - "CosmosMsg_for_Empty": { - "oneOf": [ - { - "type": "object", - "required": [ - "bank" - ], - "properties": { - "bank": { - "$ref": "#/definitions/BankMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "custom" - ], - "properties": { - "custom": { - "$ref": "#/definitions/Empty" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "staking" - ], - "properties": { - "staking": { - "$ref": "#/definitions/StakingMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "distribution" - ], - "properties": { - "distribution": { - "$ref": "#/definitions/DistributionMsg" - } - }, - "additionalProperties": false - }, - { - "description": "A Stargate message encoded the same way as a protobuf [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). This is the same structure as messages in `TxBody` from [ADR-020](https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-020-protobuf-transaction-encoding.md)", - "type": "object", - "required": [ - "stargate" - ], - "properties": { - "stargate": { - "type": "object", - "required": [ - "type_url", - "value" - ], - "properties": { - "type_url": { - "type": "string" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "ibc" - ], - "properties": { - "ibc": { - "$ref": "#/definitions/IbcMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "wasm" - ], - "properties": { - "wasm": { - "$ref": "#/definitions/WasmMsg" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "gov" - ], - "properties": { - "gov": { - "$ref": "#/definitions/GovMsg" - } - }, - "additionalProperties": false - } - ] - }, - "CroncatQuery": { - "oneOf": [ - { - "type": "object", - "required": [ - "query" - ], - "properties": { - "query": { - "type": "object", - "required": [ - "contract_addr", - "msg" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - } - } - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "has_balance_gte" - ], - "properties": { - "has_balance_gte": { - "$ref": "#/definitions/HasBalanceGte" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "check_owner_of_nft" - ], - "properties": { - "check_owner_of_nft": { - "$ref": "#/definitions/CheckOwnerOfNft" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "check_proposal_status" - ], - "properties": { - "check_proposal_status": { - "$ref": "#/definitions/CheckProposalStatus" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "generic_query" - ], - "properties": { - "generic_query": { - "$ref": "#/definitions/GenericQuery" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "smart_query" - ], - "properties": { - "smart_query": { - "$ref": "#/definitions/SmartQueryHead" - } - }, - "additionalProperties": false - } - ] - }, - "Cw20CoinVerified": { - "type": "object", - "required": [ - "address", - "amount" - ], - "properties": { - "address": { - "$ref": "#/definitions/Addr" - }, - "amount": { - "$ref": "#/definitions/Uint128" - } - } - }, - "DistributionMsg": { - "description": "The message types of the distribution module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "set_withdraw_address" - ], - "properties": { - "set_withdraw_address": { - "type": "object", - "required": [ - "address" - ], - "properties": { - "address": { - "description": "The `withdraw_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [[MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "withdraw_delegator_reward" - ], - "properties": { - "withdraw_delegator_reward": { - "type": "object", - "required": [ - "validator" - ], - "properties": { - "validator": { - "description": "The `validator_address`", - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Empty": { - "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": { - "type": "object", - "required": [ - "denominator", - "numerator" - ], - "properties": { - "denominator": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "numerator": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "GenericBalance": { - "type": "object", - "required": [ - "cw20", - "native" - ], - "properties": { - "cw20": { - "type": "array", - "items": { - "$ref": "#/definitions/Cw20CoinVerified" - } - }, - "native": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - } - } - }, - "GenericQuery": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "ordering", - "path_to_value", - "value" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "ordering": { - "$ref": "#/definitions/ValueOrdering" - }, - "path_to_value": { - "$ref": "#/definitions/PathToValue" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - }, - "GetConfigResponse": { - "type": "object", - "required": [ - "agent_active_indices", - "agent_fee", - "agent_nomination_duration", - "agents_eject_threshold", - "available_balance", - "cw20_whitelist", - "cw_rules_addr", - "gas_action_fee", - "gas_base_fee", - "gas_fraction", - "limit", - "min_tasks_per_agent", - "native_denom", - "owner_id", - "paused", - "proxy_callback_gas", - "slot_granularity_time", - "staked_balance" - ], - "properties": { - "agent_active_indices": { - "type": "array", - "items": { - "type": "array", - "items": [ - { - "$ref": "#/definitions/SlotType" - }, - { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - } - ], - "maxItems": 3, - "minItems": 3 - } - }, - "agent_fee": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "agent_nomination_duration": { - "type": "integer", - "format": "uint16", - "minimum": 0.0 - }, - "agents_eject_threshold": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "available_balance": { - "$ref": "#/definitions/GenericBalance" - }, - "cw20_whitelist": { - "type": "array", - "items": { - "$ref": "#/definitions/Addr" - } - }, - "cw_rules_addr": { - "$ref": "#/definitions/Addr" - }, - "gas_action_fee": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "gas_base_fee": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "gas_fraction": { - "$ref": "#/definitions/GasFraction" - }, - "limit": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "min_tasks_per_agent": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "native_denom": { - "type": "string" - }, - "owner_id": { - "$ref": "#/definitions/Addr" - }, - "paused": { - "type": "boolean" - }, - "proxy_callback_gas": { - "type": "integer", - "format": "uint32", - "minimum": 0.0 - }, - "slot_granularity_time": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "staked_balance": { - "$ref": "#/definitions/GenericBalance" - } - } - }, - "GovMsg": { - "oneOf": [ - { - "description": "This maps directly to [MsgVote](https://github.com/cosmos/cosmos-sdk/blob/v0.42.5/proto/cosmos/gov/v1beta1/tx.proto#L46-L56) in the Cosmos SDK with voter set to the contract address.", - "type": "object", - "required": [ - "vote" - ], - "properties": { - "vote": { - "type": "object", - "required": [ - "proposal_id", - "vote" - ], - "properties": { - "proposal_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "vote": { - "$ref": "#/definitions/VoteOption" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "HasBalanceGte": { - "type": "object", - "required": [ - "address", - "required_balance" - ], - "properties": { - "address": { - "type": "string" - }, - "required_balance": { - "$ref": "#/definitions/Balance" - } - } - }, - "IbcMsg": { - "description": "These are messages in the IBC lifecycle. Only usable by IBC-enabled contracts (contracts that directly speak the IBC protocol via 6 entry points)", - "oneOf": [ - { - "description": "Sends bank tokens owned by the contract to the given address on another chain. The channel must already be established between the ibctransfer module on this chain and a matching module on the remote chain. We cannot select the port_id, this is whatever the local chain has bound the ibctransfer module to.", - "type": "object", - "required": [ - "transfer" - ], - "properties": { - "transfer": { - "type": "object", - "required": [ - "amount", - "channel_id", - "timeout", - "to_address" - ], - "properties": { - "amount": { - "description": "packet data only supports one coin https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/ibc/applications/transfer/v1/transfer.proto#L11-L20", - "allOf": [ - { - "$ref": "#/definitions/Coin" - } - ] - }, - "channel_id": { - "description": "exisiting channel to send the tokens over", - "type": "string" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - }, - "to_address": { - "description": "address on the remote chain to receive these tokens", - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sends an IBC packet with given data over the existing channel. Data should be encoded in a format defined by the channel version, and the module on the other side should know how to parse this.", - "type": "object", - "required": [ - "send_packet" - ], - "properties": { - "send_packet": { - "type": "object", - "required": [ - "channel_id", - "data", - "timeout" - ], - "properties": { - "channel_id": { - "type": "string" - }, - "data": { - "$ref": "#/definitions/Binary" - }, - "timeout": { - "description": "when packet times out, measured on remote chain", - "allOf": [ - { - "$ref": "#/definitions/IbcTimeout" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This will close an existing channel that is owned by this contract. Port is auto-assigned to the contract's IBC port", - "type": "object", - "required": [ - "close_channel" - ], - "properties": { - "close_channel": { - "type": "object", - "required": [ - "channel_id" - ], - "properties": { - "channel_id": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "IbcTimeout": { - "description": "In IBC each package must set at least one type of timeout: the timestamp or the block height. Using this rather complex enum instead of two timeout fields we ensure that at least one timeout is set.", - "type": "object", - "properties": { - "block": { - "anyOf": [ - { - "$ref": "#/definitions/IbcTimeoutBlock" - }, - { - "type": "null" - } - ] - }, - "timestamp": { - "anyOf": [ - { - "$ref": "#/definitions/Timestamp" - }, - { - "type": "null" - } - ] - } - } - }, - "IbcTimeoutBlock": { - "description": "IBCTimeoutHeight Height is a monotonically increasing data type that can be compared against another Height for the purposes of updating and freezing clients. Ordering is (revision_number, timeout_height)", - "type": "object", - "required": [ - "height", - "revision" - ], - "properties": { - "height": { - "description": "block height after which the packet times out. the height within the given revision", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "revision": { - "description": "the version that the client is currently on (eg. after reseting the chain this could increment 1 as height drops to 0)", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - }, - "Interval": { - "description": "Defines the spacing of execution NOTES: - Block Height Based: Once, Immediate, Block - Timestamp Based: Cron - No Epoch support directly, advised to use block heights instead", - "oneOf": [ - { - "description": "For when this is a non-recurring future scheduled TXN", - "type": "string", - "enum": [ - "Once" - ] - }, - { - "description": "The ugly batch schedule type, in case you need to exceed single TXN gas limits, within fewest block(s)", - "type": "string", - "enum": [ - "Immediate" - ] - }, - { - "description": "Allows timing based on block intervals rather than timestamps", - "type": "object", - "required": [ - "Block" - ], - "properties": { - "Block": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - }, - { - "description": "Crontab Spec String", - "type": "object", - "required": [ - "Cron" - ], - "properties": { - "Cron": { - "type": "string" - } - }, - "additionalProperties": false - } - ] - }, - "NativeBalance": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "PathToValue": { - "type": "array", - "items": { - "$ref": "#/definitions/ValueIndex" - } - }, - "RoundRobinBalancerModeResponse": { - "type": "string", - "enum": [ - "ActivationOrder", - "Equalizer" - ] - }, - "SlotResponse": { - "type": "object", - "required": [ - "slot", - "tasks" - ], - "properties": { - "slot": { - "$ref": "#/definitions/Uint64" - }, - "tasks": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - } - } - } - }, - "SlotType": { - "type": "string", - "enum": [ - "Block", - "Cron" - ] - }, - "SlotWithQueriesResponse": { - "type": "object", - "required": [ - "slot", - "task_hash" - ], - "properties": { - "slot": { - "$ref": "#/definitions/Uint64" - }, - "task_hash": { - "type": "array", - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0.0 - } - } - } - }, - "SmartQueries": { - "type": "array", - "items": { - "$ref": "#/definitions/SmartQuery" - } - }, - "SmartQuery": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "path_to_msg_value", - "path_to_query_value" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "$ref": "#/definitions/Binary" - }, - "path_to_msg_value": { - "description": "Replace value inside this query", - "allOf": [ - { - "$ref": "#/definitions/PathToValue" - } - ] - }, - "path_to_query_value": { - "description": "Value passed to the next iteration", - "allOf": [ - { - "$ref": "#/definitions/PathToValue" - } - ] - } - } - }, - "SmartQueryHead": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "ordering", - "path_to_query_value", - "queries", - "value" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "description": "First query without placeholder!", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "ordering": { - "$ref": "#/definitions/ValueOrdering" - }, - "path_to_query_value": { - "description": "Value from this message", - "allOf": [ - { - "$ref": "#/definitions/PathToValue" - } - ] - }, - "queries": { - "$ref": "#/definitions/SmartQueries" - }, - "value": { - "$ref": "#/definitions/Binary" - } - } - }, - "StakingMsg": { - "description": "The message types of the staking module.\n\nSee https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto", - "oneOf": [ - { - "description": "This is translated to a [MsgDelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L81-L90). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "delegate" - ], - "properties": { - "delegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgUndelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L112-L121). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "undelegate" - ], - "properties": { - "undelegate": { - "type": "object", - "required": [ - "amount", - "validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "This is translated to a [MsgBeginRedelegate](https://github.com/cosmos/cosmos-sdk/blob/v0.40.0/proto/cosmos/staking/v1beta1/tx.proto#L95-L105). `delegator_address` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "redelegate" - ], - "properties": { - "redelegate": { - "type": "object", - "required": [ - "amount", - "dst_validator", - "src_validator" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Coin" - }, - "dst_validator": { - "type": "string" - }, - "src_validator": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - }, - "Status": { - "oneOf": [ - { - "type": "string", - "enum": [ - "execution_failed" - ] - }, - { - "description": "The proposal is open for voting.", - "type": "string", - "enum": [ - "open" - ] - }, - { - "description": "The proposal has been rejected.", - "type": "string", - "enum": [ - "rejected" - ] - }, - { - "description": "The proposal has been passed but has not been executed.", - "type": "string", - "enum": [ - "passed" - ] - }, - { - "description": "The proposal has been passed and executed.", - "type": "string", - "enum": [ - "executed" - ] - }, - { - "description": "The proposal has failed or expired and has been closed. A proposal deposit refund has been issued if applicable.", - "type": "string", - "enum": [ - "closed" - ] - } - ] - }, - "TaskResponse": { - "type": "object", - "required": [ - "actions", - "amount_for_one_task_cw20", - "amount_for_one_task_native", - "interval", - "owner_id", - "stop_on_fail", - "task_hash", - "total_cw20_deposit", - "total_deposit" - ], - "properties": { - "actions": { - "type": "array", - "items": { - "$ref": "#/definitions/Action_for_Empty" - } - }, - "amount_for_one_task_cw20": { - "type": "array", - "items": { - "$ref": "#/definitions/Cw20CoinVerified" - } - }, - "amount_for_one_task_native": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "boundary": { - "anyOf": [ - { - "$ref": "#/definitions/Boundary" - }, - { - "type": "null" - } - ] - }, - "interval": { - "$ref": "#/definitions/Interval" - }, - "owner_id": { - "$ref": "#/definitions/Addr" - }, - "queries": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/CroncatQuery" - } - }, - "stop_on_fail": { - "type": "boolean" - }, - "task_hash": { - "type": "string" - }, - "total_cw20_deposit": { - "type": "array", - "items": { - "$ref": "#/definitions/Cw20CoinVerified" - } - }, - "total_deposit": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - } - } - }, - "TaskWithQueriesResponse": { - "type": "object", - "required": [ - "interval", - "task_hash" - ], - "properties": { - "boundary": { - "anyOf": [ - { - "$ref": "#/definitions/Boundary" - }, - { - "type": "null" - } - ] - }, - "interval": { - "$ref": "#/definitions/Interval" - }, - "queries": { - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/CroncatQuery" - } - }, - "task_hash": { - "type": "string" - } - } - }, - "Timestamp": { - "description": "A point in time in nanosecond precision.\n\nThis type can represent times from 1970-01-01T00:00:00Z to 2554-07-21T23:34:33Z.\n\n## Examples\n\n``` # use cosmwasm_std::Timestamp; let ts = Timestamp::from_nanos(1_000_000_202); assert_eq!(ts.nanos(), 1_000_000_202); assert_eq!(ts.seconds(), 1); assert_eq!(ts.subsec_nanos(), 202);\n\nlet ts = ts.plus_seconds(2); assert_eq!(ts.nanos(), 3_000_000_202); assert_eq!(ts.seconds(), 3); assert_eq!(ts.subsec_nanos(), 202); ```", - "allOf": [ - { - "$ref": "#/definitions/Uint64" - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - }, - "Uint64": { - "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", - "type": "string" - }, - "ValueIndex": { - "oneOf": [ - { - "type": "object", - "required": [ - "key" - ], - "properties": { - "key": { - "type": "string" - } - }, - "additionalProperties": false - }, - { - "type": "object", - "required": [ - "index" - ], - "properties": { - "index": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - }, - "additionalProperties": false - } - ] - }, - "ValueOrdering": { - "type": "string", - "enum": [ - "unit_above", - "unit_above_equal", - "unit_below", - "unit_below_equal", - "equal", - "not_equal" - ] - }, - "VoteOption": { - "type": "string", - "enum": [ - "yes", - "no", - "abstain", - "no_with_veto" - ] - }, - "WasmMsg": { - "description": "The message types of the wasm module.\n\nSee https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto", - "oneOf": [ - { - "description": "Dispatches a call to another contract at a known address (with known ABI).\n\nThis is translated to a [MsgExecuteContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L68-L78). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "execute" - ], - "properties": { - "execute": { - "type": "object", - "required": [ - "contract_addr", - "funds", - "msg" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "msg": { - "description": "msg is the json-encoded ExecuteMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Instantiates a new contracts from previously uploaded Wasm code.\n\nThis is translated to a [MsgInstantiateContract](https://github.com/CosmWasm/wasmd/blob/v0.16.0-alpha1/x/wasm/internal/types/tx.proto#L47-L61). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "instantiate" - ], - "properties": { - "instantiate": { - "type": "object", - "required": [ - "code_id", - "funds", - "label", - "msg" - ], - "properties": { - "admin": { - "type": [ - "string", - "null" - ] - }, - "code_id": { - "type": "integer", - "format": "uint64", - "minimum": 0.0 - }, - "funds": { - "type": "array", - "items": { - "$ref": "#/definitions/Coin" - } - }, - "label": { - "description": "A human-readbale label for the contract", - "type": "string" - }, - "msg": { - "description": "msg is the JSON-encoded InstantiateMsg struct (as raw Binary)", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Migrates a given contracts to use new wasm code. Passes a MigrateMsg to allow us to customize behavior.\n\nOnly the contract admin (as defined in wasmd), if any, is able to make this call.\n\nThis is translated to a [MsgMigrateContract](https://github.com/CosmWasm/wasmd/blob/v0.14.0/x/wasm/internal/types/tx.proto#L86-L96). `sender` is automatically filled with the current contract's address.", - "type": "object", - "required": [ - "migrate" - ], - "properties": { - "migrate": { - "type": "object", - "required": [ - "contract_addr", - "msg", - "new_code_id" - ], - "properties": { - "contract_addr": { - "type": "string" - }, - "msg": { - "description": "msg is the json-encoded MigrateMsg struct that will be passed to the new code", - "allOf": [ - { - "$ref": "#/definitions/Binary" - } - ] - }, - "new_code_id": { - "description": "the code_id of the new logic to place in the given contract", - "type": "integer", - "format": "uint64", - "minimum": 0.0 - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Sets a new admin (for migrate) on the given contract. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "update_admin" - ], - "properties": { - "update_admin": { - "type": "object", - "required": [ - "admin", - "contract_addr" - ], - "properties": { - "admin": { - "type": "string" - }, - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - }, - { - "description": "Clears the admin on the given contract, so no more migration possible. Fails if this contract is not currently admin of the target contract.", - "type": "object", - "required": [ - "clear_admin" - ], - "properties": { - "clear_admin": { - "type": "object", - "required": [ - "contract_addr" - ], - "properties": { - "contract_addr": { - "type": "string" - } - } - } - }, - "additionalProperties": false - } - ] - } - } -} 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 269736a3..57f23427 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": { diff --git a/packages/cw-croncat-core/src/msg.rs b/packages/cw-croncat-core/src/msg.rs index 8e48b06d..493154bc 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 { @@ -564,3 +468,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..441f3e69 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, }, }; @@ -65,9 +65,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..b792be09 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(); @@ -507,8 +552,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..6691a733 100644 --- a/packages/cw-croncat-core/src/types.rs +++ b/packages/cw-croncat-core/src/types.rs @@ -227,6 +227,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 +237,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 +331,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 +388,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 +467,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 +484,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 +638,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 {}) } @@ -867,26 +921,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/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 befe9a5f..63571744 100644 --- a/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts +++ b/typescript/contracts/cw-croncat-core/CwCroncatCore.client.ts @@ -6,7 +6,7 @@ import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate"; import { StdFee } from "@cosmjs/amino"; -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, 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"; export interface CwCroncatCoreReadOnlyInterface { contractAddress: string; getConfig: () => Promise; @@ -67,13 +67,6 @@ export interface CwCroncatCoreReadOnlyInterface { }: { wallet: string; }) => Promise; - getState: ({ - fromIndex, - limit - }: { - fromIndex?: number; - limit?: number; - }) => Promise; } export class CwCroncatCoreQueryClient implements CwCroncatCoreReadOnlyInterface { client: CosmWasmClient; @@ -96,7 +89,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 +227,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 +236,9 @@ export interface CwCroncatCoreInterface extends CwCroncatCoreReadOnlyInterface { agentsEjectThreshold, gasActionFee, gasBaseFee, - gasFraction, + gasPrice, + gasQueryFee, + gasWasmQueryFee, minTasksPerAgent, ownerId, paused, @@ -269,7 +249,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 +357,9 @@ export class CwCroncatCoreClient extends CwCroncatCoreQueryClient implements CwC agentsEjectThreshold, gasActionFee, gasBaseFee, - gasFraction, + gasPrice, + gasQueryFee, + gasWasmQueryFee, minTasksPerAgent, ownerId, paused, @@ -386,7 +370,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 +385,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 8785d9c1..0fc4fcec 100644 --- a/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts +++ b/typescript/contracts/cw-croncat-core/CwCroncatCore.types.ts @@ -249,7 +249,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; @@ -260,8 +260,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; } @@ -421,7 +422,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; @@ -504,41 +507,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; @@ -546,18 +519,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; } @@ -629,11 +599,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