diff --git a/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs b/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs index d50e1bd881..2473a12985 100644 Binary files a/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs and b/crates/cnidarium/src/gen/proto_descriptor.bin.no_lfs differ diff --git a/crates/core/component/auction/src/auction/dutch/actions/mod.rs b/crates/core/component/auction/src/auction/dutch/actions/mod.rs index a783c92e6a..8ba8e9c00b 100644 --- a/crates/core/component/auction/src/auction/dutch/actions/mod.rs +++ b/crates/core/component/auction/src/auction/dutch/actions/mod.rs @@ -1,5 +1,14 @@ pub mod schedule; pub use schedule::ActionDutchAuctionSchedule; +pub mod schedule_view; +pub use schedule_view::ActionDutchAuctionScheduleView; + pub mod end; pub use end::ActionDutchAuctionEnd; + +pub mod withdraw; +pub use withdraw::ActionDutchAuctionWithdraw; + +pub mod withdraw_view; +pub use withdraw_view::ActionDutchAuctionWithdrawView; diff --git a/crates/core/component/auction/src/auction/dutch/actions/schedule_view.rs b/crates/core/component/auction/src/auction/dutch/actions/schedule_view.rs new file mode 100644 index 0000000000..26099e60af --- /dev/null +++ b/crates/core/component/auction/src/auction/dutch/actions/schedule_view.rs @@ -0,0 +1,68 @@ +use crate::auction::{ + dutch::{actions::ActionDutchAuctionSchedule, asset::Metadata}, + id::AuctionId, +}; +use anyhow::anyhow; +use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde( + try_from = "pb::ActionDutchAuctionScheduleView", + into = "pb::ActionDutchAuctionScheduleView" +)] +pub struct ActionDutchAuctionScheduleView { + pub action: ActionDutchAuctionSchedule, + pub auction_id: AuctionId, + pub input_metadata: Metadata, + pub output_metadata: Metadata, +} + +/* Protobuf impls */ +impl DomainType for ActionDutchAuctionScheduleView { + type Proto = pb::ActionDutchAuctionScheduleView; +} + +impl From for pb::ActionDutchAuctionScheduleView { + fn from(domain: ActionDutchAuctionScheduleView) -> Self { + pb::ActionDutchAuctionScheduleView { + action: Some(domain.action.into()), + auction_id: Some(domain.auction_id.into()), + input_metadata: Some(domain.input_metadata.into()), + output_metadata: Some(domain.output_metadata.into()), + } + } +} + +impl TryFrom for ActionDutchAuctionScheduleView { + type Error = anyhow::Error; + + fn try_from(msg: pb::ActionDutchAuctionScheduleView) -> Result { + Ok(ActionDutchAuctionScheduleView { + action: msg + .action + .ok_or_else(|| { + anyhow!("ActionDutchAuctionScheduleView message is missing an action") + })? + .try_into()?, + auction_id: msg + .auction_id + .ok_or_else(|| { + anyhow!("ActionDutchAuctionScheduleView message is missing an auction_id") + })? + .try_into()?, + input_metadata: msg + .input_metadata + .ok_or_else(|| { + anyhow!("ActionDutchAuctionScheduleView message is missing an input_metadata") + })? + .try_into()?, + output_metadata: msg + .output_metadata + .ok_or_else(|| { + anyhow!("ActionDutchAuctionScheduleView message is missing an output_metadata") + })? + .try_into()?, + }) + } +} diff --git a/crates/core/component/auction/src/auction/dutch/actions/withdraw.rs b/crates/core/component/auction/src/auction/dutch/actions/withdraw.rs new file mode 100644 index 0000000000..a2203ee69d --- /dev/null +++ b/crates/core/component/auction/src/auction/dutch/actions/withdraw.rs @@ -0,0 +1,53 @@ +use crate::auction::id::AuctionId; +use anyhow::anyhow; +use penumbra_asset::balance; +use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde( + try_from = "pb::ActionDutchAuctionWithdraw", + into = "pb::ActionDutchAuctionWithdraw" +)] +pub struct ActionDutchAuctionWithdraw { + pub auction_id: AuctionId, + pub seq: u64, + pub reserves_commitment: balance::Commitment, +} + +/* Protobuf impls */ +impl DomainType for ActionDutchAuctionWithdraw { + type Proto = pb::ActionDutchAuctionWithdraw; +} + +impl From for pb::ActionDutchAuctionWithdraw { + fn from(domain: ActionDutchAuctionWithdraw) -> Self { + pb::ActionDutchAuctionWithdraw { + auction_id: Some(domain.auction_id.into()), + seq: domain.seq, + reserves_commitment: Some(domain.reserves_commitment.into()), + } + } +} + +impl TryFrom for ActionDutchAuctionWithdraw { + type Error = anyhow::Error; + + fn try_from(msg: pb::ActionDutchAuctionWithdraw) -> Result { + Ok(ActionDutchAuctionWithdraw { + auction_id: msg + .auction_id + .ok_or_else(|| { + anyhow!("ActionDutchAuctionWithdraw message is missing an auction_id") + })? + .try_into()?, + seq: msg.seq, + reserves_commitment: msg + .reserves_commitment + .ok_or_else(|| { + anyhow!("ActionDutchAuctionWithdraw message is missing reserves_commitment") + })? + .try_into()?, + }) + } +} diff --git a/crates/core/component/auction/src/auction/dutch/actions/withdraw_view.rs b/crates/core/component/auction/src/auction/dutch/actions/withdraw_view.rs new file mode 100644 index 0000000000..f53c3e9adf --- /dev/null +++ b/crates/core/component/auction/src/auction/dutch/actions/withdraw_view.rs @@ -0,0 +1,55 @@ +use crate::auction::dutch::actions::ActionDutchAuctionWithdraw; +use anyhow::anyhow; +use penumbra_asset::ValueView; +use penumbra_proto::{core::component::auction::v1alpha1 as pb, DomainType}; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde( + try_from = "pb::ActionDutchAuctionWithdrawView", + into = "pb::ActionDutchAuctionWithdrawView" +)] +pub struct ActionDutchAuctionWithdrawView { + pub action: ActionDutchAuctionWithdraw, + // A sequence of values that sum together to the provided + // reserves commitment. + pub reserves: Vec, +} + +/* Protobuf impls */ +impl DomainType for ActionDutchAuctionWithdrawView { + type Proto = pb::ActionDutchAuctionWithdrawView; +} + +impl From for pb::ActionDutchAuctionWithdrawView { + fn from(domain: ActionDutchAuctionWithdrawView) -> Self { + pb::ActionDutchAuctionWithdrawView { + action: Some(domain.action.into()), + reserves: domain + .reserves + .into_iter() + .map(Into::into) + .collect::>(), + } + } +} + +impl TryFrom for ActionDutchAuctionWithdrawView { + type Error = anyhow::Error; + + fn try_from(msg: pb::ActionDutchAuctionWithdrawView) -> Result { + Ok(ActionDutchAuctionWithdrawView { + action: msg + .action + .ok_or_else(|| { + anyhow!("ActionDutchAuctionWithdrawView message is missing an action") + })? + .try_into()?, + reserves: msg + .reserves + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + }) + } +} diff --git a/crates/core/component/auction/src/component/action_handler/dutch/mod.rs b/crates/core/component/auction/src/component/action_handler/dutch/mod.rs index a0320395cf..df290a3344 100644 --- a/crates/core/component/auction/src/component/action_handler/dutch/mod.rs +++ b/crates/core/component/auction/src/component/action_handler/dutch/mod.rs @@ -1,2 +1,3 @@ mod end; mod schedule; +mod withdraw; diff --git a/crates/core/component/auction/src/component/action_handler/dutch/withdraw.rs b/crates/core/component/auction/src/component/action_handler/dutch/withdraw.rs new file mode 100644 index 0000000000..e6d44ca029 --- /dev/null +++ b/crates/core/component/auction/src/component/action_handler/dutch/withdraw.rs @@ -0,0 +1,18 @@ +use anyhow::Result; +use async_trait::async_trait; +use cnidarium::StateWrite; +use cnidarium_component::ActionHandler; + +use crate::auction::dutch::actions::ActionDutchAuctionWithdraw; + +#[async_trait] +impl ActionHandler for ActionDutchAuctionWithdraw { + type CheckStatelessContext = (); + async fn check_stateless(&self, _context: ()) -> Result<()> { + Ok(()) + } + + async fn check_and_execute(&self, mut _state: S) -> Result<()> { + Ok(()) + } +} diff --git a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs index 9b2da72f93..44d0d87f5b 100644 --- a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs +++ b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.rs @@ -202,6 +202,79 @@ impl ::prost::Name for ActionDutchAuctionEnd { ) } } +/// Withdraw funds from the ended auction associated with the specified `auction_id` +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ActionDutchAuctionWithdraw { + /// The auction to withdraw funds from. + #[prost(message, optional, tag = "1")] + pub auction_id: ::core::option::Option, + /// The sequence number of the withdrawal. + #[prost(uint64, tag = "2")] + pub seq: u64, + /// A transparent (zero blinding factor) commitment to the + /// auction's final reserves. + /// + /// The chain will check this commitment by recomputing it + /// with the on-chain state. + #[prost(message, optional, tag = "3")] + pub reserves_commitment: ::core::option::Option< + super::super::super::asset::v1::BalanceCommitment, + >, +} +impl ::prost::Name for ActionDutchAuctionWithdraw { + const NAME: &'static str = "ActionDutchAuctionWithdraw"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} +/// An `ActionDutchAuctionWithdraw` augmented with additional metadata. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ActionDutchAuctionWithdrawView { + #[prost(message, optional, tag = "1")] + pub action: ::core::option::Option, + /// A sequence of values that sum together to the provided + /// reserves commitment. + #[prost(message, repeated, tag = "2")] + pub reserves: ::prost::alloc::vec::Vec, +} +impl ::prost::Name for ActionDutchAuctionWithdrawView { + const NAME: &'static str = "ActionDutchAuctionWithdrawView"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} +/// An `ActionDutchAuctionSchedule` augmented with additional metadata. +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ActionDutchAuctionScheduleView { + #[prost(message, optional, tag = "1")] + pub action: ::core::option::Option, + #[prost(message, optional, tag = "2")] + pub auction_id: ::core::option::Option, + #[prost(message, optional, tag = "3")] + pub input_metadata: ::core::option::Option, + #[prost(message, optional, tag = "4")] + pub output_metadata: ::core::option::Option< + super::super::super::asset::v1::Metadata, + >, +} +impl ::prost::Name for ActionDutchAuctionScheduleView { + const NAME: &'static str = "ActionDutchAuctionScheduleView"; + const PACKAGE: &'static str = "penumbra.core.component.auction.v1alpha1"; + fn full_name() -> ::prost::alloc::string::String { + ::prost::alloc::format!( + "penumbra.core.component.auction.v1alpha1.{}", Self::NAME + ) + } +} /// Generated client implementations. #[cfg(feature = "rpc")] pub mod query_service_client { diff --git a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs index addb620772..1b8516d301 100644 --- a/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs +++ b/crates/proto/src/gen/penumbra.core.component.auction.v1alpha1.serde.rs @@ -189,6 +189,401 @@ impl<'de> serde::Deserialize<'de> for ActionDutchAuctionSchedule { deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionSchedule", FIELDS, GeneratedVisitor) } } +impl serde::Serialize for ActionDutchAuctionScheduleView { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.action.is_some() { + len += 1; + } + if self.auction_id.is_some() { + len += 1; + } + if self.input_metadata.is_some() { + len += 1; + } + if self.output_metadata.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionScheduleView", len)?; + if let Some(v) = self.action.as_ref() { + struct_ser.serialize_field("action", v)?; + } + if let Some(v) = self.auction_id.as_ref() { + struct_ser.serialize_field("auctionId", v)?; + } + if let Some(v) = self.input_metadata.as_ref() { + struct_ser.serialize_field("inputMetadata", v)?; + } + if let Some(v) = self.output_metadata.as_ref() { + struct_ser.serialize_field("outputMetadata", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ActionDutchAuctionScheduleView { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "action", + "auction_id", + "auctionId", + "input_metadata", + "inputMetadata", + "output_metadata", + "outputMetadata", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Action, + AuctionId, + InputMetadata, + OutputMetadata, + __SkipField__, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "action" => Ok(GeneratedField::Action), + "auctionId" | "auction_id" => Ok(GeneratedField::AuctionId), + "inputMetadata" | "input_metadata" => Ok(GeneratedField::InputMetadata), + "outputMetadata" | "output_metadata" => Ok(GeneratedField::OutputMetadata), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ActionDutchAuctionScheduleView; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.ActionDutchAuctionScheduleView") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut action__ = None; + let mut auction_id__ = None; + let mut input_metadata__ = None; + let mut output_metadata__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Action => { + if action__.is_some() { + return Err(serde::de::Error::duplicate_field("action")); + } + action__ = map_.next_value()?; + } + GeneratedField::AuctionId => { + if auction_id__.is_some() { + return Err(serde::de::Error::duplicate_field("auctionId")); + } + auction_id__ = map_.next_value()?; + } + GeneratedField::InputMetadata => { + if input_metadata__.is_some() { + return Err(serde::de::Error::duplicate_field("inputMetadata")); + } + input_metadata__ = map_.next_value()?; + } + GeneratedField::OutputMetadata => { + if output_metadata__.is_some() { + return Err(serde::de::Error::duplicate_field("outputMetadata")); + } + output_metadata__ = map_.next_value()?; + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(ActionDutchAuctionScheduleView { + action: action__, + auction_id: auction_id__, + input_metadata: input_metadata__, + output_metadata: output_metadata__, + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionScheduleView", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ActionDutchAuctionWithdraw { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.auction_id.is_some() { + len += 1; + } + if self.seq != 0 { + len += 1; + } + if self.reserves_commitment.is_some() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdraw", len)?; + if let Some(v) = self.auction_id.as_ref() { + struct_ser.serialize_field("auctionId", v)?; + } + if self.seq != 0 { + #[allow(clippy::needless_borrow)] + struct_ser.serialize_field("seq", ToString::to_string(&self.seq).as_str())?; + } + if let Some(v) = self.reserves_commitment.as_ref() { + struct_ser.serialize_field("reservesCommitment", v)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ActionDutchAuctionWithdraw { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "auction_id", + "auctionId", + "seq", + "reserves_commitment", + "reservesCommitment", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + AuctionId, + Seq, + ReservesCommitment, + __SkipField__, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "auctionId" | "auction_id" => Ok(GeneratedField::AuctionId), + "seq" => Ok(GeneratedField::Seq), + "reservesCommitment" | "reserves_commitment" => Ok(GeneratedField::ReservesCommitment), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ActionDutchAuctionWithdraw; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdraw") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut auction_id__ = None; + let mut seq__ = None; + let mut reserves_commitment__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::AuctionId => { + if auction_id__.is_some() { + return Err(serde::de::Error::duplicate_field("auctionId")); + } + auction_id__ = map_.next_value()?; + } + GeneratedField::Seq => { + if seq__.is_some() { + return Err(serde::de::Error::duplicate_field("seq")); + } + seq__ = + Some(map_.next_value::<::pbjson::private::NumberDeserialize<_>>()?.0) + ; + } + GeneratedField::ReservesCommitment => { + if reserves_commitment__.is_some() { + return Err(serde::de::Error::duplicate_field("reservesCommitment")); + } + reserves_commitment__ = map_.next_value()?; + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(ActionDutchAuctionWithdraw { + auction_id: auction_id__, + seq: seq__.unwrap_or_default(), + reserves_commitment: reserves_commitment__, + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdraw", FIELDS, GeneratedVisitor) + } +} +impl serde::Serialize for ActionDutchAuctionWithdrawView { + #[allow(deprecated)] + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + use serde::ser::SerializeStruct; + let mut len = 0; + if self.action.is_some() { + len += 1; + } + if !self.reserves.is_empty() { + len += 1; + } + let mut struct_ser = serializer.serialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdrawView", len)?; + if let Some(v) = self.action.as_ref() { + struct_ser.serialize_field("action", v)?; + } + if !self.reserves.is_empty() { + struct_ser.serialize_field("reserves", &self.reserves)?; + } + struct_ser.end() + } +} +impl<'de> serde::Deserialize<'de> for ActionDutchAuctionWithdrawView { + #[allow(deprecated)] + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + const FIELDS: &[&str] = &[ + "action", + "reserves", + ]; + + #[allow(clippy::enum_variant_names)] + enum GeneratedField { + Action, + Reserves, + __SkipField__, + } + impl<'de> serde::Deserialize<'de> for GeneratedField { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + struct GeneratedVisitor; + + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = GeneratedField; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "expected one of: {:?}", &FIELDS) + } + + #[allow(unused_variables)] + fn visit_str(self, value: &str) -> std::result::Result + where + E: serde::de::Error, + { + match value { + "action" => Ok(GeneratedField::Action), + "reserves" => Ok(GeneratedField::Reserves), + _ => Ok(GeneratedField::__SkipField__), + } + } + } + deserializer.deserialize_identifier(GeneratedVisitor) + } + } + struct GeneratedVisitor; + impl<'de> serde::de::Visitor<'de> for GeneratedVisitor { + type Value = ActionDutchAuctionWithdrawView; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("struct penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdrawView") + } + + fn visit_map(self, mut map_: V) -> std::result::Result + where + V: serde::de::MapAccess<'de>, + { + let mut action__ = None; + let mut reserves__ = None; + while let Some(k) = map_.next_key()? { + match k { + GeneratedField::Action => { + if action__.is_some() { + return Err(serde::de::Error::duplicate_field("action")); + } + action__ = map_.next_value()?; + } + GeneratedField::Reserves => { + if reserves__.is_some() { + return Err(serde::de::Error::duplicate_field("reserves")); + } + reserves__ = Some(map_.next_value()?); + } + GeneratedField::__SkipField__ => { + let _ = map_.next_value::()?; + } + } + } + Ok(ActionDutchAuctionWithdrawView { + action: action__, + reserves: reserves__.unwrap_or_default(), + }) + } + } + deserializer.deserialize_struct("penumbra.core.component.auction.v1alpha1.ActionDutchAuctionWithdrawView", FIELDS, GeneratedVisitor) + } +} impl serde::Serialize for AuctionId { #[allow(deprecated)] fn serialize(&self, serializer: S) -> std::result::Result diff --git a/crates/proto/src/gen/proto_descriptor.bin.no_lfs b/crates/proto/src/gen/proto_descriptor.bin.no_lfs index 6ff75478eb..db36c4744d 100644 Binary files a/crates/proto/src/gen/proto_descriptor.bin.no_lfs and b/crates/proto/src/gen/proto_descriptor.bin.no_lfs differ diff --git a/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto b/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto index 1afde18708..809c5b51cf 100644 --- a/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto +++ b/proto/penumbra/penumbra/core/component/auction/v1alpha1/auction.proto @@ -100,3 +100,33 @@ message ActionDutchAuctionEnd { // The auction to end. AuctionId auction_id = 1; } + +// Withdraw funds from the ended auction associated with the specified `auction_id` +message ActionDutchAuctionWithdraw { + // The auction to withdraw funds from. + AuctionId auction_id = 1; + // The sequence number of the withdrawal. + uint64 seq = 2; + // A transparent (zero blinding factor) commitment to the + // auction's final reserves. + // + // The chain will check this commitment by recomputing it + // with the on-chain state. + asset.v1.BalanceCommitment reserves_commitment = 3; +} + +// An `ActionDutchAuctionWithdraw` augmented with additional metadata. +message ActionDutchAuctionWithdrawView { + ActionDutchAuctionWithdraw action = 1; + // A sequence of values that sum together to the provided + // reserves commitment. + repeated asset.v1.ValueView reserves = 2; +} + +// An `ActionDutchAuctionSchedule` augmented with additional metadata. +message ActionDutchAuctionScheduleView { + ActionDutchAuctionSchedule action = 1; + AuctionId auction_id = 2; + asset.v1.Metadata input_metadata = 3; + asset.v1.Metadata output_metadata = 4; +}