Skip to content

Commit

Permalink
UIP-5: Outbound PFM support (#4940)
Browse files Browse the repository at this point in the history
Implementation of the candidate UIP-5: outbound PFM support (see
https://forum.penumbra.zone/t/pre-uip-outbound-packet-forwarding-middleware-support/121)

Should be reviewed for correctness and adherence to the spec.

Note that this only includes the required protocol changes to allow
clients to use the new memo field (a prerequisite for PFM support), and
does not implement outbound packet forwarding directly (that is to be
done in the client).

By @avahowell cherry-picked from #4923

Co-authored-by: Ava Howell <[email protected]>
(cherry picked from commit 5a66403)
  • Loading branch information
erwanor committed Dec 20, 2024
1 parent c07219b commit 45652ab
Show file tree
Hide file tree
Showing 7 changed files with 38 additions and 1 deletion.
1 change: 1 addition & 0 deletions crates/bin/pcli/src/command/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,7 @@ impl TxCmd {
// TODO: impl From<u64> for ChannelId
source_channel: ChannelId::from_str(format!("channel-{}", channel).as_ref())?,
use_compat_address: *use_compat_address,
ics20_memo: "".to_string(),
};

let plan = Planner::new(OsRng)
Expand Down
1 change: 1 addition & 0 deletions crates/core/app/tests/common/ibc_tests/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1485,6 +1485,7 @@ impl MockRelayer {
source_channel: ChannelId::from_str("channel-0")?,
// Penumbra <-> Penumbra so false
use_compat_address: false,
ics20_memo: "".to_string(),
};
// There will need to be `Spend` and `Output` actions
// within the transaction in order for it to balance
Expand Down
9 changes: 8 additions & 1 deletion crates/core/component/shielded-pool/src/ics20_withdrawal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ pub struct Ics20Withdrawal {
// Whether to use a "compat" (bech32, non-m) address for the return address in the withdrawal,
// for compatability with chains that expect to be able to parse the return address as bech32.
pub use_compat_address: bool,

// Arbitrary string data to be included in the `memo` field
// of the ICS-20 FungibleTokenPacketData for this withdrawal.
// Commonly used for packet forwarding support, or other protocols that may support usage of the memo field.
pub ics20_memo: String,
}

#[cfg(feature = "component")]
Expand Down Expand Up @@ -118,6 +123,7 @@ impl From<Ics20Withdrawal> for pb::Ics20Withdrawal {
timeout_time: w.timeout_time,
source_channel: w.source_channel.to_string(),
use_compat_address: w.use_compat_address,
ics20_memo: w.ics20_memo.to_string(),
}
}
}
Expand Down Expand Up @@ -148,6 +154,7 @@ impl TryFrom<pb::Ics20Withdrawal> for Ics20Withdrawal {
timeout_time: s.timeout_time,
source_channel: ChannelId::from_str(&s.source_channel)?,
use_compat_address: s.use_compat_address,
ics20_memo: s.ics20_memo,
})
}
}
Expand All @@ -164,7 +171,7 @@ impl From<Ics20Withdrawal> for pb::FungibleTokenPacketData {
denom: w.denom.to_string(),
receiver: w.destination_chain_address,
sender: return_address,
memo: "".to_string(),
memo: w.ics20_memo,
}
}
}
5 changes: 5 additions & 0 deletions crates/proto/src/gen/penumbra.core.component.ibc.v1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ pub struct Ics20Withdrawal {
/// for compatability with chains that expect to be able to parse the return address as bech32.
#[prost(bool, tag = "8")]
pub use_compat_address: bool,
/// Arbitrary string data to be included in the `memo` field
/// of the ICS-20 FungibleTokenPacketData for this withdrawal.
/// Commonly used for packet forwarding support, or other protocols that may support usage of the memo field.
#[prost(string, tag = "9")]
pub ics20_memo: ::prost::alloc::string::String,
}
impl ::prost::Name for Ics20Withdrawal {
const NAME: &'static str = "Ics20Withdrawal";
Expand Down
18 changes: 18 additions & 0 deletions crates/proto/src/gen/penumbra.core.component.ibc.v1.serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,9 @@ impl serde::Serialize for Ics20Withdrawal {
if self.use_compat_address {
len += 1;
}
if !self.ics20_memo.is_empty() {
len += 1;
}
let mut struct_ser = serializer.serialize_struct("penumbra.core.component.ibc.v1.Ics20Withdrawal", len)?;
if let Some(v) = self.amount.as_ref() {
struct_ser.serialize_field("amount", v)?;
Expand All @@ -1083,6 +1086,9 @@ impl serde::Serialize for Ics20Withdrawal {
if self.use_compat_address {
struct_ser.serialize_field("useCompatAddress", &self.use_compat_address)?;
}
if !self.ics20_memo.is_empty() {
struct_ser.serialize_field("ics20Memo", &self.ics20_memo)?;
}
struct_ser.end()
}
}
Expand All @@ -1107,6 +1113,8 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
"sourceChannel",
"use_compat_address",
"useCompatAddress",
"ics20_memo",
"ics20Memo",
];

#[allow(clippy::enum_variant_names)]
Expand All @@ -1119,6 +1127,7 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
TimeoutTime,
SourceChannel,
UseCompatAddress,
Ics20Memo,
__SkipField__,
}
impl<'de> serde::Deserialize<'de> for GeneratedField {
Expand Down Expand Up @@ -1149,6 +1158,7 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
"timeoutTime" | "timeout_time" => Ok(GeneratedField::TimeoutTime),
"sourceChannel" | "source_channel" => Ok(GeneratedField::SourceChannel),
"useCompatAddress" | "use_compat_address" => Ok(GeneratedField::UseCompatAddress),
"ics20Memo" | "ics20_memo" => Ok(GeneratedField::Ics20Memo),
_ => Ok(GeneratedField::__SkipField__),
}
}
Expand Down Expand Up @@ -1176,6 +1186,7 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
let mut timeout_time__ = None;
let mut source_channel__ = None;
let mut use_compat_address__ = None;
let mut ics20_memo__ = None;
while let Some(k) = map_.next_key()? {
match k {
GeneratedField::Amount => {
Expand Down Expand Up @@ -1228,6 +1239,12 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
}
use_compat_address__ = Some(map_.next_value()?);
}
GeneratedField::Ics20Memo => {
if ics20_memo__.is_some() {
return Err(serde::de::Error::duplicate_field("ics20Memo"));
}
ics20_memo__ = Some(map_.next_value()?);
}
GeneratedField::__SkipField__ => {
let _ = map_.next_value::<serde::de::IgnoredAny>()?;
}
Expand All @@ -1242,6 +1259,7 @@ impl<'de> serde::Deserialize<'de> for Ics20Withdrawal {
timeout_time: timeout_time__.unwrap_or_default(),
source_channel: source_channel__.unwrap_or_default(),
use_compat_address: use_compat_address__.unwrap_or_default(),
ics20_memo: ics20_memo__.unwrap_or_default(),
})
}
}
Expand Down
Binary file modified crates/proto/src/gen/proto_descriptor.bin.no_lfs
Binary file not shown.
5 changes: 5 additions & 0 deletions proto/penumbra/penumbra/core/component/ibc/v1/ibc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ message Ics20Withdrawal {
// Whether to use a "compat" (bech32, non-m) address for the return address in the withdrawal,
// for compatability with chains that expect to be able to parse the return address as bech32.
bool use_compat_address = 8;

// Arbitrary string data to be included in the `memo` field
// of the ICS-20 FungibleTokenPacketData for this withdrawal.
// Commonly used for packet forwarding support, or other protocols that may support usage of the memo field.
string ics20_memo = 9;
}

message ClientData {
Expand Down

0 comments on commit 45652ab

Please sign in to comment.