diff --git a/contracts/treasury/src/contract.rs b/contracts/treasury/src/contract.rs index 7532abd..0dba900 100644 --- a/contracts/treasury/src/contract.rs +++ b/contracts/treasury/src/contract.rs @@ -64,13 +64,24 @@ pub fn execute( #[entry_point] pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult { match msg { - QueryMsg::GrantConfigByTypeUrl { msg_type_url } => to_json_binary( - &query::grant_config_by_type_url(deps.storage, msg_type_url)?, + QueryMsg::RawGrantConfigByTypeUrl { msg_type_url } => to_json_binary( + &query::raw_grant_config_by_type_url(deps.storage, msg_type_url)?, ), + QueryMsg::GrantConfigByTypeUrl { + msg_type_url, + account_address, + } => to_json_binary(&query::grant_config_by_type_url( + deps.storage, + msg_type_url, + account_address, + )?), QueryMsg::GrantConfigTypeUrls {} => { to_json_binary(&query::grant_config_type_urls(deps.storage)?) } - QueryMsg::FeeConfig {} => to_json_binary(&query::fee_config(deps.storage)?), + QueryMsg::FeeConfig { address } => { + to_json_binary(&query::fee_config(deps.storage, address)?) + } + QueryMsg::RawFeeConfig {} => to_json_binary(&query::raw_fee_config(deps.storage)?), QueryMsg::Admin {} => to_json_binary(&query::admin(deps.storage)?), QueryMsg::PendingAdmin {} => to_json_binary(&query::pending_admin(deps.storage)?), QueryMsg::Params {} => to_json_binary(&query::params(deps.storage)?), diff --git a/contracts/treasury/src/error.rs b/contracts/treasury/src/error.rs index 87e3326..95edab6 100644 --- a/contracts/treasury/src/error.rs +++ b/contracts/treasury/src/error.rs @@ -1,3 +1,5 @@ +use cosmwasm_std::StdError; + #[derive(Debug, thiserror::Error)] pub enum ContractError { #[error(transparent)] @@ -38,3 +40,12 @@ pub enum ContractError { } pub type ContractResult = Result; + +impl From for StdError { + fn from(val: ContractError) -> Self { + match val { + ContractError::Std(err) => err, + _ => StdError::generic_err(val.to_string()), + } + } +} diff --git a/contracts/treasury/src/execute.rs b/contracts/treasury/src/execute.rs index b792472..4291657 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::{FeeConfig, GrantConfig}; +use crate::grant::{FeeConfigStorage, GrantConfigStorage}; use crate::state::{Params, ADMIN, FEE_CONFIG, GRANT_CONFIGS, PARAMS, PENDING_ADMIN}; use cosmos_sdk_proto::cosmos::authz::v1beta1::{QueryGrantsRequest, QueryGrantsResponse}; use cosmos_sdk_proto::cosmos::feegrant::v1beta1::QueryAllowanceRequest; @@ -22,8 +22,8 @@ pub fn init( info: MessageInfo, admin: Option, type_urls: Vec, - grant_configs: Vec, - fee_config: FeeConfig, + grant_configs: Vec, + fee_config: FeeConfigStorage, ) -> ContractResult { let treasury_admin = match admin { None => info.sender, @@ -116,7 +116,7 @@ pub fn update_grant_config( deps: DepsMut, info: MessageInfo, msg_type_url: String, - grant_config: GrantConfig, + grant_config: GrantConfigStorage, ) -> ContractResult { let admin = ADMIN.load(deps.storage)?; if admin != info.sender { @@ -165,7 +165,7 @@ pub fn remove_grant_config( pub fn update_fee_config( deps: DepsMut, info: MessageInfo, - fee_config: FeeConfig, + fee_config: FeeConfigStorage, ) -> ContractResult { let admin = ADMIN.load(deps.storage)?; if admin != info.sender { @@ -246,7 +246,12 @@ pub fn deploy_fee_grant( 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()) { + // Here authz_granter is supposed to be the abstract account (giving permissions) + if grant_config + .try_into_grant_config(authz_granter.to_string())? + .authorization + .ne(&auth.into()) + { return Err(AuthzGrantMismatch); } } @@ -259,7 +264,12 @@ pub fn deploy_fee_grant( let fee_config = FEE_CONFIG.load(deps.storage)?; // create feegrant, if needed - match fee_config.allowance { + // Here authz_granter is supposed to be the abstract account (giving authz permissions) + match fee_config + .allowance + .map(|a| a.try_into_any(authz_granter.to_string())) + .transpose()? + { // 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 diff --git a/contracts/treasury/src/grant.rs b/contracts/treasury/src/grant.rs index ebdfa28..661bb5b 100644 --- a/contracts/treasury/src/grant.rs +++ b/contracts/treasury/src/grant.rs @@ -1,8 +1,11 @@ pub mod allowance; +use cosmos_sdk_proto::{prost::Name, traits::MessageExt}; use cosmwasm_schema::cw_serde; use cosmwasm_std::Binary; +use crate::error::ContractResult; + #[cw_serde] pub struct GrantConfig { description: String, @@ -10,6 +13,69 @@ pub struct GrantConfig { pub optional: bool, } +#[cw_serde] + +pub enum AuthorizationData { + Any(Any), + ExecuteOnAccount(AuthorizationOnAccount), +} + +#[cw_serde] + +pub struct AuthorizationOnAccount { + pub limit: Option, + pub filter: Option, +} + +#[cw_serde] + +pub struct GrantConfigStorage { + pub description: String, + pub authorization: AuthorizationData, + pub optional: bool, +} + +impl AuthorizationData { + pub fn try_into_any(self, address: String) -> ContractResult { + Ok(match self { + AuthorizationData::Any(any) => any, + AuthorizationData::ExecuteOnAccount(auth) => { + // Handle the case where authorization is on the account itself + Any { + type_url: cosmos_sdk_proto::cosmwasm::wasm::v1::ContractExecutionAuthorization::full_name(), + value: + cosmos_sdk_proto::cosmwasm::wasm::v1::ContractExecutionAuthorization { + grants: vec![cosmos_sdk_proto::cosmwasm::wasm::v1::ContractGrant { + contract: address, + limit: auth.limit.map(Into::into), + filter:auth.filter.map(Into::into), + }], + } + .to_bytes()? + .into(), + } + } + }) + } +} + +impl GrantConfigStorage { + pub fn try_into_grant_config(self, address: String) -> ContractResult { + Ok(GrantConfig { + description: self.description, + authorization: self.authorization.try_into_any(address)?, + optional: self.optional, + }) + } +} + +#[cw_serde] +pub struct FeeConfigStorage { + description: String, + pub allowance: Option, + pub expiration: Option, +} + #[cw_serde] pub struct FeeConfig { description: String, @@ -17,6 +83,50 @@ pub struct FeeConfig { pub expiration: Option, } +#[cw_serde] +pub enum AllowanceData { + Any(Any), + AllowanceOnAccount(AllowanceOnAccount), +} +#[cw_serde] +pub struct AllowanceOnAccount { + pub allowance: Option, +} + +impl FeeConfigStorage { + pub fn try_into_fee_config(self, address: String) -> ContractResult { + Ok(FeeConfig { + description: self.description, + allowance: match self.allowance { + None => None, + Some(allowance) => Some(allowance.try_into_any(address)?), + }, + expiration: self.expiration, + }) + } +} + +impl AllowanceData { + pub fn try_into_any(self, address: String) -> ContractResult { + Ok(match self { + AllowanceData::Any(any) => any, + AllowanceData::AllowanceOnAccount(allowance) => { + // Handle the case where authorization is on the account itself + Any { + type_url: cosmos_sdk_proto::cosmwasm::wasm::v1::ContractExecutionAuthorization::full_name(), + value: + cosmos_sdk_proto::xion::v1::ContractsAllowance { + allowance: allowance.allowance.map(Into::into), + contract_addresses: vec![address] + } + .to_bytes()? + .into(), + } + } + }) + } +} + #[cw_serde] pub struct Any { pub type_url: String, diff --git a/contracts/treasury/src/msg.rs b/contracts/treasury/src/msg.rs index af5e3fc..0a78aad 100644 --- a/contracts/treasury/src/msg.rs +++ b/contracts/treasury/src/msg.rs @@ -1,14 +1,14 @@ -use crate::grant::{FeeConfig, GrantConfig}; +use crate::grant::{FeeConfig, FeeConfigStorage, GrantConfig, GrantConfigStorage}; use crate::state::Params; use cosmwasm_schema::{cw_serde, QueryResponses}; -use cosmwasm_std::{Addr, Binary, Coin}; +use cosmwasm_std::{Addr, Coin}; #[cw_serde] pub struct InstantiateMsg { pub admin: Option, pub type_urls: Vec, - pub grant_configs: Vec, - pub fee_config: FeeConfig, + pub grant_configs: Vec, + pub fee_config: FeeConfigStorage, } #[cw_serde] @@ -20,13 +20,13 @@ pub enum ExecuteMsg { CancelProposedAdmin {}, UpdateGrantConfig { msg_type_url: String, - grant_config: GrantConfig, + grant_config: GrantConfigStorage, }, RemoveGrantConfig { msg_type_url: String, }, UpdateFeeConfig { - fee_config: FeeConfig, + fee_config: FeeConfigStorage, }, DeployFeeGrant { authz_granter: Addr, @@ -47,21 +47,30 @@ pub enum ExecuteMsg { #[derive(QueryResponses)] pub enum QueryMsg { /// Query the grant config by type url - #[returns(Binary)] - GrantConfigByTypeUrl { msg_type_url: String }, + #[returns(GrantConfig)] + GrantConfigByTypeUrl { + msg_type_url: String, + account_address: String, + }, + /// Query the grant config by type url + #[returns(GrantConfigStorage)] + RawGrantConfigByTypeUrl { msg_type_url: String }, - #[returns(Binary)] + #[returns(Vec)] GrantConfigTypeUrls {}, - #[returns(Binary)] - FeeConfig {}, + #[returns(FeeConfig)] + FeeConfig { address: String }, + + #[returns(FeeConfigStorage)] + RawFeeConfig {}, - #[returns(Binary)] + #[returns(Addr)] Admin {}, - #[returns(Binary)] + #[returns(Addr)] PendingAdmin {}, - #[returns(Binary)] + #[returns(Params)] Params {}, } diff --git a/contracts/treasury/src/query.rs b/contracts/treasury/src/query.rs index 2be8f6e..e7dd573 100644 --- a/contracts/treasury/src/query.rs +++ b/contracts/treasury/src/query.rs @@ -1,4 +1,4 @@ -use crate::grant::{FeeConfig, GrantConfig}; +use crate::grant::{FeeConfig, FeeConfigStorage, GrantConfig, GrantConfigStorage}; use crate::state::{Params, ADMIN, FEE_CONFIG, GRANT_CONFIGS, PARAMS, PENDING_ADMIN}; use cosmwasm_std::{Addr, Order, StdResult, Storage}; @@ -12,14 +12,34 @@ pub fn grant_config_type_urls(store: &dyn Storage) -> StdResult> { pub fn grant_config_by_type_url( store: &dyn Storage, msg_type_url: String, + account_address: String, ) -> StdResult { + GRANT_CONFIGS + .load(store, msg_type_url) + .and_then(|grant_config| { + grant_config + .try_into_grant_config(account_address) + .map_err(Into::into) + }) +} + +pub fn raw_grant_config_by_type_url( + store: &dyn Storage, + msg_type_url: String, +) -> StdResult { GRANT_CONFIGS.load(store, msg_type_url) } -pub fn fee_config(store: &dyn Storage) -> StdResult { +pub fn raw_fee_config(store: &dyn Storage) -> StdResult { FEE_CONFIG.load(store) } +pub fn fee_config(store: &dyn Storage, address: String) -> StdResult { + FEE_CONFIG + .load(store) + .and_then(|fee_config| fee_config.try_into_fee_config(address).map_err(Into::into)) +} + 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 c85e241..9d12b02 100644 --- a/contracts/treasury/src/state.rs +++ b/contracts/treasury/src/state.rs @@ -1,12 +1,12 @@ -use crate::grant::{FeeConfig, GrantConfig}; +use crate::grant::{FeeConfigStorage, GrantConfigStorage}; use cosmwasm_schema::cw_serde; 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 GRANT_CONFIGS: Map = Map::new("grant_configs"); -pub const FEE_CONFIG: Item = Item::new("fee_config"); +pub const FEE_CONFIG: Item = Item::new("fee_config"); pub const ADMIN: Item = Item::new("admin");