Skip to content

Commit 20346b9

Browse files
committed
Added new flow for shielding over ibc
1 parent ff00f67 commit 20346b9

File tree

25 files changed

+502
-183
lines changed

25 files changed

+502
-183
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/apps_lib/src/client/tx.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,15 @@ use namada_sdk::collections::HashMap;
2222
use namada_sdk::governance::cli::onchain::{
2323
DefaultProposal, PgfFundingProposal, PgfStewardProposal,
2424
};
25-
use namada_sdk::ibc::convert_masp_tx_to_ibc_memo;
2625
use namada_sdk::io::{Io, display_line, edisplay_line};
2726
use namada_sdk::key::*;
2827
use namada_sdk::rpc::{InnerTxResult, TxBroadcastData, TxResponse};
2928
use namada_sdk::state::EPOCH_SWITCH_BLOCKS_DELAY;
3029
use namada_sdk::tx::data::compute_inner_tx_hash;
31-
use namada_sdk::tx::{CompressedAuthorization, Section, Signer, Tx};
30+
use namada_sdk::tx::{
31+
CompressedAuthorization, Section, Signer, Tx,
32+
convert_masp_tx_to_ibc_memo_data,
33+
};
3234
use namada_sdk::wallet::alias::{validator_address, validator_consensus_key};
3335
use namada_sdk::wallet::{Wallet, WalletIo};
3436
use namada_sdk::{ExtendedViewingKey, Namada, error, signing, tx};
@@ -2024,10 +2026,14 @@ pub async fn gen_ibc_shielding_transfer(
20242026
};
20252027
let mut out = File::create(&output_path)
20262028
.expect("Creating a new file for IBC MASP transaction failed.");
2027-
let bytes = convert_masp_tx_to_ibc_memo(
2028-
&masp_tx,
2029-
shielding_fee_payer,
2030-
shielding_fee_token,
2029+
let bytes = String::from(
2030+
convert_masp_tx_to_ibc_memo_data(
2031+
context,
2032+
&masp_tx,
2033+
shielding_fee_payer,
2034+
shielding_fee_token,
2035+
)
2036+
.await?,
20312037
);
20322038
out.write_all(bytes.as_bytes())
20332039
.expect("Writing IBC MASP transaction file failed.");

crates/core/src/masp.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use sha2::Sha256;
2323
use crate::address::{Address, DecodeError, HASH_HEX_LEN, IBC, MASP};
2424
use crate::borsh::BorshSerializeExt;
2525
use crate::chain::Epoch;
26+
use crate::hash::Hash;
2627
use crate::impl_display_and_from_str_via_format;
2728
use crate::string_encoding::{
2829
self, MASP_EXT_FULL_VIEWING_KEY_HRP, MASP_EXT_SPENDING_KEY_HRP,
@@ -79,6 +80,18 @@ impl From<TxIdInner> for MaspTxId {
7980
}
8081
}
8182

83+
impl From<Hash> for MaspTxId {
84+
fn from(hash: Hash) -> Self {
85+
MaspTxId(TxIdInner::from_bytes(hash.0))
86+
}
87+
}
88+
89+
impl From<MaspTxId> for Hash {
90+
fn from(tx_id: MaspTxId) -> Self {
91+
Hash(*tx_id.0.as_ref())
92+
}
93+
}
94+
8295
impl Display for MaspTxId {
8396
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
8497
write!(f, "{}", self.0)

crates/ibc/src/lib.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@ use ibc::core::router::types::error::RouterError;
8383
use ibc::primitives::proto::Any;
8484
pub use ibc::*;
8585
use ibc_middleware_packet_forward::PacketMetadata;
86-
use masp_primitives::transaction::Transaction as MaspTransaction;
8786
pub use msg::*;
8887
use namada_core::address::{self, Address};
8988
use namada_core::arith::{CheckedAdd, CheckedSub, checked};
@@ -101,6 +100,7 @@ use namada_state::{
101100
State, StorageHasher, StorageRead, StorageWrite, WlState,
102101
};
103102
use namada_systems::ibc::ChangedBalances;
103+
pub use namada_systems::ibc::IbcShieldingData;
104104
use namada_systems::trans_token;
105105
pub use nft::*;
106106
use prost::Message;
@@ -239,7 +239,7 @@ where
239239
{
240240
fn try_extract_masp_tx_from_envelope<Transfer: BorshDeserialize>(
241241
tx_data: &[u8],
242-
) -> StorageResult<Option<masp_primitives::transaction::Transaction>> {
242+
) -> StorageResult<Option<IbcShieldingData>> {
243243
let msg = decode_message::<Transfer>(tx_data)
244244
.into_storage_result()
245245
.ok();
@@ -578,7 +578,7 @@ pub struct InternalData<Transfer> {
578578
/// The transparent transfer that happens in parallel to IBC processes
579579
pub transparent: Option<Transfer>,
580580
/// The shielded transaction that happens in parallel to IBC processes
581-
pub shielded: Option<MaspTransaction>,
581+
pub shielded: Option<IbcShieldingData>,
582582
/// IBC tokens that are credited/debited to internal accounts
583583
pub ibc_tokens: BTreeSet<Address>,
584584
}

crates/ibc/src/msg.rs

Lines changed: 7 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
use std::collections::BTreeMap;
2-
use std::fmt;
3-
use std::str::FromStr;
42

53
use borsh::schema::{Declaration, Definition, Fields};
64
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
7-
use data_encoding::HEXUPPER;
85
use ibc::apps::nft_transfer::types::PORT_ID_STR as NFT_PORT_ID_STR;
96
use ibc::apps::nft_transfer::types::msgs::transfer::MsgTransfer as IbcMsgNftTransfer;
107
use ibc::apps::nft_transfer::types::packet::PacketData as NftPacketData;
@@ -18,13 +15,9 @@ use ibc::core::channel::types::packet::Packet;
1815
use ibc::core::handler::types::msgs::MsgEnvelope;
1916
use ibc::core::host::types::identifiers::PortId;
2017
use ibc::primitives::proto::Protobuf;
21-
use masp_primitives::transaction::Transaction as MaspTransaction;
22-
use namada_core::address::Address;
23-
use namada_core::borsh::BorshSerializeExt;
24-
use namada_core::key::common::PublicKey;
25-
use namada_core::string_encoding::StringEncoded;
2618
use serde::{Deserialize, Serialize};
27-
19+
use namada_core::string_encoding::StringEncoded;
20+
use namada_systems::ibc::IbcShieldingData;
2821
use crate::trace;
2922

3023
trait Sealed {}
@@ -238,50 +231,11 @@ impl<Transfer: BorshSchema> BorshSchema for MsgNftTransfer<Transfer> {
238231
}
239232
}
240233

241-
/// Shielding data in IBC packet memo
242-
#[derive(Debug, Clone, BorshDeserialize, BorshSerialize)]
243-
pub struct IbcShieldingData {
244-
/// The MASP transaction that does the shielding
245-
pub masp_tx: MaspTransaction,
246-
/// The account that will pay the shielding fee
247-
pub shielding_fee_payer: PublicKey,
248-
/// The token that the shielding fee will be paid in
249-
pub shielding_fee_token: Address,
250-
}
251-
252-
impl From<&IbcShieldingData> for String {
253-
fn from(data: &IbcShieldingData) -> Self {
254-
HEXUPPER.encode(&data.serialize_to_vec())
255-
}
256-
}
257-
258-
impl From<IbcShieldingData> for String {
259-
fn from(data: IbcShieldingData) -> Self {
260-
(&data).into()
261-
}
262-
}
263-
264-
impl fmt::Display for IbcShieldingData {
265-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266-
write!(f, "{}", String::from(self))
267-
}
268-
}
269-
270-
impl FromStr for IbcShieldingData {
271-
type Err = String;
272-
273-
fn from_str(s: &str) -> Result<Self, Self::Err> {
274-
let bytes = HEXUPPER
275-
.decode(s.as_bytes())
276-
.map_err(|err| err.to_string())?;
277-
IbcShieldingData::try_from_slice(&bytes).map_err(|err| err.to_string())
278-
}
279-
}
280234

281235
/// Extract MASP transaction from IBC envelope
282236
pub fn extract_masp_tx_from_envelope(
283237
envelope: &MsgEnvelope,
284-
) -> Option<MaspTransaction> {
238+
) -> Option<IbcShieldingData> {
285239
match envelope {
286240
MsgEnvelope::Packet(PacketMsg::Recv(msg)) => {
287241
extract_masp_tx_from_packet(&msg.packet)
@@ -308,9 +262,11 @@ pub fn decode_ibc_shielding_data(
308262
}
309263

310264
/// Extract MASP transaction from IBC packet memo
311-
pub fn extract_masp_tx_from_packet(packet: &Packet) -> Option<MaspTransaction> {
265+
pub fn extract_masp_tx_from_packet(
266+
packet: &Packet,
267+
) -> Option<IbcShieldingData> {
312268
let memo = extract_memo_from_packet(packet, &packet.port_id_on_b)?;
313-
decode_ibc_shielding_data(memo).map(|data| data.masp_tx)
269+
decode_ibc_shielding_data(memo)
314270
}
315271

316272
fn extract_memo_from_packet(
@@ -373,17 +329,3 @@ pub fn extract_traces_from_recv_msg(
373329
_ => Ok(vec![]),
374330
}
375331
}
376-
377-
/// Get IBC memo string from MASP transaction for receiving
378-
pub fn convert_masp_tx_to_ibc_memo(
379-
transaction: &MaspTransaction,
380-
shielding_fee_payer: PublicKey,
381-
shielding_fee_token: Address,
382-
) -> String {
383-
IbcShieldingData {
384-
masp_tx: transaction.clone(),
385-
shielding_fee_payer,
386-
shielding_fee_token,
387-
}
388-
.into()
389-
}

crates/sdk/src/args.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use crate::rpc::{
4040
query_ibc_denom, query_osmosis_pool_routes,
4141
};
4242
use crate::signing::{SigningTxData, gen_disposable_signing_key};
43+
use crate::tx::convert_masp_tx_to_ibc_memo_data;
4344
use crate::wallet::{DatedSpendingKey, DatedViewingKey};
4445
use crate::{Namada, rpc, tx};
4546

@@ -745,19 +746,17 @@ impl TxOsmosisSwap<SdkTypes> {
745746
"Failed to generate IBC shielding transfer".to_owned(),
746747
)
747748
})?;
748-
749+
let ibc_memo_data = convert_masp_tx_to_ibc_memo_data(
750+
ctx,
751+
&shielding_tx,
752+
shielded_recipient.shielding_fee_payer,
753+
shielded_recipient.shielding_fee_token,
754+
)
755+
.await?;
749756
let memo = assert_json_obj(
750757
serde_json::to_value(&NamadaMemo {
751758
namada: NamadaMemoData::OsmosisSwap {
752-
shielding_data: StringEncoded::new(
753-
IbcShieldingData {
754-
masp_tx: shielding_tx,
755-
shielding_fee_payer: shielded_recipient
756-
.shielding_fee_payer,
757-
shielding_fee_token: shielded_recipient
758-
.shielding_fee_token,
759-
},
760-
),
759+
shielding_data: StringEncoded::new(ibc_memo_data),
761760
shielded_amount: amount_to_shield,
762761
overflow_receiver,
763762
},

crates/sdk/src/masp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fn extract_masp_tx(
8181

8282
if let Some(transaction) = extract_masp_tx_from_envelope(&envelope)
8383
{
84-
Ok(transaction)
84+
Ok(transaction.masp_tx)
8585
} else {
8686
Err(Error::Other(
8787
"Failed to retrieve MASP over IBC transaction".to_string(),

crates/sdk/src/tx.rs

Lines changed: 50 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ use crate::signing::{
9292
use crate::tendermint_rpc::endpoint::broadcast::tx_sync::Response;
9393
use crate::tendermint_rpc::error::Error as RpcError;
9494
use crate::wallet::WalletIo;
95-
use crate::{Namada, args, events};
95+
use crate::{Namada, args, error, events};
9696

9797
/// Initialize account transaction WASM
9898
pub const TX_INIT_ACCOUNT_WASM: &str = "tx_init_account.wasm";
@@ -2747,9 +2747,12 @@ pub async fn build_ibc_transfer(
27472747
Some(source.clone()),
27482748
Some(source.clone()),
27492749
vec![],
2750-
args.ibc_shielding_data
2751-
.as_ref()
2752-
.map(|shielding_data| shielding_data.shielding_fee_payer.clone()),
2750+
args.ibc_shielding_data.as_ref().map(|shielding_data| {
2751+
shielding_data
2752+
.get_signer()
2753+
.cloned()
2754+
.expect("A MASP fee payer should have been provided")
2755+
}),
27532756
args.source.spending_key().is_some(),
27542757
vec![],
27552758
None,
@@ -2767,17 +2770,15 @@ pub async fn build_ibc_transfer(
27672770
// check that if there is a shielding fee payer, they have enough
27682771
// balance to cover the fee
27692772

2770-
let shielding_fee_payer = if let Some(IbcShieldingData {
2771-
shielding_fee_payer: payer,
2772-
shielding_fee_token,
2773-
..
2774-
}) = &args.ibc_shielding_data
2773+
let shielding_fee_payer = if let Some(data) =
2774+
&args.ibc_shielding_data
27752775
{
27762776
validate_shielding_fee(
27772777
context,
27782778
Some(&mut updated_balance),
2779-
payer,
2780-
shielding_fee_token,
2779+
data.get_signer()
2780+
.expect("A MASP fee payer should have been provided"),
2781+
&data.shielding_fee_token,
27812782
args.tx.force,
27822783
)
27832784
.await?
@@ -2920,16 +2921,14 @@ pub async fn build_ibc_transfer(
29202921
if let Some(memo) = &args.tx.memo {
29212922
tx.add_memo(memo);
29222923
}
2923-
if let Some(IbcShieldingData {
2924-
shielding_fee_payer: payer,
2925-
shielding_fee_token: token,
2926-
masp_tx,
2927-
}) = &args.ibc_shielding_data
2928-
{
2924+
if let Some(data) = &args.ibc_shielding_data {
29292925
tx.add_section(Section::ShieldingFee {
2930-
payer: payer.clone(),
2931-
token: token.clone(),
2932-
cmt: MaspTxId::from(masp_tx.txid()),
2926+
payer: data
2927+
.get_signer()
2928+
.cloned()
2929+
.expect("A MASP fee payer should have been provided"),
2930+
token: data.shielding_fee_token.clone(),
2931+
cmt: MaspTxId::from(data.masp_tx.txid()),
29332932
});
29342933
}
29352934

@@ -4634,3 +4633,34 @@ fn proposal_to_vec(proposal: OnChainProposal) -> Result<Vec<u8>> {
46344633
borsh::to_vec(&proposal.content)
46354634
.map_err(|e| Error::from(EncodingError::Conversion(e.to_string())))
46364635
}
4636+
4637+
/// Get IBC memo string from MASP transaction for receiving
4638+
pub async fn convert_masp_tx_to_ibc_memo_data(
4639+
context: &impl Namada,
4640+
transaction: &MaspTransaction,
4641+
shielding_fee_payer: common::PublicKey,
4642+
shielding_fee_token: Address,
4643+
) -> std::result::Result<IbcShieldingData, error::Error> {
4644+
let mut wallet = context.wallet_lock().write().await;
4645+
let secret_key = wallet
4646+
.find_key_by_pk(&shielding_fee_payer, None)
4647+
.map_err(|err| {
4648+
Error::Other(format!(
4649+
"Unable to load the keypair from the wallet for public key \
4650+
{}. Failed with: {}",
4651+
shielding_fee_payer, err
4652+
))
4653+
})?;
4654+
4655+
let target = MaspTxId::from(transaction.txid());
4656+
let authorization = Authorization::new(
4657+
vec![target.into()],
4658+
BTreeMap::from([(0, secret_key)]),
4659+
None,
4660+
);
4661+
Ok(IbcShieldingData {
4662+
masp_tx: transaction.clone(),
4663+
shielding_fee_authorization: authorization,
4664+
shielding_fee_token,
4665+
})
4666+
}

crates/shielded_token/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,4 @@ impl Default for ShieldedParams {
7878
locked_amount_target: 10_000_u64,
7979
}
8080
}
81-
}
81+
}

0 commit comments

Comments
 (0)