diff --git a/contracts/external/dao-voting-incentives/schema/dao-voting-incentives.json b/contracts/external/dao-voting-incentives/schema/dao-voting-incentives.json index 0bfbb8c10..70ef14eda 100644 --- a/contracts/external/dao-voting-incentives/schema/dao-voting-incentives.json +++ b/contracts/external/dao-voting-incentives/schema/dao-voting-incentives.json @@ -183,6 +183,18 @@ } }, "additionalProperties": false + }, + { + "type": "object", + "required": [ + "receive" + ], + "properties": { + "receive": { + "$ref": "#/definitions/Cw20ReceiveMsg" + } + }, + "additionalProperties": false } ], "definitions": { @@ -237,6 +249,31 @@ } ] }, + "Binary": { + "description": "Binary is a wrapper around Vec to add base64 de/serialization with serde. It also adds some helper methods to help encode inline.\n\nThis is only needed as serde-json-{core,wasm} has a horrible encoding for Vec. See also .", + "type": "string" + }, + "Cw20ReceiveMsg": { + "description": "Cw20ReceiveMsg should be de/serialized under `Receive()` variant in a ExecuteMsg", + "type": "object", + "required": [ + "amount", + "msg", + "sender" + ], + "properties": { + "amount": { + "$ref": "#/definitions/Uint128" + }, + "msg": { + "$ref": "#/definitions/Binary" + }, + "sender": { + "type": "string" + } + }, + "additionalProperties": false + }, "Expiration": { "description": "Expiration represents a point in time when some event happens. It can compare with a BlockInfo and will return is_expired() == true once the condition is hit (and for every block in the future)", "oneOf": [ @@ -292,6 +329,10 @@ } ] }, + "Uint128": { + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" + }, "Uint64": { "description": "A thin wrapper around u64 that is using strings for JSON encoding/decoding, such that the full u64 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u64` to get the value out:\n\n``` # use cosmwasm_std::Uint64; let a = Uint64::from(42u64); assert_eq!(a.u64(), 42);\n\nlet b = Uint64::from(70u32); assert_eq!(b.u64(), 70); ```", "type": "string" @@ -353,7 +394,7 @@ "additionalProperties": false }, { - "description": "Returns the claimable rewards for the given address.", + "description": "Returns the rewards for the given address.", "type": "object", "required": [ "rewards" @@ -375,13 +416,13 @@ "additionalProperties": false }, { - "description": "Returns the expected rewards for the given address", + "description": "Returns the votes count for the given address", "type": "object", "required": [ - "expected_rewards" + "votes" ], "properties": { - "expected_rewards": { + "votes": { "type": "object", "required": [ "address" @@ -478,65 +519,6 @@ }, "additionalProperties": false }, - "expected_rewards": { - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "RewardResponse", - "type": "object", - "required": [ - "amount", - "denom" - ], - "properties": { - "amount": { - "$ref": "#/definitions/Uint128" - }, - "denom": { - "$ref": "#/definitions/CheckedDenom" - } - }, - "additionalProperties": false, - "definitions": { - "Addr": { - "description": "A human readable address.\n\nIn Cosmos, this is typically bech32 encoded. But for multi-chain smart contracts no assumptions should be made other than being UTF-8 encoded and of reasonable length.\n\nThis type represents a validated address. It can be created in the following ways 1. Use `Addr::unchecked(input)` 2. Use `let checked: Addr = deps.api.addr_validate(input)?` 3. Use `let checked: Addr = deps.api.addr_humanize(canonical_addr)?` 4. Deserialize from JSON. This must only be done from JSON that was validated before such as a contract's state. `Addr` must not be used in messages sent by the user because this would result in unvalidated instances.\n\nThis type is immutable. If you really need to mutate it (Really? Are you sure?), create a mutable copy using `let mut mutable = Addr::to_string()` and operate on that `String` instance.", - "type": "string" - }, - "CheckedDenom": { - "description": "A denom that has been checked to point to a valid asset. This enum should never be constructed literally and should always be built by calling `into_checked` on an `UncheckedDenom` instance.", - "oneOf": [ - { - "description": "A native (bank module) asset.", - "type": "object", - "required": [ - "native" - ], - "properties": { - "native": { - "type": "string" - } - }, - "additionalProperties": false - }, - { - "description": "A cw20 asset.", - "type": "object", - "required": [ - "cw20" - ], - "properties": { - "cw20": { - "$ref": "#/definitions/Addr" - } - }, - "additionalProperties": false - } - ] - }, - "Uint128": { - "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", - "type": "string" - } - } - }, "ownership": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "Ownership_for_String", @@ -690,6 +672,12 @@ "type": "string" } } + }, + "votes": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Uint128", + "description": "A thin wrapper around u128 that is using strings for JSON encoding/decoding, such that the full u128 range can be used for clients that convert JSON numbers to floats, like JavaScript and jq.\n\n# Examples\n\nUse `from` to create instances of this and `u128` to get the value out:\n\n``` # use cosmwasm_std::Uint128; let a = Uint128::from(123u128); assert_eq!(a.u128(), 123);\n\nlet b = Uint128::from(42u64); assert_eq!(b.u128(), 42);\n\nlet c = Uint128::from(70u32); assert_eq!(c.u128(), 70); ```", + "type": "string" } } } diff --git a/contracts/external/dao-voting-incentives/src/contract.rs b/contracts/external/dao-voting-incentives/src/contract.rs index 75d5b6050..ec439fe57 100644 --- a/contracts/external/dao-voting-incentives/src/contract.rs +++ b/contracts/external/dao-voting-incentives/src/contract.rs @@ -81,10 +81,7 @@ pub fn execute( #[cfg_attr(not(feature = "library"), entry_point)] pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { - QueryMsg::Rewards { address } => to_json_binary(&query::rewards(deps, address)?), - QueryMsg::ExpectedRewards { address } => { - to_json_binary(&query::expected_rewards(deps, env, address)?) - } + QueryMsg::Rewards { address } => to_json_binary(&query::rewards(deps, env, address)?), QueryMsg::Config {} => to_json_binary(&query::config(deps)?), QueryMsg::Ownership {} => to_json_binary(&get_ownership(deps.storage)?), QueryMsg::Votes { address } => to_json_binary(&query::votes(deps, address)?), diff --git a/contracts/external/dao-voting-incentives/src/execute.rs b/contracts/external/dao-voting-incentives/src/execute.rs index 22a16935b..a4d312467 100644 --- a/contracts/external/dao-voting-incentives/src/execute.rs +++ b/contracts/external/dao-voting-incentives/src/execute.rs @@ -13,14 +13,14 @@ use crate::{ ContractError, }; -pub fn claim(deps: DepsMut, _env: Env, info: MessageInfo) -> Result { +pub fn claim(deps: DepsMut, env: Env, info: MessageInfo) -> Result { // Ensure the user has something to claim if !USER_VOTE_COUNT.has(deps.storage, &info.sender) { return Err(ContractError::NothingToClaim {}); } // Get reward information - let reward = reward(deps.as_ref(), &info.sender)?; + let reward = reward(deps.as_ref(), &env.contract.address, &info.sender)?; // If the user has rewards, then we should generate a message let mut msgs = vec![]; @@ -212,13 +212,16 @@ pub fn expire(deps: DepsMut, env: Env, _info: MessageInfo) -> Result Result { let config = CONFIG.load(deps.storage)?; // Do not accept unexpected cw20 + if config.expiration.is_expired(&env.block) { + return Err(ContractError::AlreadyExpired {}); + } match &config.denom { CheckedDenom::Native(_) => { return Err(ContractError::UnexpectedFunds { diff --git a/contracts/external/dao-voting-incentives/src/msg.rs b/contracts/external/dao-voting-incentives/src/msg.rs index 4eb0b7af4..2b21e0711 100644 --- a/contracts/external/dao-voting-incentives/src/msg.rs +++ b/contracts/external/dao-voting-incentives/src/msg.rs @@ -36,12 +36,9 @@ pub enum QueryMsg { /// Returns the config #[returns(Config)] Config {}, - /// Returns the claimable rewards for the given address. + /// Returns the rewards for the given address. #[returns(RewardResponse)] Rewards { address: String }, - /// Returns the expected rewards for the given address - #[returns(RewardResponse)] - ExpectedRewards { address: String }, /// Returns the votes count for the given address #[returns(Uint128)] Votes { address: String }, diff --git a/contracts/external/dao-voting-incentives/src/query.rs b/contracts/external/dao-voting-incentives/src/query.rs index dcee2772f..622180c2e 100644 --- a/contracts/external/dao-voting-incentives/src/query.rs +++ b/contracts/external/dao-voting-incentives/src/query.rs @@ -5,16 +5,10 @@ use crate::{ state::{self, Config, CONFIG, USER_VOTE_COUNT}, }; -pub fn rewards(deps: Deps, address: String) -> StdResult { +pub fn rewards(deps: Deps, env: Env, address: String) -> StdResult { let address = deps.api.addr_validate(&address)?; - state::reward(deps, &address).map_err(|x| StdError::GenericErr { msg: x.to_string() }) -} - -pub fn expected_rewards(deps: Deps, env: Env, address: String) -> StdResult { - let address = deps.api.addr_validate(&address)?; - - state::expected_reward(deps, env, &address) + state::reward(deps, &env.contract.address, &address) .map_err(|x| StdError::GenericErr { msg: x.to_string() }) } diff --git a/contracts/external/dao-voting-incentives/src/state.rs b/contracts/external/dao-voting-incentives/src/state.rs index 09fdbfbac..3563e38f6 100644 --- a/contracts/external/dao-voting-incentives/src/state.rs +++ b/contracts/external/dao-voting-incentives/src/state.rs @@ -1,5 +1,5 @@ use cosmwasm_schema::cw_serde; -use cosmwasm_std::{Addr, CheckedMultiplyFractionError, Deps, Env, Uint128}; +use cosmwasm_std::{Addr, CheckedMultiplyFractionError, Deps, Uint128}; use cw_denom::CheckedDenom; use cw_storage_plus::{Item, Map}; use cw_utils::Expiration; @@ -34,15 +34,25 @@ pub const GENERIC_PROPOSAL_INFO: Map<(&Addr, u64), GenericProposalInfo> = Map::new("generic_proposal_info"); /// A method to load reward information -pub fn reward(deps: Deps, addr: &Addr) -> Result { +pub fn reward(deps: Deps, contract: &Addr, addr: &Addr) -> Result { let config = CONFIG.load(deps.storage)?; + // Get the user's votes + let user_votes = USER_VOTE_COUNT + .may_load(deps.storage, addr)? + .unwrap_or_default(); + match config.expiration_balance { Some(balance) => { - // Get the user's votes - let user_votes = USER_VOTE_COUNT - .may_load(deps.storage, addr)? - .unwrap_or_default(); + // Calculate the reward + Ok(RewardResponse { + denom: config.denom, + amount: calculate_reward(config.total_votes, user_votes, balance)?, + }) + } + None => { + // Get the current voting incentives balance + let balance = config.denom.query_balance(&deps.querier, contract)?; // Calculate the reward Ok(RewardResponse { @@ -50,34 +60,9 @@ pub fn reward(deps: Deps, addr: &Addr) -> Result amount: calculate_reward(config.total_votes, user_votes, balance)?, }) } - None => Err(ContractError::NotExpired { - expiration: config.expiration, - }), } } -/// A method to load the expected reward information -/// The expected reward method can differ from the actual reward, because the balance is saved in state after expiration -pub fn expected_reward(deps: Deps, env: Env, addr: &Addr) -> Result { - let config = CONFIG.load(deps.storage)?; - - // Get the voting incentives balance - let balance = config - .denom - .query_balance(&deps.querier, &env.contract.address)?; - - // Get the user's votes - let user_votes = USER_VOTE_COUNT - .may_load(deps.storage, addr)? - .unwrap_or_default(); - - // Calculate the reward - Ok(RewardResponse { - denom: config.denom, - amount: calculate_reward(config.total_votes, user_votes, balance)?, - }) -} - fn calculate_reward( total_votes: Uint128, user_votes: Uint128,