This reverts commit 84e5c830cc
.
This commit is contained in:
parent
84e5c830cc
commit
af7c378c95
|
@ -82,11 +82,7 @@ pub fn process_cast_vote(
|
||||||
governance_info.key,
|
governance_info.key,
|
||||||
&proposal_governing_token_mint,
|
&proposal_governing_token_mint,
|
||||||
)?;
|
)?;
|
||||||
proposal_data.assert_can_cast_vote(
|
proposal_data.assert_can_cast_vote(&governance_data.config, clock.unix_timestamp)?;
|
||||||
&vote_kind,
|
|
||||||
&governance_data.config,
|
|
||||||
clock.unix_timestamp,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut voter_token_owner_record_data =
|
let mut voter_token_owner_record_data =
|
||||||
get_token_owner_record_data_for_realm_and_governing_mint(
|
get_token_owner_record_data_for_realm_and_governing_mint(
|
||||||
|
|
|
@ -31,7 +31,6 @@ pub struct GovernanceConfig {
|
||||||
pub min_community_weight_to_create_proposal: u64,
|
pub min_community_weight_to_create_proposal: u64,
|
||||||
|
|
||||||
/// Minimum waiting time in seconds for a transaction to be executed after proposal is voted on
|
/// Minimum waiting time in seconds for a transaction to be executed after proposal is voted on
|
||||||
/// If Veto vote is enabled then it can also be cast within the hold up period after Proposal vote ends
|
|
||||||
pub min_transaction_hold_up_time: u32,
|
pub min_transaction_hold_up_time: u32,
|
||||||
|
|
||||||
/// Time limit in seconds for proposal to be open for voting
|
/// Time limit in seconds for proposal to be open for voting
|
||||||
|
|
|
@ -260,88 +260,25 @@ impl ProposalV2 {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if the given vote kind can be cast for the Proposal
|
/// Checks if Proposal can be voted on
|
||||||
pub fn assert_can_cast_vote(
|
pub fn assert_can_cast_vote(
|
||||||
&self,
|
&self,
|
||||||
vote_kind: &VoteKind,
|
config: &GovernanceConfig,
|
||||||
governance_config: &GovernanceConfig,
|
|
||||||
current_unix_timestamp: UnixTimestamp,
|
current_unix_timestamp: UnixTimestamp,
|
||||||
) -> Result<(), ProgramError> {
|
) -> Result<(), ProgramError> {
|
||||||
match vote_kind {
|
|
||||||
VoteKind::Electorate => {
|
|
||||||
self.assert_can_cast_electorate_vote(governance_config, current_unix_timestamp)
|
|
||||||
}
|
|
||||||
VoteKind::Veto => {
|
|
||||||
self.assert_can_cast_veto_vote(governance_config, current_unix_timestamp)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if Electorate vote can be cast for the Proposal
|
|
||||||
pub fn assert_can_cast_electorate_vote(
|
|
||||||
&self,
|
|
||||||
governance_config: &GovernanceConfig,
|
|
||||||
current_unix_timestamp: UnixTimestamp,
|
|
||||||
) -> Result<(), ProgramError> {
|
|
||||||
// Electorate vote can only be cast in Voting state
|
|
||||||
self.assert_is_voting_state()
|
self.assert_is_voting_state()
|
||||||
.map_err(|_| GovernanceError::InvalidStateCannotVote)?;
|
.map_err(|_| GovernanceError::InvalidStateCannotVote)?;
|
||||||
|
|
||||||
// The Proposal can be still in Voting state after the voting time ends and before it's finalized
|
|
||||||
// Check if we are still within the configured max_voting_time period
|
// Check if we are still within the configured max_voting_time period
|
||||||
if self.has_vote_time_ended(governance_config, current_unix_timestamp) {
|
if self.has_vote_time_ended(config, current_unix_timestamp) {
|
||||||
return Err(GovernanceError::ProposalVotingTimeExpired.into());
|
return Err(GovernanceError::ProposalVotingTimeExpired.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if Veto vote can be cast for the Proposal
|
/// Vote end time determined by the configured max_voting_time period
|
||||||
pub fn assert_can_cast_veto_vote(
|
pub fn vote_end_time(&self, config: &GovernanceConfig) -> UnixTimestamp {
|
||||||
&self,
|
|
||||||
governance_config: &GovernanceConfig,
|
|
||||||
current_unix_timestamp: UnixTimestamp,
|
|
||||||
) -> Result<(), ProgramError> {
|
|
||||||
match self.state {
|
|
||||||
// Veto vote can be cast when:
|
|
||||||
// Proposal is in Voting state and within max_voting_time + min_transaction_hold_up_time period
|
|
||||||
ProposalState::Voting => {
|
|
||||||
if self
|
|
||||||
.expected_vote_end_time(governance_config)
|
|
||||||
.saturating_add(governance_config.min_transaction_hold_up_time as i64)
|
|
||||||
< current_unix_timestamp
|
|
||||||
{
|
|
||||||
Err(GovernanceError::ProposalVotingTimeExpired.into())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Proposal is in Succeeded state and within min_transaction_hold_up_time period calculated from the time when the vote ended (voting_completed_at)
|
|
||||||
ProposalState::Succeeded => {
|
|
||||||
if self
|
|
||||||
.voting_completed_at
|
|
||||||
.unwrap()
|
|
||||||
.saturating_add(governance_config.min_transaction_hold_up_time as i64)
|
|
||||||
< current_unix_timestamp
|
|
||||||
{
|
|
||||||
Err(GovernanceError::ProposalVotingTimeExpired.into())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProposalState::Draft
|
|
||||||
| ProposalState::Executing
|
|
||||||
| ProposalState::ExecutingWithErrors
|
|
||||||
| ProposalState::Completed
|
|
||||||
| ProposalState::Cancelled
|
|
||||||
| ProposalState::SigningOff
|
|
||||||
| ProposalState::Defeated
|
|
||||||
| ProposalState::Vetoed => Err(GovernanceError::InvalidStateCannotVote.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Expected vote end time determined by the configured max_voting_time period
|
|
||||||
pub fn expected_vote_end_time(&self, config: &GovernanceConfig) -> UnixTimestamp {
|
|
||||||
self.voting_at
|
self.voting_at
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.checked_add(config.max_voting_time as i64)
|
.checked_add(config.max_voting_time as i64)
|
||||||
|
@ -355,7 +292,7 @@ impl ProposalV2 {
|
||||||
current_unix_timestamp: UnixTimestamp,
|
current_unix_timestamp: UnixTimestamp,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Check if we passed vote_end_time
|
// Check if we passed vote_end_time
|
||||||
self.expected_vote_end_time(config) < current_unix_timestamp
|
self.vote_end_time(config) < current_unix_timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if Proposal can be finalized
|
/// Checks if Proposal can be finalized
|
||||||
|
@ -387,7 +324,7 @@ impl ProposalV2 {
|
||||||
self.assert_can_finalize_vote(config, current_unix_timestamp)?;
|
self.assert_can_finalize_vote(config, current_unix_timestamp)?;
|
||||||
|
|
||||||
self.state = self.resolve_final_vote_state(max_voter_weight, vote_threshold)?;
|
self.state = self.resolve_final_vote_state(max_voter_weight, vote_threshold)?;
|
||||||
self.voting_completed_at = Some(self.expected_vote_end_time(config));
|
self.voting_completed_at = Some(self.vote_end_time(config));
|
||||||
|
|
||||||
// Capture vote params to correctly display historical results
|
// Capture vote params to correctly display historical results
|
||||||
self.max_vote_weight = Some(max_voter_weight);
|
self.max_vote_weight = Some(max_voter_weight);
|
||||||
|
@ -1715,7 +1652,7 @@ mod test {
|
||||||
// Assert
|
// Assert
|
||||||
assert_eq!(proposal.state,test_case.expected_finalized_state,"CASE: {:?}",test_case);
|
assert_eq!(proposal.state,test_case.expected_finalized_state,"CASE: {:?}",test_case);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(proposal.expected_vote_end_time(&governance_config)),
|
Some(proposal.vote_end_time(&governance_config)),
|
||||||
proposal.voting_completed_at
|
proposal.voting_completed_at
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -2290,11 +2227,9 @@ mod test {
|
||||||
let current_timestamp =
|
let current_timestamp =
|
||||||
proposal.voting_at.unwrap() + governance_config.max_voting_time as i64 + 1;
|
proposal.voting_at.unwrap() + governance_config.max_voting_time as i64 + 1;
|
||||||
|
|
||||||
let vote_kind = VoteKind::Electorate;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let err = proposal
|
let err = proposal
|
||||||
.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp)
|
.assert_can_cast_vote(&governance_config, current_timestamp)
|
||||||
.err()
|
.err()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -2312,62 +2247,13 @@ mod test {
|
||||||
let current_timestamp =
|
let current_timestamp =
|
||||||
proposal.voting_at.unwrap() + governance_config.max_voting_time as i64;
|
proposal.voting_at.unwrap() + governance_config.max_voting_time as i64;
|
||||||
|
|
||||||
let vote_kind = VoteKind::Electorate;
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let result =
|
let result = proposal.assert_can_cast_vote(&governance_config, current_timestamp);
|
||||||
proposal.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp);
|
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
assert_eq!(result, Ok(()));
|
assert_eq!(result, Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_assert_can_cast_veto_vote_for_voting_proposal_within_hold_up_time() {
|
|
||||||
// Arrange
|
|
||||||
let mut proposal = create_test_proposal();
|
|
||||||
proposal.state = ProposalState::Voting;
|
|
||||||
let governance_config = create_test_governance_config();
|
|
||||||
|
|
||||||
let current_timestamp = proposal.voting_at.unwrap()
|
|
||||||
+ governance_config.max_voting_time as i64
|
|
||||||
+ governance_config.min_transaction_hold_up_time as i64;
|
|
||||||
|
|
||||||
let vote_kind = VoteKind::Veto;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let result =
|
|
||||||
proposal.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(result, Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_assert_can_cast_veto_vote_for_voting_proposal_with_cannot_cast_after_hold_up_time_error(
|
|
||||||
) {
|
|
||||||
// Arrange
|
|
||||||
let mut proposal = create_test_proposal();
|
|
||||||
proposal.state = ProposalState::Voting;
|
|
||||||
let governance_config = create_test_governance_config();
|
|
||||||
|
|
||||||
let current_timestamp = proposal.voting_at.unwrap()
|
|
||||||
+ governance_config.max_voting_time as i64
|
|
||||||
+ governance_config.min_transaction_hold_up_time as i64
|
|
||||||
+ 1;
|
|
||||||
|
|
||||||
let vote_kind = VoteKind::Veto;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let err = proposal
|
|
||||||
.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp)
|
|
||||||
.err()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(err, GovernanceError::ProposalVotingTimeExpired.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_assert_valid_vote_with_deny_vote_for_survey_only_proposal_error() {
|
pub fn test_assert_valid_vote_with_deny_vote_for_survey_only_proposal_error() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
@ -2384,52 +2270,6 @@ mod test {
|
||||||
assert_eq!(result, Err(GovernanceError::InvalidVote.into()));
|
assert_eq!(result, Err(GovernanceError::InvalidVote.into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_assert_can_cast_veto_vote_for_succeeded_proposal_within_hold_up_time() {
|
|
||||||
// Arrange
|
|
||||||
let mut proposal = create_test_proposal();
|
|
||||||
proposal.state = ProposalState::Succeeded;
|
|
||||||
|
|
||||||
let governance_config = create_test_governance_config();
|
|
||||||
|
|
||||||
let current_timestamp = proposal.voting_completed_at.unwrap()
|
|
||||||
+ governance_config.min_transaction_hold_up_time as i64;
|
|
||||||
|
|
||||||
let vote_kind = VoteKind::Veto;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let result =
|
|
||||||
proposal.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(result, Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
pub fn test_assert_can_cast_veto_vote_for_succeeded_proposal_with_cannot_cast_after_hold_up_time_error(
|
|
||||||
) {
|
|
||||||
// Arrange
|
|
||||||
let mut proposal = create_test_proposal();
|
|
||||||
proposal.state = ProposalState::Succeeded;
|
|
||||||
|
|
||||||
let governance_config = create_test_governance_config();
|
|
||||||
|
|
||||||
let current_timestamp = proposal.voting_completed_at.unwrap()
|
|
||||||
+ governance_config.min_transaction_hold_up_time as i64
|
|
||||||
+ 1;
|
|
||||||
|
|
||||||
let vote_kind = VoteKind::Veto;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
let err = proposal
|
|
||||||
.assert_can_cast_vote(&vote_kind, &governance_config, current_timestamp)
|
|
||||||
.err()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
assert_eq!(err, GovernanceError::ProposalVotingTimeExpired.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_assert_valid_vote_with_too_many_options_error() {
|
pub fn test_assert_valid_vote_with_too_many_options_error() {
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
@ -82,7 +82,7 @@ async fn test_finalize_vote_to_succeeded() {
|
||||||
|
|
||||||
assert_eq!(proposal_account.state, ProposalState::Succeeded);
|
assert_eq!(proposal_account.state, ProposalState::Succeeded);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(proposal_account.expected_vote_end_time(&governance_cookie.account.config)),
|
Some(proposal_account.vote_end_time(&governance_cookie.account.config)),
|
||||||
proposal_account.voting_completed_at
|
proposal_account.voting_completed_at
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ async fn test_finalize_council_vote() {
|
||||||
|
|
||||||
assert_eq!(proposal_account.state, ProposalState::Succeeded);
|
assert_eq!(proposal_account.state, ProposalState::Succeeded);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(proposal_account.expected_vote_end_time(&governance_cookie.account.config)),
|
Some(proposal_account.vote_end_time(&governance_cookie.account.config)),
|
||||||
proposal_account.voting_completed_at
|
proposal_account.voting_completed_at
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -968,66 +968,3 @@ async fn test_veto_vote_with_community_max_voter_weight_addin_and_veto_not_tippe
|
||||||
|
|
||||||
assert_eq!(proposal_account.state, ProposalState::Voting);
|
assert_eq!(proposal_account.state, ProposalState::Voting);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_cast_council_veto_vote_within_hold_up_time() {
|
|
||||||
// Arrange
|
|
||||||
let mut governance_test = GovernanceProgramTest::start_new().await;
|
|
||||||
|
|
||||||
let realm_cookie = governance_test.with_realm().await;
|
|
||||||
let governed_account_cookie = governance_test.with_governed_account().await;
|
|
||||||
|
|
||||||
let token_owner_record_cookie = governance_test
|
|
||||||
.with_council_token_deposit(&realm_cookie)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Mint extra council tokens for total supply of 120
|
|
||||||
governance_test.mint_council_tokens(&realm_cookie, 20).await;
|
|
||||||
|
|
||||||
let mut governance_cookie = governance_test
|
|
||||||
.with_governance(
|
|
||||||
&realm_cookie,
|
|
||||||
&governed_account_cookie,
|
|
||||||
&token_owner_record_cookie,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let proposal_owner_record_cookie = governance_test
|
|
||||||
.with_community_token_deposit(&realm_cookie)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let proposal_cookie = governance_test
|
|
||||||
.with_signed_off_proposal(&proposal_owner_record_cookie, &mut governance_cookie)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
governance_test
|
|
||||||
.with_cast_yes_no_vote(
|
|
||||||
&proposal_cookie,
|
|
||||||
&proposal_owner_record_cookie,
|
|
||||||
YesNoVote::Yes,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Move the clock within the hold up time period
|
|
||||||
governance_test.advance_clock().await;
|
|
||||||
|
|
||||||
// Act
|
|
||||||
|
|
||||||
governance_test
|
|
||||||
.with_cast_vote(&proposal_cookie, &token_owner_record_cookie, Vote::Veto)
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
|
|
||||||
let proposal_account = governance_test
|
|
||||||
.get_proposal_account(&proposal_cookie.address)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(proposal_account.state, ProposalState::Vetoed);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue