From 3e07a3579861ce788b00f2c64111ec46e76360d4 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 09:49:09 -0700 Subject: [PATCH 01/20] update treasury for single allowance and multi-any --- Cargo.toml | 2 +- contracts/treasury/src/contract.rs | 5 +- contracts/treasury/src/error.rs | 7 +- contracts/treasury/src/execute.rs | 154 ++++++++++------------ contracts/treasury/src/grant.rs | 8 +- contracts/treasury/src/grant/allowance.rs | 109 +++++---------- contracts/treasury/src/msg.rs | 14 +- contracts/treasury/src/state.rs | 4 +- 8 files changed, 136 insertions(+), 167 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ee86fdf..d3a23d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ 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 = "b50389f3988ba932e07f4fdee48d5928a1ed675e", default-features = false, features = ["cosmwasm", "xion"]} 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/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 82007a7..df1de5e 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -27,8 +27,8 @@ 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), + update, + } => execute::deploy_fee_grant(deps, env, authz_granter, authz_grantee, update), ExecuteMsg::UpdateAdmin { new_admin } => execute::update_admin(deps, info, new_admin), ExecuteMsg::UpdateGrantConfig { msg_type_url, @@ -37,6 +37,7 @@ pub fn execute( ExecuteMsg::RemoveGrantConfig { msg_type_url } => { execute::remove_grant_config(deps, info, msg_type_url) } + ExecuteMsg::UpdateFeeConfig { fee_config } => {} } } 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..aa34950 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -5,12 +5,12 @@ use crate::error::ContractError::{ 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 crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; +use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; 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 cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; +use pbjson_types::{Any, Timestamp}; use serde::de::value::{Error, StringDeserializer}; use serde_json::Value; @@ -103,95 +103,71 @@ pub fn deploy_fee_grant( env: Env, authz_granter: Addr, authz_grantee: Addr, - msg_type_url: String, + update: bool, ) -> 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(), - })) + // 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())?; + + // check if grant exists on chain + let authz_query_msg = QueryGrantsRequest { + granter: authz_granter.to_string(), + grantee: authz_grantee.to_string(), + msg_type_url: msg_type_url.clone(), + pagination: None, + }; + let authz_query_msg_bytes = authz_query_msg.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(), + })?; + + 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.clone().is_empty() && !grant_config.optional { + return Err(AuthzGrantNotFound { msg_type_url }); + } else { + match grants.first() { + None => return Err(AuthzGrantNotFound { msg_type_url }), + Some(grant) => { + match grant.clone().authorization { + None => return Err(AuthzGrantNotFound { msg_type_url }), + Some(auth) => { + // the authorization must match the one in the config + if grant_config.authorization.ne(&auth.into()) { + return Err(AuthzGrantMismatch); + } + } + } + } + } } - }; - 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); - } - - 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 { 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.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(), @@ -204,12 +180,26 @@ pub fn deploy_fee_grant( 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 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)) + let response = Response::new(); + if update { + // the submitter claims a feegrant already exists, so we must revoke the existing one + let feegrant_revoke_msg = + cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { + granter: env.contract.address.clone().into_string(), + grantee: authz_grantee.clone().into_string(), + }; + let feegrant_revoke_msg_bytes = feegrant_revoke_msg.to_bytes()?; + let cosmos_revoke_msg = CosmosMsg::Stargate { + type_url: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance".to_string(), + value: feegrant_revoke_msg_bytes.into(), + }; + response.add_message(cosmos_revoke_msg); + } + Ok(response.clone().add_message(cosmos_feegrant_msg)) } } } diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index 119d529..a38625b 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -9,8 +9,14 @@ use serde_json::Value; 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] diff --git a/contracts/treasury/src/grant/allowance.rs b/contracts/treasury/src/grant/allowance.rs index 3c3f779..c855dce 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -6,7 +6,7 @@ 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 cosmwasm_std::Addr; use pbjson_types::Timestamp; @@ -20,23 +20,10 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.BasicAllowance" => match expiration.clone() { 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::<&[u8]>(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(), @@ -47,27 +34,12 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.PeriodicAllowance" => match expiration.clone() { 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::<&[u8]>(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 +48,8 @@ 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::<&[u8]>(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -92,15 +57,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 +65,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::<&[u8]>(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -139,13 +90,8 @@ 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::<&[u8]>(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -153,15 +99,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::<&[u8]>(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.clone(), + )? + .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..60d2e93 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,13 @@ pub enum ExecuteMsg { RemoveGrantConfig { msg_type_url: String, }, + UpdateFeeConfig { + fee_config: FeeConfig, + }, DeployFeeGrant { authz_granter: Addr, authz_grantee: Addr, - msg_type_url: String, + update: bool, }, } @@ -37,4 +41,10 @@ pub enum QueryMsg { #[returns(Binary)] GrantConfigTypeUrls {}, + + #[returns(Binary)] + FeeConfig {}, + + #[returns(Binary)] + Admin {}, } 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"); From d10c8c431c618efe19c352a06e16668a6a9b7c89 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 09:53:57 -0700 Subject: [PATCH 02/20] dynamic check --- contracts/treasury/src/contract.rs | 3 +-- contracts/treasury/src/execute.rs | 17 ++++++++++++++++- contracts/treasury/src/msg.rs | 1 - 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index df1de5e..77fce49 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -27,8 +27,7 @@ pub fn execute( ExecuteMsg::DeployFeeGrant { authz_granter, authz_grantee, - update, - } => execute::deploy_fee_grant(deps, env, authz_granter, authz_grantee, update), + } => 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, diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index aa34950..bb20cc0 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -7,6 +7,7 @@ use crate::grant::allowance::format_allowance; use crate::grant::GrantConfig; use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; +use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; use cosmos_sdk_proto::tendermint::serializers::timestamp; use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; @@ -103,7 +104,6 @@ pub fn deploy_fee_grant( env: Env, authz_granter: Addr, authz_grantee: Addr, - update: bool, ) -> ContractResult { // 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 @@ -156,6 +156,20 @@ pub fn deploy_fee_grant( None => Ok(Response::new()), // allowance should be stored as a prost proto from the feegrant definition Some(allowance) => { + // check to see if the user already has an existing feegrant + let feegrant_query_msg = QueryAllowanceRequest { + granter: authz_granter.to_string(), + grantee: authz_grantee.to_string(), + }; + let feegrant_query_msg_bytes = feegrant_query_msg.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(), + })?; + let update = feegrant_query_res.allowance.is_some(); + // build the new allowance based on expiration let expiration = match fee_config.expiration { None => None, @@ -187,6 +201,7 @@ pub fn deploy_fee_grant( let response = Response::new(); if update { // the submitter claims a feegrant already exists, so we must revoke the existing one + // perhaps in a future version we will make this check dynamic, but it seems expensive let feegrant_revoke_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { granter: env.contract.address.clone().into_string(), diff --git a/contracts/treasury/src/msg.rs b/contracts/treasury/src/msg.rs index 60d2e93..1528e0d 100644 --- a/contracts/treasury/src/msg.rs +++ b/contracts/treasury/src/msg.rs @@ -28,7 +28,6 @@ pub enum ExecuteMsg { DeployFeeGrant { authz_granter: Addr, authz_grantee: Addr, - update: bool, }, } From 381a9b51978ecb7ca20d298206a9004f5c99cd32 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 09:59:23 -0700 Subject: [PATCH 03/20] update type --- contracts/treasury/src/execute.rs | 33 +++++++++++++++---------------- contracts/treasury/src/grant.rs | 3 +-- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index bb20cc0..e616597 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -153,23 +153,10 @@ pub fn deploy_fee_grant( let fee_config = FEE_CONFIG.load(deps.storage)?; // create feegrant, if needed 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) => { - // check to see if the user already has an existing feegrant - let feegrant_query_msg = QueryAllowanceRequest { - granter: authz_granter.to_string(), - grantee: authz_grantee.to_string(), - }; - let feegrant_query_msg_bytes = feegrant_query_msg.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(), - })?; - let update = feegrant_query_res.allowance.is_some(); - // build the new allowance based on expiration let expiration = match fee_config.expiration { None => None, @@ -199,9 +186,21 @@ pub fn deploy_fee_grant( value: feegrant_msg_bytes.into(), }; let response = Response::new(); - if update { - // the submitter claims a feegrant already exists, so we must revoke the existing one - // perhaps in a future version we will make this check dynamic, but it seems expensive + + // check to see if the user already has an existing feegrant + let feegrant_query_msg = QueryAllowanceRequest { + granter: authz_granter.to_string(), + grantee: authz_grantee.to_string(), + }; + let feegrant_query_msg_bytes = feegrant_query_msg.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(), + }, + )?; + + if feegrant_query_res.allowance.is_some() { let feegrant_revoke_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { granter: env.contract.address.clone().into_string(), diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index a38625b..1d441c1 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -3,12 +3,11 @@ 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 authorization: Any, pub optional: bool, } From 75abf57a4d3e7cc79f7f81893db19d984ed80fcc Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 10:07:21 -0700 Subject: [PATCH 04/20] more queries --- contracts/treasury/src/contract.rs | 5 ++++- contracts/treasury/src/execute.rs | 17 ++++++++++++++++- contracts/treasury/src/query.rs | 14 +++++++++++--- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 77fce49..77ecb5a 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -1,4 +1,5 @@ use crate::error::ContractResult; +use crate::execute::update_fee_config; use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg}; use crate::{execute, query, CONTRACT_NAME, CONTRACT_VERSION}; use cosmwasm_std::{ @@ -36,7 +37,7 @@ pub fn execute( ExecuteMsg::RemoveGrantConfig { msg_type_url } => { execute::remove_grant_config(deps, info, msg_type_url) } - ExecuteMsg::UpdateFeeConfig { fee_config } => {} + ExecuteMsg::UpdateFeeConfig { fee_config } => update_fee_config(deps, info, fee_config), } } @@ -49,5 +50,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/execute.rs b/contracts/treasury/src/execute.rs index e616597..e351a71 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -4,7 +4,7 @@ use crate::error::ContractError::{ }; use crate::error::ContractResult; use crate::grant::allowance::format_allowance; -use crate::grant::GrantConfig; +use crate::grant::{FeeConfig, GrantConfig}; use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; @@ -99,6 +99,21 @@ 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, 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) +} From 028199281adace1fe892ab5f043e673dcb369ec0 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 10:22:51 -0700 Subject: [PATCH 05/20] allow allowance revocation --- contracts/treasury/src/contract.rs | 3 +- contracts/treasury/src/execute.rs | 45 ++++++++++++++++++++++++------ contracts/treasury/src/msg.rs | 3 ++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 77ecb5a..1435b20 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -1,5 +1,5 @@ use crate::error::ContractResult; -use crate::execute::update_fee_config; +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::{ @@ -38,6 +38,7 @@ pub fn execute( 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), } } diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index e351a71..617802e 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -8,12 +8,9 @@ use crate::grant::{FeeConfig, GrantConfig}; use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; -use cosmos_sdk_proto::tendermint::serializers::timestamp; use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; -use pbjson_types::{Any, Timestamp}; -use serde::de::value::{Error, StringDeserializer}; -use serde_json::Value; +use pbjson_types::Timestamp; pub fn init( deps: DepsMut, @@ -191,8 +188,8 @@ pub fn deploy_fee_grant( expiration, )?; let feegrant_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgGrantAllowance { - granter: env.contract.address.into_string(), - grantee: authz_grantee.into_string(), + granter: env.contract.address.clone().into_string(), + grantee: authz_grantee.clone().into_string(), allowance: Some(formatted_allowance.into()), }; let feegrant_msg_bytes = feegrant_msg.to_bytes()?; @@ -200,7 +197,6 @@ pub fn deploy_fee_grant( type_url: "/cosmos.feegrant.v1beta1.MsgGrantAllowance".to_string(), value: feegrant_msg_bytes.into(), }; - let response = Response::new(); // check to see if the user already has an existing feegrant let feegrant_query_msg = QueryAllowanceRequest { @@ -215,6 +211,7 @@ pub fn deploy_fee_grant( }, )?; + let mut msgs: Vec = Vec::new(); if feegrant_query_res.allowance.is_some() { let feegrant_revoke_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { @@ -226,9 +223,39 @@ pub fn deploy_fee_grant( type_url: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance".to_string(), value: feegrant_revoke_msg_bytes.into(), }; - response.add_message(cosmos_revoke_msg); + msgs.push(cosmos_revoke_msg); } - Ok(response.clone().add_message(cosmos_feegrant_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 = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { + granter: env.contract.address.into_string(), + grantee: grantee.clone().into_string(), + }; + let feegrant_revoke_msg_bytes = feegrant_revoke_msg.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/msg.rs b/contracts/treasury/src/msg.rs index 1528e0d..b773fe0 100644 --- a/contracts/treasury/src/msg.rs +++ b/contracts/treasury/src/msg.rs @@ -29,6 +29,9 @@ pub enum ExecuteMsg { authz_granter: Addr, authz_grantee: Addr, }, + RevokeAllowance { + grantee: Addr, + }, } #[cw_serde] From c5afef3d40ac43632530f0d3dea0f233a30b6294 Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 10:26:50 -0700 Subject: [PATCH 06/20] cleanup serialization calls --- contracts/treasury/src/execute.rs | 56 ++++++++++++++++--------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 617802e..c9cfb84 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -1,16 +1,16 @@ +use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; +use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; +use cosmos_sdk_proto::traits::MessageExt; +use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; +use pbjson_types::Timestamp; + use crate::error::ContractError::{ - self, AuthzGrantMismatch, AuthzGrantNoAuthorization, AuthzGrantNotFound, ConfigurationMismatch, - Unauthorized, + AuthzGrantMismatch, AuthzGrantNotFound, ConfigurationMismatch, Unauthorized, }; use crate::error::ContractResult; use crate::grant::allowance::format_allowance; use crate::grant::{FeeConfig, GrantConfig}; use crate::state::{ADMIN, FEE_CONFIG, GRANT_CONFIGS}; -use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; -use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; -use cosmos_sdk_proto::traits::MessageExt; -use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; -use pbjson_types::Timestamp; pub fn init( deps: DepsMut, @@ -124,13 +124,13 @@ pub fn deploy_fee_grant( let grant_config = GRANT_CONFIGS.load(deps.storage, msg_type_url.clone())?; // check if grant exists on chain - let authz_query_msg = QueryGrantsRequest { + 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, - }; - let authz_query_msg_bytes = authz_query_msg.to_bytes()?; + } + .to_bytes()?; let authz_query_res = deps.querier .query::(&cosmwasm_std::QueryRequest::Stargate { @@ -187,23 +187,24 @@ pub fn deploy_fee_grant( authz_grantee.clone(), expiration, )?; - let feegrant_msg = 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()), - }; - let feegrant_msg_bytes = feegrant_msg.to_bytes()?; + 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(), }; // check to see if the user already has an existing feegrant - let feegrant_query_msg = QueryAllowanceRequest { + let feegrant_query_msg_bytes = QueryAllowanceRequest { granter: authz_granter.to_string(), grantee: authz_grantee.to_string(), - }; - let feegrant_query_msg_bytes = feegrant_query_msg.to_bytes()?; + } + .to_bytes()?; let feegrant_query_res = deps.querier.query::( &cosmwasm_std::QueryRequest::Stargate { path: "/cosmos.feegrant.v1beta1.Query/Allowance".to_string(), @@ -213,12 +214,12 @@ pub fn deploy_fee_grant( let mut msgs: Vec = Vec::new(); if feegrant_query_res.allowance.is_some() { - let feegrant_revoke_msg = + 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(), - }; - let feegrant_revoke_msg_bytes = feegrant_revoke_msg.to_bytes()?; + } + .to_bytes()?; let cosmos_revoke_msg = CosmosMsg::Stargate { type_url: "/cosmos.feegrant.v1beta1.MsgRevokeAllowance".to_string(), value: feegrant_revoke_msg_bytes.into(), @@ -242,11 +243,12 @@ pub fn revoke_allowance( return Err(Unauthorized); } - let feegrant_revoke_msg = cosmos_sdk_proto::cosmos::feegrant::v1beta1::MsgRevokeAllowance { - granter: env.contract.address.into_string(), - grantee: grantee.clone().into_string(), - }; - let feegrant_revoke_msg_bytes = feegrant_revoke_msg.to_bytes()?; + 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(), From 3f6290540ed297c9d1bb97063b701dad73705196 Mon Sep 17 00:00:00 2001 From: peartes Date: Fri, 19 Jul 2024 02:21:20 +0100 Subject: [PATCH 07/20] fix: failing integration test --- contracts/treasury/src/contract.rs | 9 +++- contracts/treasury/src/execute.rs | 68 +++++++++++++++++++----------- contracts/treasury/src/grant.rs | 3 +- 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 1435b20..4d16e9c 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -14,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] diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index c9cfb84..9ad38b3 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -3,9 +3,11 @@ use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAl use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; use pbjson_types::Timestamp; +use serde_json::Value; use crate::error::ContractError::{ - AuthzGrantMismatch, AuthzGrantNotFound, ConfigurationMismatch, Unauthorized, + AuthzGrantMismatch, AuthzGrantNoAuthorization, AuthzGrantNotFound, ConfigurationMismatch, + Unauthorized, }; use crate::error::ContractResult; use crate::grant::allowance::format_allowance; @@ -18,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, @@ -33,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())]), @@ -133,32 +138,46 @@ pub fn deploy_fee_grant( .to_bytes()?; let authz_query_res = deps.querier - .query::(&cosmwasm_std::QueryRequest::Stargate { + .query::(&cosmwasm_std::QueryRequest::Stargate { path: "/cosmos.authz.v1beta1.Query/Grants".to_string(), data: authz_query_msg_bytes.into(), })?; - let grants = &authz_query_res.grants; + 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.clone().is_empty() && !grant_config.optional { + if !grants.is_array() { return Err(AuthzGrantNotFound { msg_type_url }); - } else { - match grants.first() { - None => return Err(AuthzGrantNotFound { msg_type_url }), - Some(grant) => { - match grant.clone().authorization { - None => return Err(AuthzGrantNotFound { msg_type_url }), - Some(auth) => { - // the authorization must match the one in the config - if grant_config.authorization.ne(&auth.into()) { - return Err(AuthzGrantMismatch); - } - } - } - } - } } + 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); + } + // if grants.clone().is_empty() && !grant_config.optional { + // return Err(AuthzGrantNotFound { msg_type_url }); + // } else { + // match grants.first() { + // None => return Err(AuthzGrantNotFound { msg_type_url }), + // Some(grant) => { + // match grant.clone().authorization { + // None => return Err(AuthzGrantNotFound { msg_type_url }), + // Some(auth) => { + // // the authorization must match the one in the config + // if grant_config.authorization.ne(&auth.into()) { + // return Err(AuthzGrantMismatch); + // } + // } + // } + // } + // } + // } } // at this point, all the authz grants in the grant_config are verified @@ -176,7 +195,7 @@ pub fn deploy_fee_grant( let expiration_time = env.block.time.plus_seconds(seconds as u64); Some(Timestamp { seconds: expiration_time.seconds() as i64, - nanos: expiration_time.nanos() as i32, + nanos: expiration_time.subsec_nanos() as i32, }) } }; @@ -205,12 +224,13 @@ pub fn deploy_fee_grant( grantee: authz_grantee.to_string(), } .to_bytes()?; - let feegrant_query_res = deps.querier.query::( - &cosmwasm_std::QueryRequest::Stargate { + 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_default(); let mut msgs: Vec = Vec::new(); if feegrant_query_res.allowance.is_some() { diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index 1d441c1..a38625b 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -3,11 +3,12 @@ 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: Any, + pub authorization: Value, pub optional: bool, } From 02c4bfe023b89e091547622078d8116610af581f Mon Sep 17 00:00:00 2001 From: Ash Date: Thu, 18 Jul 2024 19:18:30 -0700 Subject: [PATCH 08/20] save fee config in init --- contracts/treasury/src/contract.rs | 2 +- contracts/treasury/src/execute.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 1435b20..b220e04 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -14,7 +14,7 @@ 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] diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index c9cfb84..3200fb8 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -18,6 +18,7 @@ pub fn init( admin: Option, type_urls: Vec, grant_configs: Vec, + fee_config: FeeConfig, ) -> ContractResult { let treasury_admin = match admin { None => info.sender, @@ -32,6 +33,8 @@ pub fn init( for i in 0..type_urls.len() { 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") From d049c3f67954e38f4b6a20d705ffd78ecf16a598 Mon Sep 17 00:00:00 2001 From: ash-burnt <96692350+ash-burnt@users.noreply.github.com> Date: Sat, 20 Jul 2024 07:46:25 -0700 Subject: [PATCH 09/20] Update contracts/treasury/src/execute.rs Co-authored-by: Kehinde Faleye Signed-off-by: ash-burnt <96692350+ash-burnt@users.noreply.github.com> --- contracts/treasury/src/execute.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 988f9b6..190d343 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -38,7 +38,6 @@ pub fn init( FEE_CONFIG.save(deps.storage, &fee_config)?; - FEE_CONFIG.save(deps.storage, &fee_config)?; Ok(Response::new().add_event( Event::new("create_treasury_instance") From 3db89e9920264bf9addd82d53c8d591f54ad264a Mon Sep 17 00:00:00 2001 From: peartes Date: Sat, 20 Jul 2024 15:49:05 +0100 Subject: [PATCH 10/20] fix: failing revokeAllowance call --- contracts/treasury/src/execute.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 988f9b6..6ae9625 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -222,20 +222,20 @@ pub fn deploy_fee_grant( // check to see if the user already has an existing feegrant let feegrant_query_msg_bytes = QueryAllowanceRequest { - granter: authz_granter.to_string(), + granter: env.contract.address.to_string(), grantee: authz_grantee.to_string(), } .to_bytes()?; let feegrant_query_res = deps .querier - .query::(&cosmwasm_std::QueryRequest::Stargate { + .query::(&cosmwasm_std::QueryRequest::Stargate { path: "/cosmos.feegrant.v1beta1.Query/Allowance".to_string(), data: feegrant_query_msg_bytes.into(), }) - .unwrap_or_default(); + .unwrap_or_else(|_| serde_json::json!({"allowance": null})); let mut msgs: Vec = Vec::new(); - if feegrant_query_res.allowance.is_some() { + 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(), From b30d1abcb8b3e5ddafdb328a8555d3916ba98a01 Mon Sep 17 00:00:00 2001 From: Ash Date: Sat, 20 Jul 2024 07:49:43 -0700 Subject: [PATCH 11/20] linting --- contracts/treasury/src/execute.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 190d343..9ad38b3 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -35,9 +35,8 @@ pub fn init( for i in 0..type_urls.len() { GRANT_CONFIGS.save(deps.storage, type_urls[i].clone(), &grant_configs[i])?; } - - FEE_CONFIG.save(deps.storage, &fee_config)?; + FEE_CONFIG.save(deps.storage, &fee_config)?; Ok(Response::new().add_event( Event::new("create_treasury_instance") From d7fa1ebf62bd8619be29490e1b8f5f7645cb6660 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 22 Jul 2024 15:59:53 -0400 Subject: [PATCH 12/20] lints --- contracts/treasury/src/execute.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 38fc235..5c50832 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -1,5 +1,5 @@ -use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; -use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest, QueryAllowanceResponse}; +use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest}; +use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest}; use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; use pbjson_types::Timestamp; From 0e022033a22bf499a826a6c279e36bba21c302a3 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 22 Jul 2024 16:54:17 -0400 Subject: [PATCH 13/20] format --- contracts/treasury/src/execute.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 5c50832..0c00b57 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -1,5 +1,5 @@ -use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest}; -use cosmos_sdk_proto::cosmos::feegrant::v1beta1::{QueryAllowanceRequest}; +use cosmos_sdk_proto::cosmos::authz::v1beta1::QueryGrantsRequest; +use cosmos_sdk_proto::cosmos::feegrant::v1beta1::QueryAllowanceRequest; use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; use pbjson_types::Timestamp; From fc04e2538c66ad36ea5420a206bd584b83db1681 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:07:48 -0700 Subject: [PATCH 14/20] bring down upstream changes with cosmos rust --- Cargo.toml | 4 +--- contracts/treasury/Cargo.toml | 6 +----- contracts/treasury/src/execute.rs | 2 +- contracts/treasury/src/grant.rs | 13 ++++++------- contracts/treasury/src/grant/allowance.rs | 14 +++++++------- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3a23d1..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 = "b50389f3988ba932e07f4fdee48d5928a1ed675e", 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/treasury/Cargo.toml b/contracts/treasury/Cargo.toml index 774274a..4e96e2a 100644 --- a/contracts/treasury/Cargo.toml +++ b/contracts/treasury/Cargo.toml @@ -16,8 +16,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/execute.rs b/contracts/treasury/src/execute.rs index 0c00b57..42fccb7 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -2,7 +2,7 @@ use cosmos_sdk_proto::cosmos::authz::v1beta1::QueryGrantsRequest; use cosmos_sdk_proto::cosmos::feegrant::v1beta1::QueryAllowanceRequest; use cosmos_sdk_proto::traits::MessageExt; use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; -use pbjson_types::Timestamp; +use cosmos_sdk_proto::Timestamp; use serde_json::Value; use crate::error::ContractError::{ diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index a38625b..e225988 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -2,7 +2,6 @@ pub mod allowance; use cosmwasm_schema::cw_serde; use cosmwasm_std::Binary; -use prost::bytes::Bytes; use serde_json::Value; #[cw_serde] @@ -25,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 c855dce..e15a17d 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -8,7 +8,7 @@ use cosmos_sdk_proto::prost::Message; use cosmos_sdk_proto::traits::MessageExt; use cosmos_sdk_proto::xion::v1::{AuthzAllowance, ContractsAllowance, MultiAnyAllowance}; use cosmwasm_std::Addr; -use pbjson_types::Timestamp; +use cosmos_sdk_proto::Timestamp; pub fn format_allowance( allowance_any: Any, @@ -21,7 +21,7 @@ pub fn format_allowance( None => allowance_any, Some(_) => { let mut allowance = - BasicAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + BasicAllowance::decode(allowance_any.value.as_slice())?; allowance.expiration = expiration; let allowance_bz = allowance.to_bytes()?; Any { @@ -35,7 +35,7 @@ pub fn format_allowance( None => allowance_any, Some(_) => { let mut allowance = - PeriodicAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + 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); @@ -49,7 +49,7 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.AllowedMsgAllowance" => { let mut allowance = - AllowedMsgAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -65,7 +65,7 @@ pub fn format_allowance( } "/xion.v1.AuthzAllowance" => { - let mut allowance = AuthzAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + let mut allowance = AuthzAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -91,7 +91,7 @@ pub fn format_allowance( "/xion.v1.ContractsAllowance" => { let mut allowance = - ContractsAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + ContractsAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -106,7 +106,7 @@ pub fn format_allowance( } } "/xion.v1.MultiAnyAllowance" => { - let mut allowance = MultiAnyAllowance::decode::<&[u8]>(allowance_any.value.as_slice())?; + let mut allowance = MultiAnyAllowance::decode(allowance_any.value.as_slice())?; for inner_allowance in allowance.allowances.iter_mut() { *inner_allowance = format_allowance( From 0cebe2985829f0c73fb9fb1e905f71667daa9af1 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:08:48 -0700 Subject: [PATCH 15/20] formatting --- contracts/treasury/src/execute.rs | 2 +- contracts/treasury/src/grant/allowance.rs | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 42fccb7..9163c9f 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -1,8 +1,8 @@ use cosmos_sdk_proto::cosmos::authz::v1beta1::QueryGrantsRequest; use cosmos_sdk_proto::cosmos::feegrant::v1beta1::QueryAllowanceRequest; use cosmos_sdk_proto::traits::MessageExt; -use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; use cosmos_sdk_proto::Timestamp; +use cosmwasm_std::{Addr, CosmosMsg, DepsMut, Env, Event, MessageInfo, Order, Response}; use serde_json::Value; use crate::error::ContractError::{ diff --git a/contracts/treasury/src/grant/allowance.rs b/contracts/treasury/src/grant/allowance.rs index e15a17d..4c04b95 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -7,8 +7,8 @@ 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, MultiAnyAllowance}; -use cosmwasm_std::Addr; use cosmos_sdk_proto::Timestamp; +use cosmwasm_std::Addr; pub fn format_allowance( allowance_any: Any, @@ -20,8 +20,7 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.BasicAllowance" => match expiration.clone() { None => allowance_any, Some(_) => { - let mut allowance = - BasicAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = BasicAllowance::decode(allowance_any.value.as_slice())?; allowance.expiration = expiration; let allowance_bz = allowance.to_bytes()?; Any { @@ -34,8 +33,7 @@ pub fn format_allowance( "/cosmos.feegrant.v1beta1.PeriodicAllowance" => match expiration.clone() { None => allowance_any, Some(_) => { - let mut allowance = - PeriodicAllowance::decode(allowance_any.value.as_slice())?; + 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); @@ -48,8 +46,7 @@ pub fn format_allowance( }, "/cosmos.feegrant.v1beta1.AllowedMsgAllowance" => { - let mut allowance = - AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = AllowedMsgAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, @@ -90,8 +87,7 @@ pub fn format_allowance( } "/xion.v1.ContractsAllowance" => { - let mut allowance = - ContractsAllowance::decode(allowance_any.value.as_slice())?; + let mut allowance = ContractsAllowance::decode(allowance_any.value.as_slice())?; let inner_allowance = format_allowance( allowance.allowance.ok_or(AllowanceUnset)?.into(), _granter, From 41eb0a666b5c61846de32dc6e6ca170a3a80ddca Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:11:28 -0700 Subject: [PATCH 16/20] remove comment --- contracts/treasury/src/execute.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index 9163c9f..d94ed8a 100644 --- a/contracts/treasury/src/execute.rs +++ b/contracts/treasury/src/execute.rs @@ -160,24 +160,6 @@ pub fn deploy_fee_grant( if grant_config.authorization.ne(auth) { return Err(AuthzGrantMismatch); } - // if grants.clone().is_empty() && !grant_config.optional { - // return Err(AuthzGrantNotFound { msg_type_url }); - // } else { - // match grants.first() { - // None => return Err(AuthzGrantNotFound { msg_type_url }), - // Some(grant) => { - // match grant.clone().authorization { - // None => return Err(AuthzGrantNotFound { msg_type_url }), - // Some(auth) => { - // // the authorization must match the one in the config - // if grant_config.authorization.ne(&auth.into()) { - // return Err(AuthzGrantMismatch); - // } - // } - // } - // } - // } - // } } // at this point, all the authz grants in the grant_config are verified From 05438a13ed8d877b228910b4b843e1170d25a618 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:14:12 -0700 Subject: [PATCH 17/20] ignore artifacts --- .gitignore | 1 + 1 file changed, 1 insertion(+) 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 From 50df0da50f275c4c9c5687a55e1b935d5e5fa109 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:22:12 -0700 Subject: [PATCH 18/20] remove library feature --- contracts/account/src/lib.rs | 1 - 1 file changed, 1 deletion(-) 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; From b8ae9c220c5f33db02586fff40cf1eb30c19b875 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:29:12 -0700 Subject: [PATCH 19/20] use copy trait --- contracts/treasury/src/grant/allowance.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contracts/treasury/src/grant/allowance.rs b/contracts/treasury/src/grant/allowance.rs index 4c04b95..2e19e27 100644 --- a/contracts/treasury/src/grant/allowance.rs +++ b/contracts/treasury/src/grant/allowance.rs @@ -17,7 +17,7 @@ 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(allowance_any.value.as_slice())?; @@ -30,7 +30,7 @@ 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(allowance_any.value.as_slice())?; @@ -109,7 +109,7 @@ pub fn format_allowance( inner_allowance.clone().into(), _granter.clone(), grantee.clone(), - expiration.clone(), + expiration, )? .into(); } From 32b2ac6918ce523fdb3e04fda1063dda50077743 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 12 Aug 2024 15:32:16 -0700 Subject: [PATCH 20/20] libary feature for treasury --- contracts/treasury/Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/contracts/treasury/Cargo.toml b/contracts/treasury/Cargo.toml index 4e96e2a..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 }