From 81d1785e23e3e47081aa94e8cd7b86f62c83c41c Mon Sep 17 00:00:00 2001 From: Noah Saso Date: Wed, 27 Nov 2024 11:14:03 -0800 Subject: [PATCH] added query to check if delegate is registered --- .../schema/dao-vote-delegation.json | 52 +++++++++++++++++++ .../dao-vote-delegation/src/contract.rs | 20 ++++++- .../dao-vote-delegation/src/testing/suite.rs | 40 +++++++++++--- .../dao-vote-delegation/src/testing/tests.rs | 20 ++++++- packages/dao-voting/src/delegation.rs | 15 ++++++ 5 files changed, 139 insertions(+), 8 deletions(-) diff --git a/contracts/delegation/dao-vote-delegation/schema/dao-vote-delegation.json b/contracts/delegation/dao-vote-delegation/schema/dao-vote-delegation.json index bce7dcbb0..d8b7948ee 100644 --- a/contracts/delegation/dao-vote-delegation/schema/dao-vote-delegation.json +++ b/contracts/delegation/dao-vote-delegation/schema/dao-vote-delegation.json @@ -623,6 +623,36 @@ }, "additionalProperties": false }, + { + "description": "Returns whether or not a delegate is registered, optionally at a given height.", + "type": "object", + "required": [ + "registered" + ], + "properties": { + "registered": { + "type": "object", + "required": [ + "delegate" + ], + "properties": { + "delegate": { + "type": "string" + }, + "height": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 0.0 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + }, { "description": "Returns the paginated list of active delegates.", "type": "object", @@ -975,6 +1005,28 @@ } } }, + "registered": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "RegisteredResponse", + "type": "object", + "required": [ + "height", + "registered" + ], + "properties": { + "height": { + "description": "The height at which registration was checked.", + "type": "integer", + "format": "uint64", + "minimum": 0.0 + }, + "registered": { + "description": "Whether or not the delegate is registered.", + "type": "boolean" + } + }, + "additionalProperties": false + }, "unvoted_delegated_voting_power": { "$schema": "http://json-schema.org/draft-07/schema#", "title": "UnvotedDelegatedVotingPowerResponse", diff --git a/contracts/delegation/dao-vote-delegation/src/contract.rs b/contracts/delegation/dao-vote-delegation/src/contract.rs index de4705051..4d7312c2e 100644 --- a/contracts/delegation/dao-vote-delegation/src/contract.rs +++ b/contracts/delegation/dao-vote-delegation/src/contract.rs @@ -12,7 +12,8 @@ use dao_interface::helpers::OptionalUpdate; use dao_interface::state::{ProposalModule, ProposalModuleStatus}; use dao_interface::voting::InfoResponse; use dao_voting::delegation::{ - calculate_delegated_vp, DelegationResponse, UnvotedDelegatedVotingPowerResponse, + calculate_delegated_vp, DelegationResponse, RegisteredResponse, + UnvotedDelegatedVotingPowerResponse, }; use dao_voting::voting; use semver::Version; @@ -462,6 +463,9 @@ fn execute_update_config( pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult { match msg { QueryMsg::Info {} => Ok(to_json_binary(&query_info(deps)?)?), + QueryMsg::Registered { delegate, height } => Ok(to_json_binary(&query_registered( + deps, env, delegate, height, + )?)?), QueryMsg::Delegates { start_after, limit } => Ok(to_json_binary(&query_delegates( deps, env, @@ -502,6 +506,20 @@ fn query_info(deps: Deps) -> StdResult { Ok(InfoResponse { info }) } +fn query_registered( + deps: Deps, + env: Env, + delegate: String, + height: Option, +) -> StdResult { + let height = height.unwrap_or(env.block.height); + let delegate = deps.api.addr_validate(&delegate)?; + + let registered = is_delegate_registered(deps, &delegate, Some(height))?; + + Ok(RegisteredResponse { registered, height }) +} + fn query_delegates( deps: Deps, env: Env, diff --git a/contracts/delegation/dao-vote-delegation/src/testing/suite.rs b/contracts/delegation/dao-vote-delegation/src/testing/suite.rs index bbf14657e..d864a961f 100644 --- a/contracts/delegation/dao-vote-delegation/src/testing/suite.rs +++ b/contracts/delegation/dao-vote-delegation/src/testing/suite.rs @@ -248,6 +248,20 @@ impl DaoVoteDelegationTestingSuite { /// QUERIES impl DaoVoteDelegationTestingSuite { + /// get whether a delegate is registered + pub fn registered(&self, delegate: impl Into, height: Option) -> bool { + self.querier() + .query_wasm_smart::( + &self.delegation_addr, + &crate::msg::QueryMsg::Registered { + delegate: delegate.into(), + height, + }, + ) + .unwrap() + .registered + } + /// get the delegates pub fn delegates( &self, @@ -361,18 +375,32 @@ impl DaoVoteDelegationTestingSuite { .any(|d| d.delegate == delegate.into() && d.percent == percent && d.active)); } + /// assert that a delegate is registered + pub fn assert_delegate_registered( + &self, + delegate: impl Into + Copy, + height: Option, + ) { + let registered = self.registered(delegate, height); + assert!(registered); + } + + /// assert that a delegate is not registered + pub fn assert_delegate_not_registered( + &self, + delegate: impl Into + Copy, + height: Option, + ) { + let registered = self.registered(delegate, height); + assert!(!registered); + } + /// assert that there are N delegates pub fn assert_delegates_count(&self, count: u32) { let delegates = self.delegates(None, None); assert_eq!(delegates.len() as u32, count); } - /// assert a delegate is registered - pub fn assert_registered(&self, delegate: impl Into + Copy) { - let delegates = self.delegates(None, None); - assert!(delegates.iter().any(|d| d.delegate == delegate.into())); - } - /// assert a delegate's total delegated voting power pub fn assert_delegate_total_delegated_vp( &self, diff --git a/contracts/delegation/dao-vote-delegation/src/testing/tests.rs b/contracts/delegation/dao-vote-delegation/src/testing/tests.rs index 3d5b04de4..d22964dca 100644 --- a/contracts/delegation/dao-vote-delegation/src/testing/tests.rs +++ b/contracts/delegation/dao-vote-delegation/src/testing/tests.rs @@ -41,10 +41,11 @@ fn test_simple() { .collect::>() ); + suite.assert_delegate_not_registered(ADDR0, None); + // register ADDR0 as a delegate suite.register(ADDR0); suite.assert_delegates_count(1); - suite.assert_registered(ADDR0); // delegate 100% of addr1's voting power to ADDR0 suite.delegate(ADDR1, ADDR0, Decimal::percent(100)); @@ -52,6 +53,12 @@ fn test_simple() { // delegations take effect on the next block suite.advance_block(); + // ensure registered + suite.assert_delegate_registered(ADDR0, None); + suite.assert_delegate_registered(ADDR0, Some(suite.app.block_info().height)); + // historical check works + suite.assert_delegate_not_registered(ADDR0, Some(suite.app.block_info().height - 1)); + suite.assert_delegations_count(ADDR1, 1); suite.assert_delegation(ADDR1, ADDR0, Decimal::percent(100)); suite.assert_delegate_total_delegated_vp(ADDR0, suite.members[1].weight); @@ -185,12 +192,15 @@ fn test_simple() { suite.assert_delegate_total_delegated_vp(ADDR0, total_vp_except_addr0); + suite.assert_delegate_registered(ADDR0, None); + // unregister ADDR0 as a delegate suite.unregister(ADDR0); // delegations take effect on the next block suite.advance_block(); + suite.assert_delegate_not_registered(ADDR0, None); suite.assert_delegates_count(0); // propose another proposal @@ -621,6 +631,10 @@ fn test_allow_register_after_unregister_same_block() { suite.register(ADDR0); suite.unregister(ADDR0); suite.register(ADDR0); + + // ensure registered + suite.advance_block(); + suite.assert_delegate_registered(ADDR0, None); } #[test] @@ -632,6 +646,10 @@ fn test_allow_register_after_unregister_next_block() { suite.unregister(ADDR0); suite.advance_block(); suite.register(ADDR0); + + // ensure registered + suite.advance_block(); + suite.assert_delegate_registered(ADDR0, None); } #[test] diff --git a/packages/dao-voting/src/delegation.rs b/packages/dao-voting/src/delegation.rs index 9387e9ff4..9ccd8c4c4 100644 --- a/packages/dao-voting/src/delegation.rs +++ b/packages/dao-voting/src/delegation.rs @@ -8,6 +8,13 @@ pub enum QueryMsg { /// Returns contract version info #[returns(InfoResponse)] Info {}, + /// Returns whether or not a delegate is registered, optionally at a given + /// height. + #[returns(RegisteredResponse)] + Registered { + delegate: String, + height: Option, + }, /// Returns the paginated list of active delegates. #[returns(DelegatesResponse)] Delegates { @@ -50,6 +57,14 @@ pub enum QueryMsg { }, } +#[cw_serde] +pub struct RegisteredResponse { + /// Whether or not the delegate is registered. + pub registered: bool, + /// The height at which registration was checked. + pub height: u64, +} + #[cw_serde] pub struct DelegatesResponse { /// The delegates.