diff --git a/.gitignore b/.gitignore index 09e44d4..a857565 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ **/schema .vscode Cargo.lock +/artifacts # Cargo+Git helper file (https://github.com/rust-lang/cargo/blob/0.44.1/src/cargo/s$ .cargo-ok diff --git a/Cargo.toml b/Cargo.toml index ee86fdf..4780c33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,5 @@ rsa = { version = "0.9.2" } getrandom = { version = "0.2.10", features = ["custom"] } p256 = {version = "0.13.2", features = ["ecdsa-core", "arithmetic", "serde"]} prost = {version = "0.11.2", default-features = false, features = ["prost-derive"]} -cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "9108ae0517bd9fd543c0662e06598032a642e426", default-features = false, features = ["cosmwasm", "xion"]} +cosmos-sdk-proto = {git = "https://github.com/burnt-labs/cosmos-rust.git", rev = "75e72f446629f98330e209e2f6268250d325cccb", default-features = false, features = ["std", "cosmwasm", "xion", "serde"]} osmosis-std-derive = "0.13.2" -prost-types = "0.12.6" -pbjson-types = "0.6.0" \ No newline at end of file diff --git a/contracts/account/src/lib.rs b/contracts/account/src/lib.rs index 5f48840..01e848c 100644 --- a/contracts/account/src/lib.rs +++ b/contracts/account/src/lib.rs @@ -1,7 +1,6 @@ extern crate core; mod auth; -#[cfg(not(feature = "library"))] pub mod contract; pub mod error; pub mod execute; diff --git a/contracts/treasury/Cargo.toml b/contracts/treasury/Cargo.toml index 774274a..d65d65b 100644 --- a/contracts/treasury/Cargo.toml +++ b/contracts/treasury/Cargo.toml @@ -7,6 +7,10 @@ edition = "2021" [lib] crate-type = ["cdylib", "rlib"] +[features] +# enable feature if you want to disable entry points +library = [] + [dependencies] cosmwasm-schema = { workspace = true } cosmwasm-std = { workspace = true } @@ -16,8 +20,4 @@ thiserror = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } schemars = { workspace = true } -cosmos-sdk-proto = { workspace = true } -prost = { workspace = true } -osmosis-std-derive = { workspace = true } -prost-types = { workspace = true } -pbjson-types = { workspace = true } \ No newline at end of file +cosmos-sdk-proto = { workspace = true } \ No newline at end of file diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 82007a7..4d16e9c 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -1,4 +1,5 @@ use crate::error::ContractResult; +use crate::execute::{revoke_allowance, update_fee_config}; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::{execute, query, CONTRACT_NAME, CONTRACT_VERSION}; use cosmwasm_std::{ @@ -13,7 +14,14 @@ pub fn instantiate( msg: InstantiateMsg, ) -> ContractResult { cw2::set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?; - execute::init(deps, info, msg.admin, msg.type_urls, msg.grant_configs) + execute::init( + deps, + info, + msg.admin, + msg.type_urls, + msg.grant_configs, + msg.fee_config, + ) } #[entry_point] @@ -27,8 +35,7 @@ pub fn execute( ExecuteMsg::DeployFeeGrant { authz_granter, authz_grantee, - msg_type_url, - } => execute::deploy_fee_grant(deps, env, authz_granter, authz_grantee, msg_type_url), + } => execute::deploy_fee_grant(deps, env, authz_granter, authz_grantee), ExecuteMsg::UpdateAdmin { new_admin } => execute::update_admin(deps, info, new_admin), ExecuteMsg::UpdateGrantConfig { msg_type_url, @@ -37,6 +44,8 @@ pub fn execute( ExecuteMsg::RemoveGrantConfig { msg_type_url } => { execute::remove_grant_config(deps, info, msg_type_url) } + ExecuteMsg::UpdateFeeConfig { fee_config } => update_fee_config(deps, info, fee_config), + ExecuteMsg::RevokeAllowance { grantee } => revoke_allowance(deps, env, info, grantee), } } @@ -49,5 +58,7 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { QueryMsg::GrantConfigTypeUrls {} => { to_json_binary(&query::grant_config_type_urls(deps.storage)?) } + QueryMsg::FeeConfig {} => to_json_binary(&query::fee_config(deps.storage)?), + QueryMsg::Admin {} => to_json_binary(&query::admin(deps.storage)?), } } diff --git a/contracts/treasury/src/error.rs b/contracts/treasury/src/error.rs index 8aedc8e..1f999a3 100644 --- a/contracts/treasury/src/error.rs +++ b/contracts/treasury/src/error.rs @@ -6,8 +6,11 @@ pub enum ContractError { #[error(transparent)] Encode(#[from] cosmos_sdk_proto::prost::EncodeError), - #[error("authz grant not found")] - AuthzGrantNotFound, + #[error(transparent)] + Decode(#[from] cosmos_sdk_proto::prost::DecodeError), + + #[error("authz grant not found, msg_type: {msg_type_url}")] + AuthzGrantNotFound { msg_type_url: String }, #[error("authz grant has no authorization")] AuthzGrantNoAuthorization, diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 1af5918..d94ed8a 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -1,18 +1,18 @@ +use cosmos_sdk_proto::cosmos::authz::v1beta1::QueryGrantsRequest; +use cosmos_sdk_proto::cosmos::feegrant::v1beta1::QueryAllowanceRequest; +use cosmos_sdk_proto::traits::MessageExt; +use cosmos_sdk_proto::Timestamp; +use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; +use serde_json::Value; + use crate::error::ContractError::{ - self, AuthzGrantMismatch, AuthzGrantNoAuthorization, AuthzGrantNotFound, ConfigurationMismatch, + AuthzGrantMismatch, AuthzGrantNoAuthorization, AuthzGrantNotFound, ConfigurationMismatch, Unauthorized, }; use crate::error::ContractResult; use crate::grant::allowance::format_allowance; -use crate::grant::GrantConfig; -use crate::state::{ADMIN, GRANT_CONFIGS}; -use cosmos_sdk_proto::cosmos::authz::v1beta1::QueryGrantsRequest; -use cosmos_sdk_proto::tendermint::serializers::timestamp; -use cosmos_sdk_proto::traits::MessageExt; -use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Response}; -use pbjson_types::Timestamp; -use serde::de::value::{Error, StringDeserializer}; -use serde_json::Value; +use crate::grant::{FeeConfig, GrantConfig}; +use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; pub fn init( deps: DepsMut, @@ -20,6 +20,7 @@ pub fn init( admin: Option, type_urls: Vec, grant_configs: Vec, + fee_config: FeeConfig, ) -> ContractResult { let treasury_admin = match admin { None => info.sender, @@ -35,6 +36,8 @@ pub fn init( GRANT_CONFIGS.save(deps.storage, type_urls[i].clone(), &grant_configs[i])?; } + FEE_CONFIG.save(deps.storage, &fee_config)?; + Ok(Response::new().add_event( Event::new("create_treasury_instance") .add_attributes(vec![("admin", treasury_admin.into_string())]), @@ -98,118 +101,165 @@ pub fn remove_grant_config( )) } +pub fn update_fee_config( + deps: DepsMut, + info: MessageInfo, + fee_config: FeeConfig, +) -> ContractResult { + let admin = ADMIN.load(deps.storage)?; + if admin != info.sender { + return Err(Unauthorized); + } + + FEE_CONFIG.save(deps.storage, &fee_config)?; + + Ok(Response::new().add_event(Event::new("updated_treasury_fee_config"))) +} + pub fn deploy_fee_grant( deps: DepsMut, env: Env, authz_granter: Addr, authz_grantee: Addr, - msg_type_url: String, ) -> ContractResult { - // check if grant exists in patterns on contract - let grant_config = GRANT_CONFIGS.load(deps.storage, msg_type_url.clone())?; - - // check if grant exists on chain - let query_msg = QueryGrantsRequest { - granter: authz_granter.to_string(), - grantee: authz_grantee.to_string(), - msg_type_url: msg_type_url.clone(), - pagination: None, - }; - let query_msg_bytes = match query_msg.to_bytes() { - Ok(bz) => bz, - Err(_) => { - return Err(ContractError::Std(cosmwasm_std::StdError::SerializeErr { - source_type: String::from("QueryGrantsRequest"), - msg: "Unable to serialize QueryGrantsRequest".to_string(), - })) - } - }; - let query_res = deps - .querier - .query::(&cosmwasm_std::QueryRequest::Stargate { - path: "/cosmos.authz.v1beta1.Query/Grants".to_string(), - data: query_msg_bytes.into(), - })?; - - let grants = &query_res["grants"]; - // grant queries with a granter, grantee and type_url should always result - // in only one result - if !grants.is_array() { - return Err(AuthzGrantNotFound); - } - let grant = grants[0].clone(); - if grant.is_null() { - return Err(AuthzGrantNotFound); - } + // iterate through all grant configs to validate user has correct permissions + // we must iterate, because calling for the list of grants doesn't return msg_type_urls + for key in GRANT_CONFIGS.keys(deps.storage, None, None, Order::Ascending) { + let msg_type_url = key?; + let grant_config = GRANT_CONFIGS.load(deps.storage, msg_type_url.clone())?; - let auth = &grant["authorization"]; - if auth.is_null() { - return Err(AuthzGrantNoAuthorization); - } + // check if grant exists on chain + let authz_query_msg_bytes = QueryGrantsRequest { + granter: authz_granter.to_string(), + grantee: authz_grantee.to_string(), + msg_type_url: msg_type_url.clone(), + pagination: None, + } + .to_bytes()?; + let authz_query_res = + deps.querier + .query::(&cosmwasm_std::QueryRequest::Stargate { + path: "/cosmos.authz.v1beta1.Query/Grants".to_string(), + data: authz_query_msg_bytes.into(), + })?; - if grant_config.authorization.ne(auth) { - return Err(AuthzGrantMismatch); + let grants = &authz_query_res["grants"]; + // grant queries with a granter, grantee and type_url should always result + // in only one result, unless the grant is optional + if !grants.is_array() { + return Err(AuthzGrantNotFound { msg_type_url }); + } + let grant = grants[0].clone(); + if grant.is_null() { + return Err(AuthzGrantNotFound { msg_type_url }); + } + let auth = &grant["authorization"]; + if auth.is_null() { + return Err(AuthzGrantNoAuthorization); + } + if grant_config.authorization.ne(auth) { + return Err(AuthzGrantMismatch); + } } + // at this point, all the authz grants in the grant_config are verified + let fee_config = FEE_CONFIG.load(deps.storage)?; // create feegrant, if needed - match grant_config.allowance { + match fee_config.allowance { + // this treasury doesn't deploy any fees, and can return None => Ok(Response::new()), // allowance should be stored as a prost proto from the feegrant definition Some(allowance) => { - let grant_expiration = - grant["expiration"].as_str().map(|t| { - match timestamp::deserialize(StringDeserializer::::new(t.to_string())) { - Ok(tm) => Timestamp { - seconds: tm.seconds, - nanos: tm.nanos, - }, - Err(_) => Timestamp::default(), - } - }); - - let max_expiration = match grant_config.max_duration { + // build the new allowance based on expiration + let expiration = match fee_config.expiration { None => None, - Some(duration) => { - let max_timestamp = env.block.time.plus_seconds(duration as u64); + Some(seconds) => { + let expiration_time = env.block.time.plus_seconds(seconds as u64); Some(Timestamp { - seconds: max_timestamp.seconds() as i64, - nanos: max_timestamp.nanos() as i32, + seconds: expiration_time.seconds() as i64, + nanos: expiration_time.subsec_nanos() as i32, }) } }; - let expiration = match grant_expiration { - None => max_expiration, - Some(grant_expiration) => match max_expiration { - None => Some(grant_expiration), - Some(max_expiration) => { - if max_expiration.seconds < grant_expiration.seconds { - Some(max_expiration) - } else { - Some(grant_expiration) - } - } - }, - }; - let formatted_allowance = format_allowance( allowance, env.contract.address.clone(), authz_grantee.clone(), expiration, )?; - let feegrant_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgGrantAllowance { - granter: env.contract.address.into_string(), - grantee: authz_grantee.into_string(), - allowance: Some(formatted_allowance.into()), - }; - let feegrant_msg_bytes = feegrant_msg.to_bytes()?; - // todo: what if a feegrant already exists? - let cosmos_msg = CosmosMsg::Stargate { + let feegrant_msg_bytes = + cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgGrantAllowance { + granter: env.contract.address.clone().into_string(), + grantee: authz_grantee.clone().into_string(), + allowance: Some(formatted_allowance.into()), + } + .to_bytes()?; + let cosmos_feegrant_msg = CosmosMsg::Stargate { type_url: "/cosmos.feegrant.v1beta1.MsgGrantAllowance".to_string(), value: feegrant_msg_bytes.into(), }; - Ok(Response::new().add_message(cosmos_msg)) + + // check to see if the user already has an existing feegrant + let feegrant_query_msg_bytes = QueryAllowanceRequest { + granter: env.contract.address.to_string(), + grantee: authz_grantee.to_string(), + } + .to_bytes()?; + let feegrant_query_res = deps + .querier + .query::(&cosmwasm_std::QueryRequest::Stargate { + path: "/cosmos.feegrant.v1beta1.Query/Allowance".to_string(), + data: feegrant_query_msg_bytes.into(), + }) + .unwrap_or_else(|_| serde_json::json!({"allowance": null})); + + let mut msgs: Vec = Vec::new(); + if !feegrant_query_res["allowance"].is_null() { + let feegrant_revoke_msg_bytes = + cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { + granter: env.contract.address.clone().into_string(), + grantee: authz_grantee.clone().into_string(), + } + .to_bytes()?; + let cosmos_revoke_msg = CosmosMsg::Stargate { + type_url: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance".to_string(), + value: feegrant_revoke_msg_bytes.into(), + }; + msgs.push(cosmos_revoke_msg); + } + msgs.push(cosmos_feegrant_msg); + Ok(Response::new().add_messages(msgs)) } } } + +pub fn revoke_allowance( + deps: DepsMut, + env: Env, + info: MessageInfo, + grantee: Addr, +) -> ContractResult { + let admin = ADMIN.load(deps.storage)?; + if admin != info.sender { + return Err(Unauthorized); + } + + let feegrant_revoke_msg_bytes = + cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { + granter: env.contract.address.into_string(), + grantee: grantee.clone().into_string(), + } + .to_bytes()?; + let cosmos_feegrant_revoke_msg = CosmosMsg::Stargate { + type_url: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance".to_string(), + value: feegrant_revoke_msg_bytes.into(), + }; + + Ok(Response::new() + .add_message(cosmos_feegrant_revoke_msg) + .add_event( + Event::new("revoked_treasury_allowance") + .add_attributes(vec![("grantee", grantee.into_string())]), + )) +} diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index 119d529..e225988 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -2,15 +2,20 @@ pub mod allowance; use cosmwasm_schema::cw_serde; use cosmwasm_std::Binary; -use prost::bytes::Bytes; use serde_json::Value; #[cw_serde] pub struct GrantConfig { description: String, pub authorization: Value, + pub optional: bool, +} + +#[cw_serde] +pub struct FeeConfig { + description: String, pub allowance: Option, - pub max_duration: Option, + pub expiration: Option, } #[cw_serde] @@ -19,20 +24,20 @@ pub struct Any { pub value: Binary, } -impl From for Any { - fn from(value: pbjson_types::Any) -> Self { +impl From for Any { + fn from(value: cosmos_sdk_proto::Any) -> Self { Any { type_url: value.type_url, - value: Binary::from(value.value.to_vec()), + value: Binary::from(value.value), } } } -impl From for pbjson_types::Any { +impl From for cosmos_sdk_proto::Any { fn from(value: Any) -> Self { - pbjson_types::Any { + cosmos_sdk_proto::Any { type_url: value.type_url, - value: Bytes::copy_from_slice(value.value.as_slice()), + value: value.value.to_vec(), } } } diff --git a/contracts/treasury/src/grant/allowance.rs b/contracts/treasury/src/grant/allowance.rs index 3c3f779..2e19e27 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -6,9 +6,9 @@ use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{ }; use cosmos_sdk_proto::prost::Message; use cosmos_sdk_proto::traits::MessageExt; -use cosmos_sdk_proto::xion::v1::{AuthzAllowance, ContractsAllowance}; +use cosmos_sdk_proto::xion::v1::{AuthzAllowance, ContractsAllowance, MultiAnyAllowance}; +use cosmos_sdk_proto::Timestamp; use cosmwasm_std::Addr; -use pbjson_types::Timestamp; pub fn format_allowance( allowance_any: Any, @@ -17,26 +17,12 @@ pub fn format_allowance( expiration: Option, ) -> ContractResult { let formatted_allowance: Any = match allowance_any.type_url.as_str() { - "/cosmos.feegrant.v1beta1.BasicAllowance" => match expiration.clone() { + "/cosmos.feegrant.v1beta1.BasicAllowance" => match expiration { None => allowance_any, Some(_) => { - let mut allowance = BasicAllowance::decode::<&[u8]>(allowance_any.value.as_slice()) - .map_err(|err| { - ContractError::Std(cosmwasm_std::StdError::ParseErr { - target_type: "Basic Allowance".to_string(), - msg: err.to_string(), - }) - })?; + let mut allowance = BasicAllowance::decode(allowance_any.value.as_slice())?; allowance.expiration = expiration; - let allowance_bz = match allowance.to_bytes() { - Ok(bz) => bz, - Err(_) => { - return Err(ContractError::Std(cosmwasm_std::StdError::SerializeErr { - source_type: String::from("BasicAllowance"), - msg: "unable to serialize basic allowance".to_string(), - })) - } - }; + let allowance_bz = allowance.to_bytes()?; Any { type_url: allowance_any.type_url, value: allowance_bz.into(), @@ -44,30 +30,14 @@ pub fn format_allowance( } }, - "/cosmos.feegrant.v1beta1.PeriodicAllowance" => match expiration.clone() { + "/cosmos.feegrant.v1beta1.PeriodicAllowance" => match expiration { None => allowance_any, Some(_) => { - let mut allowance = PeriodicAllowance::decode::<&[u8]>( - allowance_any.value.as_slice(), - ) - .map_err(|err| { - ContractError::Std(cosmwasm_std::StdError::ParseErr { - target_type: "Periodic Allowance".to_string(), - msg: err.to_string(), - }) - })?; + let mut allowance = PeriodicAllowance::decode(allowance_any.value.as_slice())?; let mut inner_basic = allowance.basic.clone().ok_or(AllowanceUnset)?; inner_basic.expiration = expiration; allowance.basic = Some(inner_basic); - let allowance_bz = match allowance.to_bytes() { - Ok(bz) => bz, - Err(_) => { - return Err(ContractError::Std(cosmwasm_std::StdError::SerializeErr { - source_type: String::from("PeriodicAllowance"), - msg: "unable to serialize periodic allowance".to_string(), - })) - } - }; + let allowance_bz = allowance.to_bytes()?; Any { type_url: allowance_any.type_url, value: allowance_bz.into(), @@ -76,15 +46,7 @@ pub fn format_allowance( }, "/cosmos.feegrant.v1beta1.AllowedMsgAllowance" => { - let mut allowance = AllowedMsgAllowance::decode::<&[u8]>( - allowance_any.value.as_slice(), - ) - .map_err(|err| { - ContractError::Std(cosmwasm_std::StdError::ParseErr { - target_type: "Allowed Msg Allowance".to_string(), - msg: err.to_string(), - }) - })?; + let mut allowance = AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -92,15 +54,7 @@ pub fn format_allowance( expiration, )?; allowance.allowance = Some(inner_allowance.into()); - let allowance_bz = match allowance.to_bytes() { - Ok(bz) => bz, - Err(_) => { - return Err(ContractError::Std(cosmwasm_std::StdError::SerializeErr { - source_type: String::from("AllowedMsgAllowance"), - msg: "unable to serialize allowed msg allowance".to_string(), - })) - } - }; + let allowance_bz = allowance.to_bytes()?; Any { type_url: allowance_any.type_url, value: allowance_bz.into(), @@ -108,13 +62,7 @@ pub fn format_allowance( } "/xion.v1.AuthzAllowance" => { - let mut allowance = AuthzAllowance::decode::<&[u8]>(allowance_any.value.as_slice()) - .map_err(|err| { - ContractError::Std(cosmwasm_std::StdError::ParseErr { - target_type: "Authz Allowance".to_string(), - msg: err.to_string(), - }) - })?; + let mut allowance = AuthzAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -139,13 +87,7 @@ pub fn format_allowance( } "/xion.v1.ContractsAllowance" => { - let mut allowance = ContractsAllowance::decode::<&[u8]>(allowance_any.value.as_slice()) - .map_err(|err| { - ContractError::Std(cosmwasm_std::StdError::ParseErr { - target_type: "Contract Allowance".to_string(), - msg: err.to_string(), - }) - })?; + let mut allowance = ContractsAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -153,15 +95,26 @@ pub fn format_allowance( expiration, )?; allowance.allowance = Some(inner_allowance.into()); - let allowance_bz = match allowance.to_bytes() { - Ok(bz) => bz, - Err(_) => { - return Err(ContractError::Std(cosmwasm_std::StdError::SerializeErr { - source_type: String::from("ContractAllowance"), - msg: "unable to serialize contract allowance".to_string(), - })) - } - }; + let allowance_bz = allowance.to_bytes()?; + Any { + type_url: allowance_any.type_url, + value: allowance_bz.into(), + } + } + "/xion.v1.MultiAnyAllowance" => { + let mut allowance = MultiAnyAllowance::decode(allowance_any.value.as_slice())?; + + for inner_allowance in allowance.allowances.iter_mut() { + *inner_allowance = format_allowance( + inner_allowance.clone().into(), + _granter.clone(), + grantee.clone(), + expiration, + )? + .into(); + } + + let allowance_bz = allowance.to_bytes()?; Any { type_url: allowance_any.type_url, value: allowance_bz.into(), diff --git a/contracts/treasury/src/msg.rs b/contracts/treasury/src/msg.rs index 9b2b120..b773fe0 100644 --- a/contracts/treasury/src/msg.rs +++ b/contracts/treasury/src/msg.rs @@ -1,4 +1,4 @@ -use crate::grant::GrantConfig; +use crate::grant::{FeeConfig, GrantConfig}; use cosmwasm_schema::{cw_serde, QueryResponses}; use cosmwasm_std::{Addr, Binary}; @@ -7,6 +7,7 @@ pub struct InstantiateMsg { pub admin: Option, pub type_urls: Vec, pub grant_configs: Vec, + pub fee_config: FeeConfig, } #[cw_serde] @@ -21,10 +22,15 @@ pub enum ExecuteMsg { RemoveGrantConfig { msg_type_url: String, }, + UpdateFeeConfig { + fee_config: FeeConfig, + }, DeployFeeGrant { authz_granter: Addr, authz_grantee: Addr, - msg_type_url: String, + }, + RevokeAllowance { + grantee: Addr, }, } @@ -37,4 +43,10 @@ pub enum QueryMsg { #[returns(Binary)] GrantConfigTypeUrls {}, + + #[returns(Binary)] + FeeConfig {}, + + #[returns(Binary)] + Admin {}, } diff --git a/contracts/treasury/src/query.rs b/contracts/treasury/src/query.rs index 0a4390c..59d4253 100644 --- a/contracts/treasury/src/query.rs +++ b/contracts/treasury/src/query.rs @@ -1,6 +1,6 @@ -use crate::grant::GrantConfig; -use crate::state::GRANT_CONFIGS; -use cosmwasm_std::{Order, StdResult, Storage}; +use crate::grant::{FeeConfig, GrantConfig}; +use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; +use cosmwasm_std::{Addr, Order, StdResult, Storage}; pub fn grant_config_type_urls(store: &dyn Storage) -> StdResult> { Ok(GRANT_CONFIGS @@ -15,3 +15,11 @@ pub fn grant_config_by_type_url( ) -> StdResult { GRANT_CONFIGS.load(store, msg_type_url) } + +pub fn fee_config(store: &dyn Storage) -> StdResult { + FEE_CONFIG.load(store) +} + +pub fn admin(store: &dyn Storage) -> StdResult { + ADMIN.load(store) +} diff --git a/contracts/treasury/src/state.rs b/contracts/treasury/src/state.rs index a4dc05b..5bbf98b 100644 --- a/contracts/treasury/src/state.rs +++ b/contracts/treasury/src/state.rs @@ -1,8 +1,10 @@ -use crate::grant::GrantConfig; +use crate::grant::{FeeConfig, GrantConfig}; use cosmwasm_std::Addr; use cw_storage_plus::{Item, Map}; // msg_type_url to grant config pub const GRANT_CONFIGS: Map = Map::new("grant_configs"); +pub const FEE_CONFIG: Item = Item::new("fee_config"); + pub const ADMIN: Item = Item::new("admin");