Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

proto: add extra metadata fields to SwapView.Opaque #4164

Merged
merged 4 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/bin/pcli/src/transaction_view_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ impl TransactionViewExt for TransactionView {

["Swap", &action]
}
SwapView::Opaque { swap } => {
SwapView::Opaque { swap, .. } => {
action = format!(
"Opaque swap for trading pair: {} <=> {}",
format_asset_id(&swap.body.trading_pair.asset_1()),
Expand Down
31 changes: 28 additions & 3 deletions crates/core/component/dex/src/swap/view.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use penumbra_asset::asset::Metadata;
use penumbra_asset::{asset::Metadata, ValueView};
use penumbra_proto::{penumbra::core::component::dex::v1 as pb, DomainType};
use penumbra_shielded_pool::NoteView;
use penumbra_txhash::TransactionId;
Expand All @@ -24,6 +24,11 @@ pub enum SwapView {
},
Opaque {
swap: Swap,
batch_swap_output_data: Option<BatchSwapOutputData>,
output_1: Option<ValueView>,
output_2: Option<ValueView>,
asset_1_metadata: Option<Metadata>,
asset_2_metadata: Option<Metadata>,
},
}

Expand Down Expand Up @@ -63,6 +68,14 @@ impl TryFrom<pb::SwapView> for SwapView {
.swap
.ok_or_else(|| anyhow::anyhow!("missing swap field"))?
.try_into()?,
batch_swap_output_data: x
.batch_swap_output_data
.map(TryInto::try_into)
.transpose()?,
output_1: x.output_1_value.map(TryInto::try_into).transpose()?,
output_2: x.output_2_value.map(TryInto::try_into).transpose()?,
asset_1_metadata: x.asset_1_metadata.map(TryInto::try_into).transpose()?,
asset_2_metadata: x.asset_2_metadata.map(TryInto::try_into).transpose()?,
}),
}
}
Expand Down Expand Up @@ -93,9 +106,21 @@ impl From<SwapView> for pb::SwapView {
batch_swap_output_data: batch_swap_output_data.map(Into::into),
})),
},
SwapView::Opaque { swap } => Self {
SwapView::Opaque {
swap,
batch_swap_output_data,
output_1,
output_2,
asset_1_metadata,
asset_2_metadata,
} => Self {
swap_view: Some(sv::SwapView::Opaque(sv::Opaque {
swap: Some(swap.into()),
batch_swap_output_data: batch_swap_output_data.map(Into::into),
output_1_value: output_1.map(Into::into),
output_2_value: output_2.map(Into::into),
asset_1_metadata: asset_1_metadata.map(Into::into),
asset_2_metadata: asset_2_metadata.map(Into::into),
})),
},
}
Expand All @@ -106,7 +131,7 @@ impl From<SwapView> for Swap {
fn from(v: SwapView) -> Self {
match v {
SwapView::Visible { swap, .. } => swap,
SwapView::Opaque { swap } => swap,
SwapView::Opaque { swap, .. } => swap,
}
}
}
62 changes: 59 additions & 3 deletions crates/core/transaction/src/is_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,65 @@ impl IsAction for Swap {
.cloned(),
}
}
None => SwapView::Opaque {
swap: self.to_owned(),
},
None => {
// If we can find a matching BSOD in the TxP, we can use it to compute the output notes
// for the swap.
let bsod = txp
.batch_swap_output_data
.iter()
// This finds the first matching one; there should only be one
// per trading pair per block and we trust the TxP provider not to lie about it.
jessepinho marked this conversation as resolved.
Show resolved Hide resolved
.find(|bsod| bsod.trading_pair == self.body.trading_pair);

// We can get the denom metadata whether we get a BSOD or not

let denom_1 = txp.denoms.get(&self.body.trading_pair.asset_1()).cloned();
let denom_2 = txp.denoms.get(&self.body.trading_pair.asset_2()).cloned();

match bsod {
None => {
// If we can't find a matching BSOD, we can't compute the output notes
// for the swap.
// TODO: is defaulting to 'None' the right behavior here, or is not matching on a BSOD as above an error?
cratelyn marked this conversation as resolved.
Show resolved Hide resolved
SwapView::Opaque {
swap: self.to_owned(),
batch_swap_output_data: None,
output_1: None,
output_2: None,
asset_1_metadata: denom_1.clone(),
asset_2_metadata: denom_2.clone(),
}
}
Some(bsod) => {
// If we can find a matching BSOD, use it to compute the output notes
// for the swap.

let (lambda_1_i, lambda_2_i) =
bsod.pro_rata_outputs((self.body.delta_1_i, self.body.delta_2_i));

SwapView::Opaque {
swap: self.to_owned(),
batch_swap_output_data: Some(bsod.clone()),
asset_1_metadata: denom_1.clone(),
asset_2_metadata: denom_2.clone(),
output_1: Some(
Value {
amount: lambda_1_i,
asset_id: self.body.trading_pair.asset_1(),
}
.view_with_cache(&txp.denoms),
),
output_2: Some(
Value {
amount: lambda_2_i,
asset_id: self.body.trading_pair.asset_2(),
}
.view_with_cache(&txp.denoms),
),
}
}
}
}
})
}
}
Expand Down
35 changes: 35 additions & 0 deletions crates/proto/src/gen/penumbra.core.component.dex.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,41 @@ pub mod swap_view {
pub struct Opaque {
#[prost(message, optional, tag = "1")]
pub swap: ::core::option::Option<super::Swap>,
/// Optionally, if the swap has been confirmed, the batch price it received.
///
/// As soon as the swap is detected, the view server can in principle record
/// the relevant BSOD and provide it as part of the view. This allows providing
/// info about the execution of the swap.
#[prost(message, optional, tag = "20")]
pub batch_swap_output_data: ::core::option::Option<super::BatchSwapOutputData>,
/// Optionally, if the swap has been confirmed, the output value of asset 1.
///
/// This is the value of the note that will be minted by the SwapClaim action.
/// Note that unlike the `Visible` variant, this is only a `ValueView` since
/// the details of the note (in particular the claim address) are not publicly known.
#[prost(message, optional, tag = "30")]
pub output_1_value: ::core::option::Option<
super::super::super::super::asset::v1::ValueView,
>,
/// Optionally, if the swap has been confirmed, the output value of asset 2.
///
/// This is the note that will be minted by the SwapClaim action.
/// Note that unlike the `Visible` variant, this is only a `ValueView` since
/// the details of the note (in particular the claim address) are not publicly known.
#[prost(message, optional, tag = "31")]
pub output_2_value: ::core::option::Option<
super::super::super::super::asset::v1::ValueView,
>,
/// Optionally, metadata about asset 1 in the `swap`'s trading pair.
#[prost(message, optional, tag = "40")]
pub asset_1_metadata: ::core::option::Option<
super::super::super::super::asset::v1::Metadata,
>,
/// Optionally, metadata about asset 2 in the `swap`'s trading pair.
#[prost(message, optional, tag = "41")]
pub asset_2_metadata: ::core::option::Option<
super::super::super::super::asset::v1::Metadata,
>,
}
impl ::prost::Name for Opaque {
const NAME: &'static str = "Opaque";
Expand Down
90 changes: 90 additions & 0 deletions crates/proto/src/gen/penumbra.core.component.dex.v1.serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8215,10 +8215,40 @@ impl serde::Serialize for swap_view::Opaque {
if self.swap.is_some() {
len += 1;
}
if self.batch_swap_output_data.is_some() {
len += 1;
}
if self.output_1_value.is_some() {
len += 1;
}
if self.output_2_value.is_some() {
len += 1;
}
if self.asset_1_metadata.is_some() {
len += 1;
}
if self.asset_2_metadata.is_some() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.core.component.dex.v1.SwapView.Opaque", len)?;
if let Some(v) = self.swap.as_ref() {
struct_ser.serialize_field("swap", v)?;
}
if let Some(v) = self.batch_swap_output_data.as_ref() {
struct_ser.serialize_field("batchSwapOutputData", v)?;
}
if let Some(v) = self.output_1_value.as_ref() {
struct_ser.serialize_field("output1Value", v)?;
}
if let Some(v) = self.output_2_value.as_ref() {
struct_ser.serialize_field("output2Value", v)?;
}
if let Some(v) = self.asset_1_metadata.as_ref() {
struct_ser.serialize_field("asset1Metadata", v)?;
}
if let Some(v) = self.asset_2_metadata.as_ref() {
struct_ser.serialize_field("asset2Metadata", v)?;
}
struct_ser.end()
}
}
Expand All @@ -8230,11 +8260,26 @@ impl<'de> serde::Deserialize<'de> for swap_view::Opaque {
{
const FIELDS: &[&str] = &[
"swap",
"batch_swap_output_data",
"batchSwapOutputData",
"output_1_value",
"output1Value",
"output_2_value",
"output2Value",
"asset_1_metadata",
"asset1Metadata",
"asset_2_metadata",
"asset2Metadata",
];

#[allow(clippy::enum_variant_names)]
enum GeneratedField {
Swap,
BatchSwapOutputData,
Output1Value,
Output2Value,
Asset1Metadata,
Asset2Metadata,
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
Expand All @@ -8258,6 +8303,11 @@ impl<'de> serde::Deserialize<'de> for swap_view::Opaque {
{
match value {
"swap" => Ok(GeneratedField::Swap),
"batchSwapOutputData" | "batch_swap_output_data" => Ok(GeneratedField::BatchSwapOutputData),
"output1Value" | "output_1_value" => Ok(GeneratedField::Output1Value),
"output2Value" | "output_2_value" => Ok(GeneratedField::Output2Value),
"asset1Metadata" | "asset_1_metadata" => Ok(GeneratedField::Asset1Metadata),
"asset2Metadata" | "asset_2_metadata" => Ok(GeneratedField::Asset2Metadata),
_ => Ok(GeneratedField::__SkipField__),
}
}
Expand All @@ -8278,6 +8328,11 @@ impl<'de> serde::Deserialize<'de> for swap_view::Opaque {
V: serde::de::MapAccess<'de>,
{
let mut swap__ = None;
let mut batch_swap_output_data__ = None;
let mut output_1_value__ = None;
let mut output_2_value__ = None;
let mut asset_1_metadata__ = None;
let mut asset_2_metadata__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Swap => {
Expand All @@ -8286,13 +8341,48 @@ impl<'de> serde::Deserialize<'de> for swap_view::Opaque {
}
swap__ = map_.next_value()?;
}
GeneratedField::BatchSwapOutputData => {
if batch_swap_output_data__.is_some() {
return Err(serde::de::Error::duplicate_field("batchSwapOutputData"));
}
batch_swap_output_data__ = map_.next_value()?;
}
GeneratedField::Output1Value => {
if output_1_value__.is_some() {
return Err(serde::de::Error::duplicate_field("output1Value"));
}
output_1_value__ = map_.next_value()?;
}
GeneratedField::Output2Value => {
if output_2_value__.is_some() {
return Err(serde::de::Error::duplicate_field("output2Value"));
}
output_2_value__ = map_.next_value()?;
}
GeneratedField::Asset1Metadata => {
if asset_1_metadata__.is_some() {
return Err(serde::de::Error::duplicate_field("asset1Metadata"));
}
asset_1_metadata__ = map_.next_value()?;
}
GeneratedField::Asset2Metadata => {
if asset_2_metadata__.is_some() {
return Err(serde::de::Error::duplicate_field("asset2Metadata"));
}
asset_2_metadata__ = map_.next_value()?;
}
GeneratedField::__SkipField__ => {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
}
}
Ok(swap_view::Opaque {
swap: swap__,
batch_swap_output_data: batch_swap_output_data__,
output_1_value: output_1_value__,
output_2_value: output_2_value__,
asset_1_metadata: asset_1_metadata__,
asset_2_metadata: asset_2_metadata__,
})
}
}
Expand Down
22 changes: 22 additions & 0 deletions proto/penumbra/penumbra/core/component/dex/v1/dex.proto
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,28 @@ message SwapView {

message Opaque {
dex.v1.Swap swap = 1;
// Optionally, if the swap has been confirmed, the batch price it received.
//
// As soon as the swap is detected, the view server can in principle record
// the relevant BSOD and provide it as part of the view. This allows providing
// info about the execution of the swap.
BatchSwapOutputData batch_swap_output_data = 20;
// Optionally, if the swap has been confirmed, the output value of asset 1.
//
// This is the value of the note that will be minted by the SwapClaim action.
// Note that unlike the `Visible` variant, this is only a `ValueView` since
// the details of the note (in particular the claim address) are not publicly known.
asset.v1.ValueView output_1_value = 30;
// Optionally, if the swap has been confirmed, the output value of asset 2.
//
// This is the note that will be minted by the SwapClaim action.
// Note that unlike the `Visible` variant, this is only a `ValueView` since
// the details of the note (in particular the claim address) are not publicly known.
asset.v1.ValueView output_2_value = 31;
// Optionally, metadata about asset 1 in the `swap`'s trading pair.
asset.v1.Metadata asset_1_metadata = 40;
// Optionally, metadata about asset 2 in the `swap`'s trading pair.
asset.v1.Metadata asset_2_metadata = 41;
}

oneof swap_view {
Expand Down
Loading