-
Notifications
You must be signed in to change notification settings - Fork 310
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement rust equivalent of LQT actions
- Loading branch information
1 parent
6a209d4
commit e42c010
Showing
12 changed files
with
352 additions
and
4 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
crates/core/component/funding/src/liquidity_tournament/action/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
use anyhow::{anyhow, Context}; | ||
use decaf377_rdsa::{Signature, SpendAuth, VerificationKey}; | ||
use penumbra_sdk_asset::{asset::Denom, balance, Value}; | ||
use penumbra_sdk_keys::Address; | ||
use penumbra_sdk_proto::{core::component::funding::v1 as pb, DomainType}; | ||
use penumbra_sdk_sct::Nullifier; | ||
use penumbra_sdk_tct::Position; | ||
use penumbra_sdk_txhash::{EffectHash, EffectingData}; | ||
|
||
use super::proof::LiquidityTournamentVoteProof; | ||
|
||
/// The internal body of an LQT vote, containing the intended vote and other validity information. | ||
/// | ||
/// c.f. [`penumbra_sdk_governance::delegator_vote::action::DelegatorVoteBody`], which is similar. | ||
#[derive(Clone, Debug)] | ||
pub struct LiquidityTournamentVoteBody { | ||
/// Which asset is being incentivized. | ||
/// | ||
/// We use the base denom to allow filtering particular asset sources (i.e. IBC transfers)a. | ||
pub incentivized: Denom, | ||
/// The address that will receive any rewards for voting. | ||
pub rewards_recipient: Address, | ||
/// The start position of the tournament. | ||
/// | ||
/// This is included to allow stateless verification, but should match the epoch of the LQT. | ||
pub start_position: Position, | ||
/// The value being used to vote with. | ||
/// | ||
/// This should be the delegation tokens for a specific validator. | ||
pub value: Value, | ||
/// The nullifier of the note being spent. | ||
pub nullifier: Nullifier, | ||
/// The key that must be used to vote. | ||
pub rk: VerificationKey<SpendAuth>, | ||
} | ||
|
||
impl DomainType for LiquidityTournamentVoteBody { | ||
type Proto = pb::LiquidityTournamentVoteBody; | ||
} | ||
|
||
impl TryFrom<pb::LiquidityTournamentVoteBody> for LiquidityTournamentVoteBody { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(proto: pb::LiquidityTournamentVoteBody) -> Result<Self, Self::Error> { | ||
Result::<_, Self::Error>::Ok(Self { | ||
incentivized: proto | ||
.incentivized | ||
.ok_or_else(|| anyhow!("missing `incentivized`"))? | ||
.try_into()?, | ||
rewards_recipient: proto | ||
.rewards_recipient | ||
.ok_or_else(|| anyhow!("missing `rewards_recipient`"))? | ||
.try_into()?, | ||
start_position: proto.start_position.into(), | ||
value: proto | ||
.value | ||
.ok_or_else(|| anyhow!("missing `value`"))? | ||
.try_into()?, | ||
nullifier: proto | ||
.nullifier | ||
.ok_or_else(|| anyhow!("missing `nullifier`"))? | ||
.try_into()?, | ||
rk: proto | ||
.rk | ||
.ok_or_else(|| anyhow!("missing `rk`"))? | ||
.try_into()?, | ||
}) | ||
.with_context(|| format!("while parsing {}", std::any::type_name::<Self>())) | ||
} | ||
} | ||
|
||
impl From<LiquidityTournamentVoteBody> for pb::LiquidityTournamentVoteBody { | ||
fn from(value: LiquidityTournamentVoteBody) -> Self { | ||
Self { | ||
incentivized: Some(value.incentivized.into()), | ||
rewards_recipient: Some(value.rewards_recipient.into()), | ||
start_position: value.start_position.into(), | ||
value: Some(value.value.into()), | ||
nullifier: Some(value.nullifier.into()), | ||
rk: Some(value.rk.into()), | ||
} | ||
} | ||
} | ||
|
||
/// The action used to vote in the liquidity tournament. | ||
/// | ||
/// This vote is towards a particular asset whose liquidity should be incentivized, | ||
/// and is weighted by the amount of delegation tokens being expended. | ||
#[derive(Clone, Debug)] | ||
pub struct ActionLiquidityTournamentVote { | ||
/// The actual body, containing the vote and other validity information. | ||
pub body: LiquidityTournamentVoteBody, | ||
/// An authorization over the body. | ||
pub auth_sig: Signature<SpendAuth>, | ||
/// A ZK proof tying in the private information for this action. | ||
pub proof: LiquidityTournamentVoteProof, | ||
} | ||
|
||
impl DomainType for ActionLiquidityTournamentVote { | ||
type Proto = pb::ActionLiquidityTournamentVote; | ||
} | ||
|
||
impl TryFrom<pb::ActionLiquidityTournamentVote> for ActionLiquidityTournamentVote { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(value: pb::ActionLiquidityTournamentVote) -> Result<Self, Self::Error> { | ||
Result::<_, Self::Error>::Ok(Self { | ||
body: value | ||
.body | ||
.ok_or_else(|| anyhow!("missing `body`"))? | ||
.try_into()?, | ||
auth_sig: value | ||
.auth_sig | ||
.ok_or_else(|| anyhow!("missing `auth_sig`"))? | ||
.try_into()?, | ||
proof: value | ||
.proof | ||
.ok_or_else(|| anyhow!("missing `proof`"))? | ||
.try_into()?, | ||
}) | ||
.with_context(|| format!("while parsing {}", std::any::type_name::<Self>())) | ||
} | ||
} | ||
|
||
impl From<ActionLiquidityTournamentVote> for pb::ActionLiquidityTournamentVote { | ||
fn from(value: ActionLiquidityTournamentVote) -> Self { | ||
Self { | ||
body: Some(value.body.into()), | ||
auth_sig: Some(value.auth_sig.into()), | ||
proof: Some(value.proof.into()), | ||
} | ||
} | ||
} | ||
|
||
impl EffectingData for ActionLiquidityTournamentVote { | ||
fn effect_hash(&self) -> EffectHash { | ||
EffectHash::from_proto_effecting_data(&self.to_proto()) | ||
} | ||
} | ||
|
||
impl ActionLiquidityTournamentVote { | ||
/// This action doesn't actually produce or consume value. | ||
pub fn balance_commmitment(&self) -> balance::Commitment { | ||
// This will be the commitment to zero. | ||
balance::Commitment::default() | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
crates/core/component/funding/src/liquidity_tournament/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
mod action; | ||
mod view; | ||
|
||
pub mod proof; | ||
pub use action::{ActionLiquidityTournamentVote, LiquidityTournamentVoteBody}; | ||
pub use view::ActionLiquidityTournamentVoteView; | ||
|
||
/// The maximum number of allowable bytes in the denom string. | ||
pub const LIQUIDITY_TOURNAMENT_VOTE_DENOM_MAX_BYTES: usize = 256; |
91 changes: 91 additions & 0 deletions
91
crates/core/component/funding/src/liquidity_tournament/view/mod.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
use anyhow::{anyhow, Context}; | ||
use penumbra_sdk_proto::{core::component::funding::v1 as pb, DomainType}; | ||
use penumbra_sdk_shielded_pool::NoteView; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
use super::ActionLiquidityTournamentVote; | ||
|
||
#[derive(Clone, Debug, Serialize, Deserialize)] | ||
#[serde( | ||
try_from = "pb::ActionLiquidityTournamentVoteView", | ||
into = "pb::ActionLiquidityTournamentVoteView" | ||
)] | ||
#[allow(clippy::large_enum_variant)] | ||
pub enum ActionLiquidityTournamentVoteView { | ||
Visible { | ||
vote: ActionLiquidityTournamentVote, | ||
note: NoteView, | ||
}, | ||
Opaque { | ||
vote: ActionLiquidityTournamentVote, | ||
}, | ||
} | ||
|
||
impl DomainType for ActionLiquidityTournamentVoteView { | ||
type Proto = pb::ActionLiquidityTournamentVoteView; | ||
} | ||
|
||
impl TryFrom<pb::ActionLiquidityTournamentVoteView> for ActionLiquidityTournamentVoteView { | ||
type Error = anyhow::Error; | ||
|
||
fn try_from(value: pb::ActionLiquidityTournamentVoteView) -> Result<Self, Self::Error> { | ||
let out: Result<Self, Self::Error> = match value | ||
.liquidity_tournament_vote | ||
.ok_or_else(|| anyhow::anyhow!("missing `liquidity_tournament_vote`"))? | ||
{ | ||
pb::action_liquidity_tournament_vote_view::LiquidityTournamentVote::Visible( | ||
visible, | ||
) => Ok(Self::Visible { | ||
vote: visible | ||
.vote | ||
.ok_or_else(|| anyhow!("missing `visible.vote`"))? | ||
.try_into()?, | ||
note: visible | ||
.note | ||
.ok_or_else(|| anyhow!("missing `visible.note`"))? | ||
.try_into()?, | ||
}), | ||
pb::action_liquidity_tournament_vote_view::LiquidityTournamentVote::Opaque(opaque) => { | ||
Ok(Self::Opaque { | ||
vote: opaque | ||
.vote | ||
.ok_or_else(|| anyhow!("missing `opaque.vote`"))? | ||
.try_into()?, | ||
}) | ||
} | ||
}; | ||
out.with_context(|| format!("while parsing `{}`", std::any::type_name::<Self>())) | ||
} | ||
} | ||
|
||
impl From<ActionLiquidityTournamentVoteView> for pb::ActionLiquidityTournamentVoteView { | ||
fn from(value: ActionLiquidityTournamentVoteView) -> Self { | ||
use pb::action_liquidity_tournament_vote_view as pblqtvv; | ||
match value { | ||
ActionLiquidityTournamentVoteView::Visible { vote, note } => Self { | ||
liquidity_tournament_vote: Some(pblqtvv::LiquidityTournamentVote::Visible( | ||
pblqtvv::Visible { | ||
vote: Some(vote.into()), | ||
note: Some(note.into()), | ||
}, | ||
)), | ||
}, | ||
ActionLiquidityTournamentVoteView::Opaque { vote } => Self { | ||
liquidity_tournament_vote: Some(pblqtvv::LiquidityTournamentVote::Opaque( | ||
pblqtvv::Opaque { | ||
vote: Some(vote.into()), | ||
}, | ||
)), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
impl From<ActionLiquidityTournamentVoteView> for ActionLiquidityTournamentVote { | ||
fn from(value: ActionLiquidityTournamentVoteView) -> Self { | ||
match value { | ||
ActionLiquidityTournamentVoteView::Visible { vote, .. } => vote, | ||
ActionLiquidityTournamentVoteView::Opaque { vote } => vote, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.