From a35d98ebf0ef9f09a2c030d563b9383c5e81af44 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Mon, 14 Feb 2022 09:07:52 +0800 Subject: [PATCH 1/9] Adds the ability to delegate vote setting to a different address --- .../instructions/create_gauge_delegation.rs | 50 +++++++++++++++++++ .../instructions/delegated_gauge_set_vote.rs | 38 ++++++++++++++ .../delegation_set_vote_setter.rs | 44 ++++++++++++++++ .../gauge/src/instructions/gauge_set_vote.rs | 13 +++-- programs/gauge/src/instructions/mod.rs | 6 +++ programs/gauge/src/lib.rs | 29 ++++++++++- programs/gauge/src/state.rs | 11 ++++ 7 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 programs/gauge/src/instructions/create_gauge_delegation.rs create mode 100644 programs/gauge/src/instructions/delegated_gauge_set_vote.rs create mode 100644 programs/gauge/src/instructions/delegation_set_vote_setter.rs diff --git a/programs/gauge/src/instructions/create_gauge_delegation.rs b/programs/gauge/src/instructions/create_gauge_delegation.rs new file mode 100644 index 0000000..f98b6b8 --- /dev/null +++ b/programs/gauge/src/instructions/create_gauge_delegation.rs @@ -0,0 +1,50 @@ +//! Creates a [GaugeDelegation]. + +use locked_voter::Escrow; +use vipers::assert_keys_eq; + +use crate::*; + +/// Accounts for [gauge::create_gauge_delegation]. +#[derive(Accounts)] +#[instruction(bump: u8)] +pub struct CreateGaugeDelegation<'info> { + /// The [Gauge] to be created. + #[account( + init, + seeds = [ + b"GaugeDelegation".as_ref(), + gauge_voter.key().as_ref(), + ], + bump = bump, + payer = payer + )] + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, + + /// [GaugeVoter]. + pub gauge_voter: Account<'info, GaugeVoter>, + + /// [Escrow]. + pub escrow: Account<'info, Escrow>, + + /// Payer. + #[account(mut)] + pub payer: Signer<'info>, + + /// System program. + pub system_program: Program<'info, System>, +} + +pub fn handler(ctx: Context) -> ProgramResult { + let gauge_delegation = &mut ctx.accounts.gauge_delegation.load_init()?; + gauge_delegation.gauge_voter = ctx.accounts.gauge_voter.key(); + gauge_delegation.vote_setter = Pubkey::default(); + Ok(()) +} + +impl<'info> Validate<'info> for CreateGaugeDelegation<'info> { + fn validate(&self) -> ProgramResult { + assert_keys_eq!(self.escrow, self.gauge_voter.escrow); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/delegated_gauge_set_vote.rs b/programs/gauge/src/instructions/delegated_gauge_set_vote.rs new file mode 100644 index 0000000..dfed8d1 --- /dev/null +++ b/programs/gauge/src/instructions/delegated_gauge_set_vote.rs @@ -0,0 +1,38 @@ +//! Votes for a [Gauge] using the [GaugeDelegation]. + +use vipers::assert_keys_eq; + +use crate::*; + +/// Accounts for [gauge::delegated_gauge_set_vote]. +#[derive(Accounts)] +pub struct DelegatedGaugeSetVote<'info> { + /// Common accounts for setting gauge votes. + /// The [GaugeSetVote::vote_delegate] is overloaded to be the [GaugeDelegation::vote_setter]. + pub common: GaugeSetVote<'info>, + /// The [GaugeDelegation]. + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, + /// [GaugeDelegation::vote_setter]. + pub vote_setter: Signer<'info>, +} + +impl<'info> DelegatedGaugeSetVote<'info> { + /// Sets a non-zero vote. + fn set_vote(&mut self, weight: u32) -> ProgramResult { + self.common.set_vote(weight) + } +} + +pub fn handler(ctx: Context, weight: u32) -> ProgramResult { + ctx.accounts.set_vote(weight) +} + +impl<'info> Validate<'info> for DelegatedGaugeSetVote<'info> { + fn validate(&self) -> ProgramResult { + let delegation = self.gauge_delegation.load()?; + self.common.validate_delegated()?; + assert_keys_eq!(self.common.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.common.vote_delegate, delegation.vote_setter); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/delegation_set_vote_setter.rs b/programs/gauge/src/instructions/delegation_set_vote_setter.rs new file mode 100644 index 0000000..69750a4 --- /dev/null +++ b/programs/gauge/src/instructions/delegation_set_vote_setter.rs @@ -0,0 +1,44 @@ +//! Votes for a [Gauge]. + +use locked_voter::Escrow; + +use crate::*; + +/// Accounts for [gauge::delegated_gauge_set_vote]. +#[derive(Accounts)] +pub struct DelegationSetVoteSetter<'info> { + /// The [GaugeDelegation]. + #[account(mut)] + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, + /// [GaugeVoter]. + pub gauge_voter: Account<'info, GaugeVoter>, + /// The [Escrow]. + pub escrow: Account<'info, Escrow>, + /// [Escrow::vote_delegate]. + pub escrow_vote_delegate: Signer<'info>, + /// The new [GaugeDelegation::vote_setter]. + pub new_vote_setter: UncheckedAccount<'info>, +} + +impl<'info> DelegationSetVoteSetter<'info> { + /// Sets a non-zero vote. + fn set_vote_setter(&self) -> ProgramResult { + let gauge_delegation = &mut self.gauge_delegation.load_mut()?; + gauge_delegation.vote_setter = self.new_vote_setter.key(); + Ok(()) + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.set_vote_setter() +} + +impl<'info> Validate<'info> for DelegationSetVoteSetter<'info> { + fn validate(&self) -> ProgramResult { + let delegation = self.gauge_delegation.load()?; + assert_keys_eq!(self.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.escrow, self.gauge_voter.escrow); + assert_keys_eq!(self.escrow_vote_delegate, self.escrow.vote_delegate); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/gauge_set_vote.rs b/programs/gauge/src/instructions/gauge_set_vote.rs index 43dacc5..d5eb349 100644 --- a/programs/gauge/src/instructions/gauge_set_vote.rs +++ b/programs/gauge/src/instructions/gauge_set_vote.rs @@ -36,7 +36,7 @@ impl<'info> GaugeSetVote<'info> { } /// Sets a non-zero vote. - fn set_vote(&mut self, weight: u32) -> ProgramResult { + pub(crate) fn set_vote(&mut self, weight: u32) -> ProgramResult { if weight != 0 { invariant!(!self.gauge.is_disabled, CannotVoteGaugeDisabled); } @@ -80,13 +80,20 @@ pub fn handler(ctx: Context, weight: u32) -> ProgramResult { ctx.accounts.set_vote(weight) } -impl<'info> Validate<'info> for GaugeSetVote<'info> { - fn validate(&self) -> ProgramResult { +impl<'info> GaugeSetVote<'info> { + pub(crate) fn validate_delegated(&self) -> ProgramResult { assert_keys_eq!(self.gaugemeister, self.gauge.gaugemeister); assert_keys_eq!(self.gauge, self.gauge_vote.gauge); assert_keys_eq!(self.gauge_voter, self.gauge_vote.gauge_voter); assert_keys_eq!(self.escrow, self.gauge_voter.escrow); + Ok(()) + } +} + +impl<'info> Validate<'info> for GaugeSetVote<'info> { + fn validate(&self) -> ProgramResult { + self.validate_delegated()?; assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); Ok(()) } diff --git a/programs/gauge/src/instructions/mod.rs b/programs/gauge/src/instructions/mod.rs index f1278fd..1ea3e1b 100644 --- a/programs/gauge/src/instructions/mod.rs +++ b/programs/gauge/src/instructions/mod.rs @@ -2,9 +2,12 @@ pub mod create_epoch_gauge; pub mod create_gauge; +pub mod create_gauge_delegation; pub mod create_gauge_vote; pub mod create_gauge_voter; pub mod create_gaugemeister; +pub mod delegated_gauge_set_vote; +pub mod delegation_set_vote_setter; pub mod gauge_commit_vote; pub mod gauge_disable; pub mod gauge_enable; @@ -18,9 +21,12 @@ pub mod trigger_next_epoch; pub use create_epoch_gauge::*; pub use create_gauge::*; +pub use create_gauge_delegation::*; pub use create_gauge_vote::*; pub use create_gauge_voter::*; pub use create_gaugemeister::*; +pub use delegated_gauge_set_vote::*; +pub use delegation_set_vote_setter::*; pub use gauge_commit_vote::*; pub use gauge_disable::*; pub use gauge_enable::*; diff --git a/programs/gauge/src/lib.rs b/programs/gauge/src/lib.rs index 7834113..c2a5ef9 100644 --- a/programs/gauge/src/lib.rs +++ b/programs/gauge/src/lib.rs @@ -10,7 +10,7 @@ #![deny(clippy::unwrap_used)] use anchor_lang::prelude::*; -use vipers::Validate; +use vipers::prelude::*; mod instructions; mod macros; @@ -145,6 +145,33 @@ pub mod gauge { ) -> ProgramResult { set_gaugemeister_params::handler(ctx, new_epoch_duration_seconds, new_foreman) } + + // Delegation + + /// Creates a [GaugeDelegation] for a [GaugeVoter]. Permissionless. + #[access_control(ctx.accounts.validate())] + pub fn create_gauge_delegation( + ctx: Context, + _bump: u8, + ) -> ProgramResult { + create_gauge_delegation::handler(ctx) + } + + /// Sets the vote of a [Gauge] using the [GaugeDelegation]. + /// Only the [GaugeDelegation::vote_setter] may call this. + #[access_control(ctx.accounts.validate())] + pub fn delegated_gauge_set_vote( + ctx: Context, + weight: u32, + ) -> ProgramResult { + delegated_gauge_set_vote::handler(ctx, weight) + } + + /// Sets the [GaugeDelegation::vote_setter]. Only the [Escrow::vote_delegate] may call this. + #[access_control(ctx.accounts.validate())] + pub fn delegation_set_vote_setter(ctx: Context) -> ProgramResult { + delegation_set_vote_setter::handler(ctx) + } } /// Errors. diff --git a/programs/gauge/src/state.rs b/programs/gauge/src/state.rs index e360f28..cd512b6 100644 --- a/programs/gauge/src/state.rs +++ b/programs/gauge/src/state.rs @@ -171,3 +171,14 @@ impl EpochGaugeVote { ) } } + +/// Enables delegating vote allocations to another address. +#[account(zero_copy)] +#[derive(Debug, Default)] +pub struct GaugeDelegation { + /// The [GaugeVoter]. + pub gauge_voter: Pubkey, + + /// Address which can call [delegate_gauge_set_vote] on behalf of the [Self::gauge_voter]. + pub vote_setter: Pubkey, +} From 806c039f8ee3797782f7f5fca4b6bbb4fc84bb57 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Mon, 14 Feb 2022 09:16:38 +0800 Subject: [PATCH 2/9] Add delegation of gauge_revert_vote --- .../instructions/create_gauge_delegation.rs | 1 + .../delegated_gauge_revert_vote.rs | 36 ++++++++++ .../instructions/delegated_gauge_set_vote.rs | 4 +- .../src/instructions/gauge_revert_vote.rs | 65 +++++++++++-------- .../gauge/src/instructions/gauge_set_vote.rs | 4 +- programs/gauge/src/instructions/mod.rs | 2 + programs/gauge/src/lib.rs | 7 ++ programs/gauge/src/state.rs | 5 +- 8 files changed, 91 insertions(+), 33 deletions(-) create mode 100644 programs/gauge/src/instructions/delegated_gauge_revert_vote.rs diff --git a/programs/gauge/src/instructions/create_gauge_delegation.rs b/programs/gauge/src/instructions/create_gauge_delegation.rs index f98b6b8..8b4e8da 100644 --- a/programs/gauge/src/instructions/create_gauge_delegation.rs +++ b/programs/gauge/src/instructions/create_gauge_delegation.rs @@ -39,6 +39,7 @@ pub fn handler(ctx: Context) -> ProgramResult { let gauge_delegation = &mut ctx.accounts.gauge_delegation.load_init()?; gauge_delegation.gauge_voter = ctx.accounts.gauge_voter.key(); gauge_delegation.vote_setter = Pubkey::default(); + gauge_delegation.vote_committer = Pubkey::default(); Ok(()) } diff --git a/programs/gauge/src/instructions/delegated_gauge_revert_vote.rs b/programs/gauge/src/instructions/delegated_gauge_revert_vote.rs new file mode 100644 index 0000000..69dd317 --- /dev/null +++ b/programs/gauge/src/instructions/delegated_gauge_revert_vote.rs @@ -0,0 +1,36 @@ +//! Votes for a [Gauge] using the [GaugeDelegation]. + +use vipers::assert_keys_eq; + +use crate::*; + +/// Accounts for [gauge::delegated_gauge_revert_vote]. +#[derive(Accounts)] +pub struct DelegatedGaugeRevertVote<'info> { + /// Common accounts for setting gauge votes. + /// The [GaugeRevertVote::vote_delegate] is overloaded to be the [GaugeDelegation::vote_setter]. + pub common: GaugeRevertVote<'info>, + /// The [GaugeDelegation]. + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, +} + +impl<'info> DelegatedGaugeRevertVote<'info> { + /// Sets a non-zero vote. + fn revert_vote(&mut self) -> ProgramResult { + self.common.revert_vote() + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.revert_vote() +} + +impl<'info> Validate<'info> for DelegatedGaugeRevertVote<'info> { + fn validate(&self) -> ProgramResult { + let delegation = self.gauge_delegation.load()?; + self.common.validate_without_delegate()?; + assert_keys_eq!(self.common.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.common.vote_delegate, delegation.vote_setter); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/delegated_gauge_set_vote.rs b/programs/gauge/src/instructions/delegated_gauge_set_vote.rs index dfed8d1..49c85a5 100644 --- a/programs/gauge/src/instructions/delegated_gauge_set_vote.rs +++ b/programs/gauge/src/instructions/delegated_gauge_set_vote.rs @@ -12,8 +12,6 @@ pub struct DelegatedGaugeSetVote<'info> { pub common: GaugeSetVote<'info>, /// The [GaugeDelegation]. pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, - /// [GaugeDelegation::vote_setter]. - pub vote_setter: Signer<'info>, } impl<'info> DelegatedGaugeSetVote<'info> { @@ -30,7 +28,7 @@ pub fn handler(ctx: Context, weight: u32) -> ProgramResul impl<'info> Validate<'info> for DelegatedGaugeSetVote<'info> { fn validate(&self) -> ProgramResult { let delegation = self.gauge_delegation.load()?; - self.common.validate_delegated()?; + self.common.validate_without_delegate()?; assert_keys_eq!(self.common.gauge_voter, delegation.gauge_voter); assert_keys_eq!(self.common.vote_delegate, delegation.vote_setter); Ok(()) diff --git a/programs/gauge/src/instructions/gauge_revert_vote.rs b/programs/gauge/src/instructions/gauge_revert_vote.rs index 367fb17..8ac1c56 100644 --- a/programs/gauge/src/instructions/gauge_revert_vote.rs +++ b/programs/gauge/src/instructions/gauge_revert_vote.rs @@ -33,32 +33,8 @@ pub struct GaugeRevertVote<'info> { pub payer: Signer<'info>, } -pub fn handler(ctx: Context) -> ProgramResult { - let epoch_gauge = &mut ctx.accounts.epoch_gauge; - let epoch_voter = &mut ctx.accounts.epoch_gauge_voter; - let epoch_vote = &mut ctx.accounts.epoch_gauge_vote; - - let power_subtract = epoch_vote.allocated_power; - epoch_voter.allocated_power = - unwrap_int!(epoch_voter.allocated_power.checked_sub(power_subtract)); - epoch_gauge.total_power = unwrap_int!(epoch_gauge.total_power.checked_sub(power_subtract)); - - emit!(RevertGaugeVoteEvent { - gaugemeister: ctx.accounts.gaugemeister.key(), - gauge: ctx.accounts.gauge.key(), - quarry: ctx.accounts.gauge.quarry, - gauge_voter_owner: ctx.accounts.gauge_voter.owner, - subtracted_power: power_subtract, - voting_epoch: epoch_voter.voting_epoch, - updated_allocated_power: epoch_voter.allocated_power, - updated_total_power: epoch_gauge.total_power, - }); - - Ok(()) -} - -impl<'info> Validate<'info> for GaugeRevertVote<'info> { - fn validate(&self) -> ProgramResult { +impl<'info> GaugeRevertVote<'info> { + pub(crate) fn validate_without_delegate(&self) -> ProgramResult { assert_keys_eq!(self.gaugemeister, self.gauge.gaugemeister); let voting_epoch = self.gaugemeister.voting_epoch()?; invariant!( @@ -81,10 +57,45 @@ impl<'info> Validate<'info> for GaugeRevertVote<'info> { assert_keys_eq!(epoch_gauge_vote_key, self.epoch_gauge_vote); assert_keys_eq!(self.escrow, self.gauge_voter.escrow); - assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); Ok(()) } + + pub(crate) fn revert_vote(&mut self) -> ProgramResult { + let epoch_gauge = &mut self.epoch_gauge; + let epoch_voter = &mut self.epoch_gauge_voter; + let epoch_vote = &mut self.epoch_gauge_vote; + + let power_subtract = epoch_vote.allocated_power; + epoch_voter.allocated_power = + unwrap_int!(epoch_voter.allocated_power.checked_sub(power_subtract)); + epoch_gauge.total_power = unwrap_int!(epoch_gauge.total_power.checked_sub(power_subtract)); + + emit!(RevertGaugeVoteEvent { + gaugemeister: self.gaugemeister.key(), + gauge: self.gauge.key(), + quarry: self.gauge.quarry, + gauge_voter_owner: self.gauge_voter.owner, + subtracted_power: power_subtract, + voting_epoch: epoch_voter.voting_epoch, + updated_allocated_power: epoch_voter.allocated_power, + updated_total_power: epoch_gauge.total_power, + }); + + Ok(()) + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.revert_vote() +} + +impl<'info> Validate<'info> for GaugeRevertVote<'info> { + fn validate(&self) -> ProgramResult { + self.validate_without_delegate()?; + assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); + Ok(()) + } } /// Event called in [gauge::gauge_revert_vote]. diff --git a/programs/gauge/src/instructions/gauge_set_vote.rs b/programs/gauge/src/instructions/gauge_set_vote.rs index d5eb349..50cedfc 100644 --- a/programs/gauge/src/instructions/gauge_set_vote.rs +++ b/programs/gauge/src/instructions/gauge_set_vote.rs @@ -81,7 +81,7 @@ pub fn handler(ctx: Context, weight: u32) -> ProgramResult { } impl<'info> GaugeSetVote<'info> { - pub(crate) fn validate_delegated(&self) -> ProgramResult { + pub(crate) fn validate_without_delegate(&self) -> ProgramResult { assert_keys_eq!(self.gaugemeister, self.gauge.gaugemeister); assert_keys_eq!(self.gauge, self.gauge_vote.gauge); assert_keys_eq!(self.gauge_voter, self.gauge_vote.gauge_voter); @@ -93,7 +93,7 @@ impl<'info> GaugeSetVote<'info> { impl<'info> Validate<'info> for GaugeSetVote<'info> { fn validate(&self) -> ProgramResult { - self.validate_delegated()?; + self.validate_without_delegate()?; assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); Ok(()) } diff --git a/programs/gauge/src/instructions/mod.rs b/programs/gauge/src/instructions/mod.rs index 1ea3e1b..a248834 100644 --- a/programs/gauge/src/instructions/mod.rs +++ b/programs/gauge/src/instructions/mod.rs @@ -6,6 +6,7 @@ pub mod create_gauge_delegation; pub mod create_gauge_vote; pub mod create_gauge_voter; pub mod create_gaugemeister; +pub mod delegated_gauge_revert_vote; pub mod delegated_gauge_set_vote; pub mod delegation_set_vote_setter; pub mod gauge_commit_vote; @@ -25,6 +26,7 @@ pub use create_gauge_delegation::*; pub use create_gauge_vote::*; pub use create_gauge_voter::*; pub use create_gaugemeister::*; +pub use delegated_gauge_revert_vote::*; pub use delegated_gauge_set_vote::*; pub use delegation_set_vote_setter::*; pub use gauge_commit_vote::*; diff --git a/programs/gauge/src/lib.rs b/programs/gauge/src/lib.rs index c2a5ef9..0151353 100644 --- a/programs/gauge/src/lib.rs +++ b/programs/gauge/src/lib.rs @@ -167,6 +167,13 @@ pub mod gauge { delegated_gauge_set_vote::handler(ctx, weight) } + /// Reverts a committed vote of a [Gauge] using the [GaugeDelegation]. + /// Only the [GaugeDelegation::vote_setter] may call this. + #[access_control(ctx.accounts.validate())] + pub fn delegated_gauge_revert_vote(ctx: Context) -> ProgramResult { + delegated_gauge_revert_vote::handler(ctx) + } + /// Sets the [GaugeDelegation::vote_setter]. Only the [Escrow::vote_delegate] may call this. #[access_control(ctx.accounts.validate())] pub fn delegation_set_vote_setter(ctx: Context) -> ProgramResult { diff --git a/programs/gauge/src/state.rs b/programs/gauge/src/state.rs index cd512b6..9e12106 100644 --- a/programs/gauge/src/state.rs +++ b/programs/gauge/src/state.rs @@ -179,6 +179,9 @@ pub struct GaugeDelegation { /// The [GaugeVoter]. pub gauge_voter: Pubkey, - /// Address which can call [delegate_gauge_set_vote] on behalf of the [Self::gauge_voter]. + /// Address which can call [gauge::delegated_gauge_set_vote] on behalf of the [Self::gauge_voter]. pub vote_setter: Pubkey, + + /// UNIMPLEMENTED: account which is allowed to commit votes on behalf of the gauge. + pub vote_committer: Pubkey, } From 97d21113daf2fd8f0fe1a387529c592ed5721c00 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Mon, 14 Feb 2022 09:21:33 +0800 Subject: [PATCH 3/9] set vote committer --- .../delegation_set_vote_committer.rs | 44 +++++++++++++++++++ .../delegation_set_vote_setter.rs | 4 +- programs/gauge/src/instructions/mod.rs | 2 + programs/gauge/src/lib.rs | 10 ++++- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 programs/gauge/src/instructions/delegation_set_vote_committer.rs diff --git a/programs/gauge/src/instructions/delegation_set_vote_committer.rs b/programs/gauge/src/instructions/delegation_set_vote_committer.rs new file mode 100644 index 0000000..2c3d99f --- /dev/null +++ b/programs/gauge/src/instructions/delegation_set_vote_committer.rs @@ -0,0 +1,44 @@ +//! Sets the [GaugeDelegation::vote_committer]. + +use locked_voter::Escrow; + +use crate::*; + +/// Accounts for [gauge::delegation_set_vote_committer]. +#[derive(Accounts)] +pub struct DelegationSetVoteCommitter<'info> { + /// The [GaugeDelegation]. + #[account(mut)] + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, + /// [GaugeVoter]. + pub gauge_voter: Account<'info, GaugeVoter>, + /// The [Escrow]. + pub escrow: Account<'info, Escrow>, + /// [Escrow::vote_delegate]. + pub escrow_vote_delegate: Signer<'info>, + /// The new [GaugeDelegation::vote_committer]. + pub new_vote_committer: UncheckedAccount<'info>, +} + +impl<'info> DelegationSetVoteCommitter<'info> { + /// Sets a non-zero vote. + fn set_vote_committer(&self) -> ProgramResult { + let gauge_delegation = &mut self.gauge_delegation.load_mut()?; + gauge_delegation.vote_committer = self.new_vote_committer.key(); + Ok(()) + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.set_vote_committer() +} + +impl<'info> Validate<'info> for DelegationSetVoteCommitter<'info> { + fn validate(&self) -> ProgramResult { + let delegation = self.gauge_delegation.load()?; + assert_keys_eq!(self.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.escrow, self.gauge_voter.escrow); + assert_keys_eq!(self.escrow_vote_delegate, self.escrow.vote_delegate); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/delegation_set_vote_setter.rs b/programs/gauge/src/instructions/delegation_set_vote_setter.rs index 69750a4..6558c66 100644 --- a/programs/gauge/src/instructions/delegation_set_vote_setter.rs +++ b/programs/gauge/src/instructions/delegation_set_vote_setter.rs @@ -1,10 +1,10 @@ -//! Votes for a [Gauge]. +//! Sets the [GaugeDelegation::vote_setter]. use locked_voter::Escrow; use crate::*; -/// Accounts for [gauge::delegated_gauge_set_vote]. +/// Accounts for [gauge::delegation_set_vote_committer]. #[derive(Accounts)] pub struct DelegationSetVoteSetter<'info> { /// The [GaugeDelegation]. diff --git a/programs/gauge/src/instructions/mod.rs b/programs/gauge/src/instructions/mod.rs index a248834..1a0d78e 100644 --- a/programs/gauge/src/instructions/mod.rs +++ b/programs/gauge/src/instructions/mod.rs @@ -8,6 +8,7 @@ pub mod create_gauge_voter; pub mod create_gaugemeister; pub mod delegated_gauge_revert_vote; pub mod delegated_gauge_set_vote; +pub mod delegation_set_vote_committer; pub mod delegation_set_vote_setter; pub mod gauge_commit_vote; pub mod gauge_disable; @@ -28,6 +29,7 @@ pub use create_gauge_voter::*; pub use create_gaugemeister::*; pub use delegated_gauge_revert_vote::*; pub use delegated_gauge_set_vote::*; +pub use delegation_set_vote_committer::*; pub use delegation_set_vote_setter::*; pub use gauge_commit_vote::*; pub use gauge_disable::*; diff --git a/programs/gauge/src/lib.rs b/programs/gauge/src/lib.rs index 0151353..5cc5861 100644 --- a/programs/gauge/src/lib.rs +++ b/programs/gauge/src/lib.rs @@ -174,11 +174,19 @@ pub mod gauge { delegated_gauge_revert_vote::handler(ctx) } - /// Sets the [GaugeDelegation::vote_setter]. Only the [Escrow::vote_delegate] may call this. + /// Sets the [GaugeDelegation::vote_setter]. Only the [locked_voter::Escrow::vote_delegate] may call this. #[access_control(ctx.accounts.validate())] pub fn delegation_set_vote_setter(ctx: Context) -> ProgramResult { delegation_set_vote_setter::handler(ctx) } + + /// Sets the [GaugeDelegation::vote_committer]. Only the [locked_voter::Escrow::vote_delegate] may call this. + #[access_control(ctx.accounts.validate())] + pub fn delegation_set_vote_committer( + ctx: Context, + ) -> ProgramResult { + delegation_set_vote_committer::handler(ctx) + } } /// Errors. From 0d72400ee6f65982710cd15fd4fc26e6aec04ae4 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Mon, 14 Feb 2022 22:46:16 +0800 Subject: [PATCH 4/9] adds checked vote commitment and vote commitment delegation --- .../delegated_gauge_commit_vote.rs | 35 +++++ .../src/instructions/gauge_commit_vote_v2.rs | 138 ++++++++++++++++++ programs/gauge/src/instructions/mod.rs | 4 + programs/gauge/src/lib.rs | 14 ++ 4 files changed, 191 insertions(+) create mode 100644 programs/gauge/src/instructions/delegated_gauge_commit_vote.rs create mode 100644 programs/gauge/src/instructions/gauge_commit_vote_v2.rs diff --git a/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs b/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs new file mode 100644 index 0000000..700f129 --- /dev/null +++ b/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs @@ -0,0 +1,35 @@ +//! Votes for a [Gauge] using the [GaugeDelegation]. + +use vipers::assert_keys_eq; + +use crate::*; + +/// Accounts for [gauge::delegated_gauge_set_vote]. +#[derive(Accounts)] +pub struct DelegatedGaugeCommitVote<'info> { + /// Common accounts for setting gauge votes. + /// The [GaugeCommitVoteV2::vote_delegate] is overloaded to be the [GaugeDelegation::vote_committer]. + pub common: GaugeCommitVoteV2<'info>, + /// The [GaugeDelegation]. + pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, +} + +impl<'info> DelegatedGaugeCommitVote<'info> { + fn commit_vote(&mut self) -> ProgramResult { + self.common.commit_vote() + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.commit_vote() +} + +impl<'info> Validate<'info> for DelegatedGaugeCommitVote<'info> { + fn validate(&self) -> ProgramResult { + let delegation = self.gauge_delegation.load()?; + self.common.validate_without_delegate()?; + assert_keys_eq!(self.common.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.common.vote_delegate, delegation.vote_committer); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs new file mode 100644 index 0000000..961544a --- /dev/null +++ b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs @@ -0,0 +1,138 @@ +//! Commits the votes for a [Gauge], requiring permission. +//! The old commitment mechanism will be deprecated. + +use num_traits::ToPrimitive; +use vipers::{assert_keys_eq, invariant, unwrap_int}; + +use crate::*; + +/// Accounts for [gauge::gauge_commit_vote]. +#[derive(Accounts)] +#[instruction(vote_bump: u8)] +pub struct GaugeCommitVoteV2<'info> { + /// The [Gaugemeister]. + pub gaugemeister: Account<'info, Gaugemeister>, + /// The [Gauge]. + pub gauge: Account<'info, Gauge>, + /// The [GaugeVoter]. + pub gauge_voter: Account<'info, GaugeVoter>, + /// The [GaugeVote] containing the vote weights. + pub gauge_vote: Account<'info, GaugeVote>, + + /// The [EpochGauge]. + #[account(mut)] + pub epoch_gauge: Account<'info, EpochGauge>, + /// The [EpochGaugeVoter]. + #[account(mut)] + pub epoch_gauge_voter: Account<'info, EpochGaugeVoter>, + + /// The [EpochGaugeVote] to create. + #[account( + init, + seeds = [ + b"EpochGaugeVote", + gauge_vote.key().as_ref(), + epoch_gauge_voter.voting_epoch.to_le_bytes().as_ref(), + ], + bump = vote_bump, + payer = payer + )] + pub epoch_gauge_vote: Account<'info, EpochGaugeVote>, + + /// The escrow. + pub escrow: Account<'info, locked_voter::Escrow>, + /// The [Escrow::vote_delegate]. + pub vote_delegate: Signer<'info>, + + /// Funder of the [EpochGaugeVote] to create. + #[account(mut)] + pub payer: Signer<'info>, + /// The [System] program. + pub system_program: Program<'info, System>, +} + +impl<'info> GaugeCommitVoteV2<'info> { + fn vote_shares_for_next_epoch(&self) -> Option { + if self.gauge_vote.weight == 0 { + return Some(0); + } + let power: u64 = self.epoch_gauge_voter.voting_power; + let total_shares = (power as u128) + .checked_mul(self.gauge_vote.weight.into())? + .checked_div(self.gauge_voter.total_weight.into())? + .to_u64()?; + msg!("power: {}, shares: {}", power, total_shares); + Some(total_shares) + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.commit_vote() +} + +impl<'info> GaugeCommitVoteV2<'info> { + pub(crate) fn commit_vote(&mut self) -> ProgramResult { + let next_vote_shares = unwrap_int!(self.vote_shares_for_next_epoch()); + // if zero vote shares, don't do anything + if next_vote_shares == 0 { + return Ok(()); + } + + let epoch_gauge = &mut self.epoch_gauge; + let epoch_voter = &mut self.epoch_gauge_voter; + let epoch_vote = &mut self.epoch_gauge_vote; + + epoch_voter.allocated_power = + unwrap_int!(epoch_voter.allocated_power.checked_add(next_vote_shares)); + epoch_vote.allocated_power = next_vote_shares; + + epoch_gauge.total_power = + unwrap_int!(epoch_gauge.total_power.checked_add(next_vote_shares)); + + emit!(CommitGaugeVoteEvent { + gaugemeister: self.gauge.gaugemeister, + gauge: self.gauge.key(), + quarry: self.gauge.quarry, + gauge_voter_owner: self.gauge_voter.owner, + vote_shares_for_next_epoch: next_vote_shares, + voting_epoch: epoch_voter.voting_epoch, + updated_allocated_power: epoch_voter.allocated_power, + updated_total_power: epoch_gauge.total_power, + }); + + Ok(()) + } + + pub(crate) fn validate_without_delegate(&self) -> ProgramResult { + assert_keys_eq!(self.gaugemeister, self.gauge.gaugemeister); + assert_keys_eq!(self.gauge, self.gauge_vote.gauge); + assert_keys_eq!(self.gauge_voter, self.gauge_vote.gauge_voter); + + assert_keys_eq!(self.epoch_gauge.gauge, self.gauge); + assert_keys_eq!(self.epoch_gauge_voter.gauge_voter, self.gauge_voter); + + invariant!(!self.gauge.is_disabled, CannotCommitGaugeDisabled); + invariant!( + self.epoch_gauge_voter.weight_change_seqno == self.gauge_voter.weight_change_seqno, + WeightSeqnoChanged + ); + + let voting_epoch = self.gaugemeister.voting_epoch()?; + invariant!( + self.epoch_gauge_voter.voting_epoch == voting_epoch, + EpochGaugeNotVoting + ); + + assert_keys_eq!(self.escrow, self.gauge_voter.escrow); + + Ok(()) + } +} + +impl<'info> Validate<'info> for GaugeCommitVoteV2<'info> { + fn validate(&self) -> ProgramResult { + self.validate_without_delegate()?; + assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); + Ok(()) + } +} diff --git a/programs/gauge/src/instructions/mod.rs b/programs/gauge/src/instructions/mod.rs index 1a0d78e..f734160 100644 --- a/programs/gauge/src/instructions/mod.rs +++ b/programs/gauge/src/instructions/mod.rs @@ -6,11 +6,13 @@ pub mod create_gauge_delegation; pub mod create_gauge_vote; pub mod create_gauge_voter; pub mod create_gaugemeister; +pub mod delegated_gauge_commit_vote; pub mod delegated_gauge_revert_vote; pub mod delegated_gauge_set_vote; pub mod delegation_set_vote_committer; pub mod delegation_set_vote_setter; pub mod gauge_commit_vote; +pub mod gauge_commit_vote_v2; pub mod gauge_disable; pub mod gauge_enable; pub mod gauge_revert_vote; @@ -27,11 +29,13 @@ pub use create_gauge_delegation::*; pub use create_gauge_vote::*; pub use create_gauge_voter::*; pub use create_gaugemeister::*; +pub use delegated_gauge_commit_vote::*; pub use delegated_gauge_revert_vote::*; pub use delegated_gauge_set_vote::*; pub use delegation_set_vote_committer::*; pub use delegation_set_vote_setter::*; pub use gauge_commit_vote::*; +pub use gauge_commit_vote_v2::*; pub use gauge_disable::*; pub use gauge_enable::*; pub use gauge_revert_vote::*; diff --git a/programs/gauge/src/lib.rs b/programs/gauge/src/lib.rs index 5cc5861..560e63b 100644 --- a/programs/gauge/src/lib.rs +++ b/programs/gauge/src/lib.rs @@ -104,6 +104,13 @@ pub mod gauge { gauge_commit_vote::handler(ctx) } + /// Commits the vote of a [Gauge]. + /// Only the voter can call this. + #[access_control(ctx.accounts.validate())] + pub fn gauge_commit_vote_v2(ctx: Context, _vote_bump: u8) -> ProgramResult { + gauge_commit_vote_v2::handler(ctx) + } + /// Reverts a vote commitment of a [Gauge]. /// Only the voter can call this. #[access_control(ctx.accounts.validate())] @@ -174,6 +181,13 @@ pub mod gauge { delegated_gauge_revert_vote::handler(ctx) } + /// Commits a vote of a [Gauge] using the [GaugeDelegation]. + /// Only the [GaugeDelegation::vote_committer] may call this. + #[access_control(ctx.accounts.validate())] + pub fn delegated_gauge_commit_vote(ctx: Context) -> ProgramResult { + delegated_gauge_commit_vote::handler(ctx) + } + /// Sets the [GaugeDelegation::vote_setter]. Only the [locked_voter::Escrow::vote_delegate] may call this. #[access_control(ctx.accounts.validate())] pub fn delegation_set_vote_setter(ctx: Context) -> ProgramResult { From a743383e6f86293d7d8a3b6938091b0d454b58d0 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Wed, 16 Feb 2022 08:30:34 +0800 Subject: [PATCH 5/9] fix v0.21 --- programs/gauge/src/instructions/create_gauge_delegation.rs | 3 +-- programs/gauge/src/instructions/gauge_commit_vote_v2.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/programs/gauge/src/instructions/create_gauge_delegation.rs b/programs/gauge/src/instructions/create_gauge_delegation.rs index 8b4e8da..90d2332 100644 --- a/programs/gauge/src/instructions/create_gauge_delegation.rs +++ b/programs/gauge/src/instructions/create_gauge_delegation.rs @@ -7,7 +7,6 @@ use crate::*; /// Accounts for [gauge::create_gauge_delegation]. #[derive(Accounts)] -#[instruction(bump: u8)] pub struct CreateGaugeDelegation<'info> { /// The [Gauge] to be created. #[account( @@ -16,7 +15,7 @@ pub struct CreateGaugeDelegation<'info> { b"GaugeDelegation".as_ref(), gauge_voter.key().as_ref(), ], - bump = bump, + bump, payer = payer )] pub gauge_delegation: AccountLoader<'info, GaugeDelegation>, diff --git a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs index 961544a..39412fd 100644 --- a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs +++ b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs @@ -8,7 +8,6 @@ use crate::*; /// Accounts for [gauge::gauge_commit_vote]. #[derive(Accounts)] -#[instruction(vote_bump: u8)] pub struct GaugeCommitVoteV2<'info> { /// The [Gaugemeister]. pub gaugemeister: Account<'info, Gaugemeister>, @@ -34,7 +33,7 @@ pub struct GaugeCommitVoteV2<'info> { gauge_vote.key().as_ref(), epoch_gauge_voter.voting_epoch.to_le_bytes().as_ref(), ], - bump = vote_bump, + bump, payer = payer )] pub epoch_gauge_vote: Account<'info, EpochGaugeVote>, From b30406b2f3522e32c5cf5d8a85c0162a0560cb10 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Wed, 16 Feb 2022 11:39:13 +0800 Subject: [PATCH 6/9] upgrade tribeca --- package.json | 2 +- yarn.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index d2512fc..0717ba6 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@saberhq/token-utils": "^1.12.44", "@saberhq/tsconfig": "^1.12.44", "@solana/web3.js": "^1.34.0", - "@tribecahq/tribeca-sdk": "^0.4.0", + "@tribecahq/tribeca-sdk": "^0.4.1", "@types/bn.js": "^5.1.0", "@types/chai": "^4.3.0", "@types/lodash": "^4.14.178", diff --git a/yarn.lock b/yarn.lock index ebdccdd..fb744dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -237,7 +237,7 @@ __metadata: "@saberhq/token-utils": ^1.12.44 "@saberhq/tsconfig": ^1.12.44 "@solana/web3.js": ^1.34.0 - "@tribecahq/tribeca-sdk": ^0.4.0 + "@tribecahq/tribeca-sdk": ^0.4.1 "@types/bn.js": ^5.1.0 "@types/chai": ^4.3.0 "@types/lodash": ^4.14.178 @@ -498,21 +498,21 @@ __metadata: languageName: node linkType: hard -"@tribecahq/tribeca-sdk@npm:^0.4.0": - version: 0.4.0 - resolution: "@tribecahq/tribeca-sdk@npm:0.4.0" +"@tribecahq/tribeca-sdk@npm:^0.4.1": + version: 0.4.1 + resolution: "@tribecahq/tribeca-sdk@npm:0.4.1" dependencies: tiny-invariant: ^1.2.0 tslib: ^2.3.1 peerDependencies: - "@gokiprotocol/client": ^0.5 + "@gokiprotocol/client": ^0.6.1 "@project-serum/anchor": ">=0.19" "@saberhq/anchor-contrib": ^1.10.6 "@saberhq/solana-contrib": ^1.10.6 "@saberhq/token-utils": ^1.10.6 "@solana/web3.js": ^1.29.2 bn.js: ^5.2.0 - checksum: 019ecd01f2d8605561d34d959b6994e6166309efd4b3d589feac6b88f40ad491f1ce8137822d5a00fefe9c7a3ef20803c0ac5a0c893dfa49bd6601b4c4eb3b95 + checksum: 4f982ed2807d53a6e3589df2537021a51e5cc4e9b0ccc40389f5069cc37ca15f8fa54a68827ed8f63e7365600ba7381e71b2c434af992130ec073c2ad306983c languageName: node linkType: hard From d7ab3c8ca0f53ebbbe04f04df0bb5c93082def48 Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Wed, 16 Feb 2022 12:01:23 +0800 Subject: [PATCH 7/9] generate seeds --- Anchor.toml | 3 + ci.nix | 4 +- flake.lock | 24 ++-- .../gauge/src/instructions/create_gauge.rs | 2 +- .../instructions/create_gauge_delegation.rs | 4 +- .../src/instructions/create_gauge_vote.rs | 2 +- .../src/instructions/create_gaugemeister.rs | 2 +- .../delegated_gauge_commit_vote.rs | 4 +- .../src/instructions/gauge_commit_vote.rs | 58 +++++---- .../src/instructions/gauge_commit_vote_v2.rs | 111 ++---------------- .../instructions/prepare_epoch_gauge_voter.rs | 13 +- programs/gauge/src/state.rs | 13 +- 12 files changed, 83 insertions(+), 157 deletions(-) diff --git a/Anchor.toml b/Anchor.toml index 5278328..f354d8c 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -1,6 +1,9 @@ anchor_version = "0.20.1" solana_version = "1.8.11" +[features] +seeds = true + [scripts] test = "yarn mocha" diff --git a/ci.nix b/ci.nix index 92d1222..5bacc2e 100644 --- a/ci.nix +++ b/ci.nix @@ -4,9 +4,9 @@ pkgs.buildEnv { paths = with pkgs; with saber-pkgs; (pkgs.lib.optionals pkgs.stdenv.isLinux ([ libudev ])) ++ [ - anchor-0_20_0 + anchor-0_21_0 cargo-workspaces - solana-install + solana-basic # sdk nodejs diff --git a/flake.lock b/flake.lock index 606e671..72b6d39 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "flake-utils": { "locked": { - "lastModified": 1638122382, - "narHash": "sha256-sQzZzAbvKEqN9s0bzWuYmRaA03v40gaJ4+iL1LXjaeI=", + "lastModified": 1644229661, + "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", "owner": "numtide", "repo": "flake-utils", - "rev": "74f7e4319258e287b0f9cb95426c9853b282730b", + "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", "type": "github" }, "original": { @@ -47,11 +47,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1641671388, - "narHash": "sha256-aHoO6CpPLJK8hLkPJrpMnCRnj3YbfQZ7HNcXcnI83E0=", + "lastModified": 1644938674, + "narHash": "sha256-7/xRvb45vPCT3JdusuXSxEO8b8RQpTrBliwWzVMQ9sM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "32356ce11b8cc5cc421b68138ae8c730cc8ad4a2", + "rev": "a40082270194f2068e6cfb4d26d53d511fc8c34b", "type": "github" }, "original": { @@ -79,11 +79,11 @@ }, "nixpkgs_3": { "locked": { - "lastModified": 1641671388, - "narHash": "sha256-aHoO6CpPLJK8hLkPJrpMnCRnj3YbfQZ7HNcXcnI83E0=", + "lastModified": 1644938674, + "narHash": "sha256-7/xRvb45vPCT3JdusuXSxEO8b8RQpTrBliwWzVMQ9sM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "32356ce11b8cc5cc421b68138ae8c730cc8ad4a2", + "rev": "a40082270194f2068e6cfb4d26d53d511fc8c34b", "type": "github" }, "original": { @@ -126,11 +126,11 @@ "rust-overlay": "rust-overlay" }, "locked": { - "lastModified": 1641689883, - "narHash": "sha256-xvsrJylsXjGNgOIrId03FcfK5GV6RKS6Y/c0GcUWyB4=", + "lastModified": 1644970002, + "narHash": "sha256-nhr0wL1RIrL7Iq45sHnwOX/QN/WNkYdVqD4PCwscx4k=", "owner": "saber-hq", "repo": "saber-overlay", - "rev": "72aa48864ac91a994dc91bf7bc20be390d9778fe", + "rev": "e358951e9233e8b5d8f398138f33a1ad98ed17d4", "type": "github" }, "original": { diff --git a/programs/gauge/src/instructions/create_gauge.rs b/programs/gauge/src/instructions/create_gauge.rs index 6f0e8a1..cc300c1 100644 --- a/programs/gauge/src/instructions/create_gauge.rs +++ b/programs/gauge/src/instructions/create_gauge.rs @@ -13,7 +13,7 @@ pub struct CreateGauge<'info> { seeds = [ b"Gauge".as_ref(), gaugemeister.key().as_ref(), - quarry.key().as_ref(), + quarry.key().as_ref() ], bump, payer = payer diff --git a/programs/gauge/src/instructions/create_gauge_delegation.rs b/programs/gauge/src/instructions/create_gauge_delegation.rs index 90d2332..58507cf 100644 --- a/programs/gauge/src/instructions/create_gauge_delegation.rs +++ b/programs/gauge/src/instructions/create_gauge_delegation.rs @@ -8,12 +8,12 @@ use crate::*; /// Accounts for [gauge::create_gauge_delegation]. #[derive(Accounts)] pub struct CreateGaugeDelegation<'info> { - /// The [Gauge] to be created. + /// The [GaugeDelegation] to be created. #[account( init, seeds = [ b"GaugeDelegation".as_ref(), - gauge_voter.key().as_ref(), + gauge_voter.key().as_ref() ], bump, payer = payer diff --git a/programs/gauge/src/instructions/create_gauge_vote.rs b/programs/gauge/src/instructions/create_gauge_vote.rs index d22238d..0fa06dc 100644 --- a/programs/gauge/src/instructions/create_gauge_vote.rs +++ b/programs/gauge/src/instructions/create_gauge_vote.rs @@ -13,7 +13,7 @@ pub struct CreateGaugeVote<'info> { seeds = [ b"GaugeVote".as_ref(), gauge_voter.key().as_ref(), - gauge.key().as_ref(), + gauge.key().as_ref() ], bump, payer = payer diff --git a/programs/gauge/src/instructions/create_gaugemeister.rs b/programs/gauge/src/instructions/create_gaugemeister.rs index dfdc334..91d31e7 100644 --- a/programs/gauge/src/instructions/create_gaugemeister.rs +++ b/programs/gauge/src/instructions/create_gaugemeister.rs @@ -13,7 +13,7 @@ pub struct CreateGaugemeister<'info> { init, seeds = [ b"Gaugemeister".as_ref(), - base.key().as_ref(), + base.key().as_ref() ], bump, payer = payer diff --git a/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs b/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs index 700f129..c2f5c51 100644 --- a/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs +++ b/programs/gauge/src/instructions/delegated_gauge_commit_vote.rs @@ -16,7 +16,7 @@ pub struct DelegatedGaugeCommitVote<'info> { impl<'info> DelegatedGaugeCommitVote<'info> { fn commit_vote(&mut self) -> ProgramResult { - self.common.commit_vote() + self.common.common.commit_vote() } } @@ -28,7 +28,7 @@ impl<'info> Validate<'info> for DelegatedGaugeCommitVote<'info> { fn validate(&self) -> ProgramResult { let delegation = self.gauge_delegation.load()?; self.common.validate_without_delegate()?; - assert_keys_eq!(self.common.gauge_voter, delegation.gauge_voter); + assert_keys_eq!(self.common.common.gauge_voter, delegation.gauge_voter); assert_keys_eq!(self.common.vote_delegate, delegation.vote_committer); Ok(()) } diff --git a/programs/gauge/src/instructions/gauge_commit_vote.rs b/programs/gauge/src/instructions/gauge_commit_vote.rs index 3223f4d..d6d3341 100644 --- a/programs/gauge/src/instructions/gauge_commit_vote.rs +++ b/programs/gauge/src/instructions/gauge_commit_vote.rs @@ -28,7 +28,7 @@ pub struct GaugeCommitVote<'info> { #[account( init, seeds = [ - b"EpochGaugeVote", + b"EpochGaugeVote".as_ref(), gauge_vote.key().as_ref(), epoch_gauge_voter.voting_epoch.to_le_bytes().as_ref(), ], @@ -57,37 +57,43 @@ impl<'info> GaugeCommitVote<'info> { msg!("power: {}, shares: {}", power, total_shares); Some(total_shares) } -} -pub fn handler(ctx: Context) -> ProgramResult { - let next_vote_shares = unwrap_int!(ctx.accounts.vote_shares_for_next_epoch()); - // if zero vote shares, don't do anything - if next_vote_shares == 0 { - return Ok(()); - } + /// Handles the commit vote. + pub(crate) fn commit_vote(&mut self) -> ProgramResult { + let next_vote_shares = unwrap_int!(self.vote_shares_for_next_epoch()); + // if zero vote shares, don't do anything + if next_vote_shares == 0 { + return Ok(()); + } - let epoch_gauge = &mut ctx.accounts.epoch_gauge; - let epoch_voter = &mut ctx.accounts.epoch_gauge_voter; - let epoch_vote = &mut ctx.accounts.epoch_gauge_vote; + let epoch_gauge = &mut self.epoch_gauge; + let epoch_voter = &mut self.epoch_gauge_voter; + let epoch_vote = &mut self.epoch_gauge_vote; - epoch_voter.allocated_power = - unwrap_int!(epoch_voter.allocated_power.checked_add(next_vote_shares)); - epoch_vote.allocated_power = next_vote_shares; + epoch_voter.allocated_power = + unwrap_int!(epoch_voter.allocated_power.checked_add(next_vote_shares)); + epoch_vote.allocated_power = next_vote_shares; - epoch_gauge.total_power = unwrap_int!(epoch_gauge.total_power.checked_add(next_vote_shares)); + epoch_gauge.total_power = + unwrap_int!(epoch_gauge.total_power.checked_add(next_vote_shares)); - emit!(CommitGaugeVoteEvent { - gaugemeister: ctx.accounts.gauge.gaugemeister, - gauge: ctx.accounts.gauge.key(), - quarry: ctx.accounts.gauge.quarry, - gauge_voter_owner: ctx.accounts.gauge_voter.owner, - vote_shares_for_next_epoch: next_vote_shares, - voting_epoch: epoch_voter.voting_epoch, - updated_allocated_power: epoch_voter.allocated_power, - updated_total_power: epoch_gauge.total_power, - }); + emit!(CommitGaugeVoteEvent { + gaugemeister: self.gauge.gaugemeister, + gauge: self.gauge.key(), + quarry: self.gauge.quarry, + gauge_voter_owner: self.gauge_voter.owner, + vote_shares_for_next_epoch: next_vote_shares, + voting_epoch: epoch_voter.voting_epoch, + updated_allocated_power: epoch_voter.allocated_power, + updated_total_power: epoch_gauge.total_power, + }); - Ok(()) + Ok(()) + } +} + +pub fn handler(ctx: Context) -> ProgramResult { + ctx.accounts.commit_vote() } impl<'info> Validate<'info> for GaugeCommitVote<'info> { diff --git a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs index 39412fd..c2a0f09 100644 --- a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs +++ b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs @@ -1,44 +1,16 @@ //! Commits the votes for a [Gauge], requiring permission. //! The old commitment mechanism will be deprecated. -use num_traits::ToPrimitive; -use vipers::{assert_keys_eq, invariant, unwrap_int}; +use vipers::assert_keys_eq; use crate::*; -/// Accounts for [gauge::gauge_commit_vote]. +/// Accounts for [gauge::gauge_commit_vote_v2]. #[derive(Accounts)] pub struct GaugeCommitVoteV2<'info> { - /// The [Gaugemeister]. - pub gaugemeister: Account<'info, Gaugemeister>, - /// The [Gauge]. - pub gauge: Account<'info, Gauge>, - /// The [GaugeVoter]. - pub gauge_voter: Account<'info, GaugeVoter>, - /// The [GaugeVote] containing the vote weights. - pub gauge_vote: Account<'info, GaugeVote>, - - /// The [EpochGauge]. - #[account(mut)] - pub epoch_gauge: Account<'info, EpochGauge>, - /// The [EpochGaugeVoter]. - #[account(mut)] - pub epoch_gauge_voter: Account<'info, EpochGaugeVoter>, - - /// The [EpochGaugeVote] to create. - #[account( - init, - seeds = [ - b"EpochGaugeVote", - gauge_vote.key().as_ref(), - epoch_gauge_voter.voting_epoch.to_le_bytes().as_ref(), - ], - bump, - payer = payer - )] - pub epoch_gauge_vote: Account<'info, EpochGaugeVote>, - - /// The escrow. + /// Common accounts. + pub common: GaugeCommitVote<'info>, + /// The [Escrow]. pub escrow: Account<'info, locked_voter::Escrow>, /// The [Escrow::vote_delegate]. pub vote_delegate: Signer<'info>, @@ -50,87 +22,20 @@ pub struct GaugeCommitVoteV2<'info> { pub system_program: Program<'info, System>, } -impl<'info> GaugeCommitVoteV2<'info> { - fn vote_shares_for_next_epoch(&self) -> Option { - if self.gauge_vote.weight == 0 { - return Some(0); - } - let power: u64 = self.epoch_gauge_voter.voting_power; - let total_shares = (power as u128) - .checked_mul(self.gauge_vote.weight.into())? - .checked_div(self.gauge_voter.total_weight.into())? - .to_u64()?; - msg!("power: {}, shares: {}", power, total_shares); - Some(total_shares) - } -} - pub fn handler(ctx: Context) -> ProgramResult { - ctx.accounts.commit_vote() + ctx.accounts.common.commit_vote() } impl<'info> GaugeCommitVoteV2<'info> { - pub(crate) fn commit_vote(&mut self) -> ProgramResult { - let next_vote_shares = unwrap_int!(self.vote_shares_for_next_epoch()); - // if zero vote shares, don't do anything - if next_vote_shares == 0 { - return Ok(()); - } - - let epoch_gauge = &mut self.epoch_gauge; - let epoch_voter = &mut self.epoch_gauge_voter; - let epoch_vote = &mut self.epoch_gauge_vote; - - epoch_voter.allocated_power = - unwrap_int!(epoch_voter.allocated_power.checked_add(next_vote_shares)); - epoch_vote.allocated_power = next_vote_shares; - - epoch_gauge.total_power = - unwrap_int!(epoch_gauge.total_power.checked_add(next_vote_shares)); - - emit!(CommitGaugeVoteEvent { - gaugemeister: self.gauge.gaugemeister, - gauge: self.gauge.key(), - quarry: self.gauge.quarry, - gauge_voter_owner: self.gauge_voter.owner, - vote_shares_for_next_epoch: next_vote_shares, - voting_epoch: epoch_voter.voting_epoch, - updated_allocated_power: epoch_voter.allocated_power, - updated_total_power: epoch_gauge.total_power, - }); - - Ok(()) - } - pub(crate) fn validate_without_delegate(&self) -> ProgramResult { - assert_keys_eq!(self.gaugemeister, self.gauge.gaugemeister); - assert_keys_eq!(self.gauge, self.gauge_vote.gauge); - assert_keys_eq!(self.gauge_voter, self.gauge_vote.gauge_voter); - - assert_keys_eq!(self.epoch_gauge.gauge, self.gauge); - assert_keys_eq!(self.epoch_gauge_voter.gauge_voter, self.gauge_voter); - - invariant!(!self.gauge.is_disabled, CannotCommitGaugeDisabled); - invariant!( - self.epoch_gauge_voter.weight_change_seqno == self.gauge_voter.weight_change_seqno, - WeightSeqnoChanged - ); - - let voting_epoch = self.gaugemeister.voting_epoch()?; - invariant!( - self.epoch_gauge_voter.voting_epoch == voting_epoch, - EpochGaugeNotVoting - ); - - assert_keys_eq!(self.escrow, self.gauge_voter.escrow); - - Ok(()) + self.common.validate() } } impl<'info> Validate<'info> for GaugeCommitVoteV2<'info> { fn validate(&self) -> ProgramResult { self.validate_without_delegate()?; + assert_keys_eq!(self.escrow, self.common.gauge_voter.escrow); assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); Ok(()) } diff --git a/programs/gauge/src/instructions/prepare_epoch_gauge_voter.rs b/programs/gauge/src/instructions/prepare_epoch_gauge_voter.rs index d4925d0..41fa2f5 100644 --- a/programs/gauge/src/instructions/prepare_epoch_gauge_voter.rs +++ b/programs/gauge/src/instructions/prepare_epoch_gauge_voter.rs @@ -6,23 +6,24 @@ use vipers::{assert_keys_eq, unwrap_int}; /// Accounts for [gauge::prepare_epoch_gauge_voter]. #[derive(Accounts)] -#[instruction(bump: u8)] pub struct PrepareEpochGaugeVoter<'info> { + /// [GaugeVoter::gaugemeister]. pub gaugemeister: Account<'info, Gaugemeister>, + /// [Escrow::locker]. pub locker: Account<'info, locked_voter::Locker>, + /// [GaugeVoter::escrow]. pub escrow: Account<'info, locked_voter::Escrow>, - /// Gauge vote. + /// Gauge voter. pub gauge_voter: Account<'info, GaugeVoter>, /// The [EpochGaugeVoter]. #[account( init, seeds = [ - b"EpochGaugeVoter", + b"EpochGaugeVoter".as_ref(), gauge_voter.key().as_ref(), - #[allow(clippy::unwrap_used)] - gaugemeister.current_rewards_epoch.checked_add(1).unwrap().to_le_bytes().as_ref() + gaugemeister.voting_epoch_unwrapped().to_le_bytes().as_ref() ], bump, payer = payer @@ -92,7 +93,7 @@ pub struct PrepareEpochGaugeVoterEvent { /// The [Rewarder] pub rewarder: Pubkey, #[index] - /// The assocated [locked_voter::Locker]. + /// The associated [locked_voter::Locker]. pub locker: Pubkey, #[index] /// The owner of the [GaugeVoter]. diff --git a/programs/gauge/src/state.rs b/programs/gauge/src/state.rs index 9e12106..46332f5 100644 --- a/programs/gauge/src/state.rs +++ b/programs/gauge/src/state.rs @@ -47,6 +47,13 @@ impl Gaugemeister { let voting_epoch = unwrap_int!(self.current_rewards_epoch.checked_add(1)); Ok(voting_epoch) } + + /// Fetches the current voting epoch, unwrapped. + /// This is only used in [gauge::prepare_epoch_gauge_voter]. + pub(crate) fn voting_epoch_unwrapped(&self) -> u32 { + #[allow(clippy::unwrap_used)] + self.voting_epoch().unwrap() + } } /// A [Gauge] determines the rewards shares to give to a [quarry_mine::Quarry]. @@ -173,6 +180,10 @@ impl EpochGaugeVote { } /// Enables delegating vote allocations to another address. +/// Each [GaugeVoter] may only have one [GaugeDelegation]. +/// +/// If multiple [`Self::vote_setter`]s or [`Self::vote_committer`]s are desired, +/// one should use a [Goki owner invoker](https://docs.tribeca.so/goki/smart-wallet#subaccounts) or some other sort of multisig. #[account(zero_copy)] #[derive(Debug, Default)] pub struct GaugeDelegation { @@ -182,6 +193,6 @@ pub struct GaugeDelegation { /// Address which can call [gauge::delegated_gauge_set_vote] on behalf of the [Self::gauge_voter]. pub vote_setter: Pubkey, - /// UNIMPLEMENTED: account which is allowed to commit votes on behalf of the gauge. + /// Address which is allowed to commit votes on behalf of the gauge via [gauge::delegated_gauge_commit_vote]. pub vote_committer: Pubkey, } From 1a18af843fb862f46100a1d81e1eba396635079d Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Wed, 16 Feb 2022 12:01:55 +0800 Subject: [PATCH 8/9] Delete unused accounts --- programs/gauge/src/instructions/gauge_commit_vote_v2.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs index c2a0f09..ce73424 100644 --- a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs +++ b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs @@ -14,12 +14,6 @@ pub struct GaugeCommitVoteV2<'info> { pub escrow: Account<'info, locked_voter::Escrow>, /// The [Escrow::vote_delegate]. pub vote_delegate: Signer<'info>, - - /// Funder of the [EpochGaugeVote] to create. - #[account(mut)] - pub payer: Signer<'info>, - /// The [System] program. - pub system_program: Program<'info, System>, } pub fn handler(ctx: Context) -> ProgramResult { From cf5e92a9bcba4413577b32e22ef0ba4d5607b29a Mon Sep 17 00:00:00 2001 From: Larry Jarry Date: Wed, 16 Feb 2022 12:03:19 +0800 Subject: [PATCH 9/9] fix delegation checks --- programs/gauge/src/instructions/gauge_commit_vote_v2.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs index ce73424..3d04dbc 100644 --- a/programs/gauge/src/instructions/gauge_commit_vote_v2.rs +++ b/programs/gauge/src/instructions/gauge_commit_vote_v2.rs @@ -22,14 +22,15 @@ pub fn handler(ctx: Context) -> ProgramResult { impl<'info> GaugeCommitVoteV2<'info> { pub(crate) fn validate_without_delegate(&self) -> ProgramResult { - self.common.validate() + self.common.validate()?; + assert_keys_eq!(self.escrow, self.common.gauge_voter.escrow); + Ok(()) } } impl<'info> Validate<'info> for GaugeCommitVoteV2<'info> { fn validate(&self) -> ProgramResult { self.validate_without_delegate()?; - assert_keys_eq!(self.escrow, self.common.gauge_voter.escrow); assert_keys_eq!(self.vote_delegate, self.escrow.vote_delegate); Ok(()) }