namada_sdk/
args.rs

1//! Structures encapsulating SDK arguments
2
3use std::borrow::Cow;
4use std::fmt::Display;
5use std::path::PathBuf;
6use std::str::FromStr;
7use std::time::Duration as StdDuration;
8
9use either::Either;
10use masp_primitives::transaction::components::sapling::builder::BuildParams;
11use masp_primitives::zip32::PseudoExtendedKey;
12use namada_core::address::{Address, MASP};
13use namada_core::chain::{BlockHeight, ChainId, Epoch};
14use namada_core::collections::HashMap;
15use namada_core::dec::Dec;
16use namada_core::ethereum_events::EthAddress;
17use namada_core::keccak::KeccakHash;
18use namada_core::key::{SchemeType, common};
19use namada_core::masp::{DiversifierIndex, MaspEpoch, PaymentAddress};
20use namada_core::string_encoding::StringEncoded;
21use namada_core::time::DateTimeUtc;
22use namada_core::token::Amount;
23use namada_core::{storage, token};
24use namada_governance::cli::onchain::{
25    DefaultProposal, PgfFundingProposal, PgfStewardProposal,
26};
27use namada_ibc::IbcShieldingData;
28use namada_io::{Io, display_line};
29use namada_token::masp::utils::RetryStrategy;
30use namada_tx::Memo;
31use namada_tx::data::GasLimit;
32use serde::{Deserialize, Serialize};
33use zeroize::Zeroizing;
34
35use crate::error::Error;
36use crate::eth_bridge::bridge_pool;
37use crate::ibc::core::host::types::identifiers::{ChannelId, PortId};
38use crate::ibc::{NamadaMemo, NamadaMemoData};
39use crate::rpc::{
40    get_registry_from_xcs_osmosis_contract, osmosis_denom_from_namada_denom,
41    query_ibc_denom, query_osmosis_route_and_min_out,
42};
43use crate::signing::{SigningData, gen_disposable_signing_key};
44use crate::wallet::{DatedSpendingKey, DatedViewingKey};
45use crate::{Namada, rpc, tx};
46
47/// [`Duration`](StdDuration) wrapper that provides a
48/// method to parse a value from a string.
49#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
50#[repr(transparent)]
51pub struct Duration(pub StdDuration);
52
53impl ::std::str::FromStr for Duration {
54    type Err = String;
55
56    #[inline]
57    fn from_str(s: &str) -> Result<Self, Self::Err> {
58        ::duration_str::parse(s).map(Duration)
59    }
60}
61
62/// Abstraction of types being used in Namada
63pub trait NamadaTypes: Clone + std::fmt::Debug {
64    /// Represents an address on the ledger
65    type Address: Clone + std::fmt::Debug;
66    /// Represents an address that defaults to a native token
67    type AddrOrNativeToken: Clone + std::fmt::Debug + From<Self::Address>;
68    /// Represents a key pair
69    type Keypair: Clone + std::fmt::Debug;
70    /// Represents the address of a Tendermint endpoint (used in context-less
71    /// CLI commands where chain config isn't available)
72    type TendermintAddress: Clone + std::fmt::Debug;
73    /// RPC address of a locally configured node
74    type ConfigRpcTendermintAddress: Clone
75        + std::fmt::Debug
76        + From<Self::TendermintAddress>;
77    /// Represents the address of an Ethereum endpoint
78    type EthereumAddress: Clone + std::fmt::Debug;
79    /// Represents a shielded viewing key
80    type ViewingKey: Clone + std::fmt::Debug;
81    /// Represents a shielded spending key
82    type SpendingKey: Clone + std::fmt::Debug;
83    /// Represents a shielded viewing key
84    type DatedViewingKey: Clone + std::fmt::Debug;
85    /// Represents a shielded spending key
86    type DatedSpendingKey: Clone + std::fmt::Debug;
87    /// Represents a shielded payment address
88    type PaymentAddress: Clone + std::fmt::Debug;
89    /// Represents the owner of a balance
90    type BalanceOwner: Clone + std::fmt::Debug;
91    /// Represents a public key
92    type PublicKey: Clone + std::fmt::Debug;
93    /// Represents the source of a Transfer
94    type TransferSource: Clone + std::fmt::Debug;
95    /// Represents the target of a Transfer
96    type TransferTarget: Clone + std::fmt::Debug;
97    /// Represents some data that is used in a transaction
98    type Data: Clone + std::fmt::Debug;
99    /// Bridge pool recommendations conversion rates table.
100    type BpConversionTable: Clone + std::fmt::Debug;
101    /// Address of a `namada-masp-indexer` live instance
102    type MaspIndexerAddress: Clone + std::fmt::Debug;
103    /// Represents a block height
104    type BlockHeight: Clone + std::fmt::Debug;
105}
106
107/// The concrete types being used in Namada SDK
108#[derive(Clone, Debug)]
109pub struct SdkTypes;
110
111/// An entry in the Bridge pool recommendations conversion
112/// rates table.
113#[derive(Clone, Debug, Serialize, Deserialize)]
114pub struct BpConversionTableEntry {
115    /// An alias for the token, or the string representation
116    /// of its address if none is available.
117    pub alias: String,
118    /// Conversion rate from the given token to gwei.
119    pub conversion_rate: f64,
120}
121
122impl NamadaTypes for SdkTypes {
123    type AddrOrNativeToken = Address;
124    type Address = Address;
125    type BalanceOwner = namada_core::masp::BalanceOwner;
126    type BlockHeight = namada_core::chain::BlockHeight;
127    type BpConversionTable = HashMap<Address, BpConversionTableEntry>;
128    type ConfigRpcTendermintAddress = tendermint_rpc::Url;
129    type Data = Vec<u8>;
130    type DatedSpendingKey = DatedSpendingKey;
131    type DatedViewingKey = DatedViewingKey;
132    type EthereumAddress = ();
133    type Keypair = namada_core::key::common::SecretKey;
134    type MaspIndexerAddress = String;
135    type PaymentAddress = namada_core::masp::PaymentAddress;
136    type PublicKey = namada_core::key::common::PublicKey;
137    type SpendingKey = PseudoExtendedKey;
138    type TendermintAddress = tendermint_rpc::Url;
139    type TransferSource = namada_core::masp::TransferSource;
140    type TransferTarget = namada_core::masp::TransferTarget;
141    type ViewingKey = namada_core::masp::ExtendedViewingKey;
142}
143
144/// Common query arguments
145#[derive(Clone, Debug)]
146pub struct Query<C: NamadaTypes = SdkTypes> {
147    /// The address of the ledger node as host:port
148    pub ledger_address: C::ConfigRpcTendermintAddress,
149}
150
151/// Common query arguments
152#[derive(Clone, Debug)]
153pub struct QueryWithoutCtx<C: NamadaTypes = SdkTypes> {
154    /// The address of the ledger node as host:port
155    pub ledger_address: C::TendermintAddress,
156}
157
158/// Transaction associated results arguments
159#[derive(Clone, Debug)]
160pub struct QueryResult<C: NamadaTypes = SdkTypes> {
161    /// Common query args
162    pub query: Query<C>,
163    /// Hash of transaction to lookup
164    pub tx_hash: String,
165}
166
167/// Custom transaction arguments
168#[derive(Clone, Debug)]
169pub struct TxCustom<C: NamadaTypes = SdkTypes> {
170    /// Common tx arguments
171    pub tx: Tx<C>,
172    /// Path to the tx WASM code file
173    pub code_path: Option<PathBuf>,
174    /// Path to the data file
175    pub data_path: Option<C::Data>,
176    /// Path to the serialized transaction
177    pub serialized_tx: Option<C::Data>,
178    /// The optional address that correspond to the signatures/signing-keys
179    pub owner: Option<C::Address>,
180    /// List of signatures to attach to the transaction
181    pub signatures: Vec<C::Data>,
182    /// Optional path to a serialized wrapper signature
183    pub wrapper_signature: Option<C::Data>,
184}
185
186impl<C: NamadaTypes> TxBuilder<C> for TxCustom<C> {
187    fn tx<F>(self, func: F) -> Self
188    where
189        F: FnOnce(Tx<C>) -> Tx<C>,
190    {
191        TxCustom {
192            tx: func(self.tx),
193            ..self
194        }
195    }
196}
197
198impl<C: NamadaTypes> TxCustom<C> {
199    /// Path to the tx WASM code file
200    pub fn code_path(self, code_path: PathBuf) -> Self {
201        Self {
202            code_path: Some(code_path),
203            ..self
204        }
205    }
206
207    /// Path to the data file
208    pub fn data_path(self, data_path: C::Data) -> Self {
209        Self {
210            data_path: Some(data_path),
211            ..self
212        }
213    }
214
215    /// Path to the serialized transaction
216    pub fn serialized_tx(self, serialized_tx: C::Data) -> Self {
217        Self {
218            serialized_tx: Some(serialized_tx),
219            ..self
220        }
221    }
222
223    /// The address that correspond to the signatures/signing-keys
224    pub fn owner(self, owner: Option<C::Address>) -> Self {
225        Self { owner, ..self }
226    }
227}
228
229impl TxCustom {
230    /// Build a transaction from this builder
231    pub async fn build(
232        &self,
233        context: &impl Namada,
234    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
235        tx::build_custom(context, self).await
236    }
237}
238
239/// An amount read in by the cli
240#[derive(Copy, Clone, Debug)]
241pub enum InputAmount {
242    /// An amount whose representation has been validated
243    /// against the allowed representation in storage
244    Validated(token::DenominatedAmount),
245    /// The parsed amount read in from the cli. It has
246    /// not yet been validated against the allowed
247    /// representation in storage.
248    Unvalidated(token::DenominatedAmount),
249}
250
251impl std::str::FromStr for InputAmount {
252    type Err = <token::DenominatedAmount as std::str::FromStr>::Err;
253
254    fn from_str(s: &str) -> Result<Self, Self::Err> {
255        token::DenominatedAmount::from_str(s).map(InputAmount::Unvalidated)
256    }
257}
258
259impl From<token::DenominatedAmount> for InputAmount {
260    fn from(amt: token::DenominatedAmount) -> Self {
261        InputAmount::Unvalidated(amt)
262    }
263}
264
265/// Transparent transfer transaction arguments
266#[derive(Clone, Debug)]
267pub struct TxTransparentTransfer<C: NamadaTypes = SdkTypes> {
268    /// Common tx arguments
269    pub tx: Tx<C>,
270    /// The transfer specific data
271    pub sources: Vec<TxTransparentSource<C>>,
272    /// The transfer specific data
273    pub targets: Vec<TxTransparentTarget<C>>,
274    /// Path to the TX WASM code file
275    pub tx_code_path: PathBuf,
276}
277
278impl<C: NamadaTypes> TxBuilder<C> for TxTransparentTransfer<C> {
279    fn tx<F>(self, func: F) -> Self
280    where
281        F: FnOnce(Tx<C>) -> Tx<C>,
282    {
283        TxTransparentTransfer {
284            tx: func(self.tx),
285            ..self
286        }
287    }
288}
289
290impl<C: NamadaTypes> TxTransparentTransfer<C> {
291    /// Path to the TX WASM code file
292    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
293        Self {
294            tx_code_path,
295            ..self
296        }
297    }
298}
299
300impl TxTransparentTransfer {
301    /// Build a transaction from this builder
302    pub async fn build(
303        &mut self,
304        context: &impl Namada,
305    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
306        tx::build_transparent_transfer(context, self).await
307    }
308}
309
310/// Shielded transfer-specific arguments
311#[derive(Clone, Debug)]
312pub struct TxShieldedSource<C: NamadaTypes = SdkTypes> {
313    /// Transfer source spending key
314    pub source: C::SpendingKey,
315    /// Transferred token address
316    pub token: C::Address,
317    /// Transferred token amount
318    pub amount: InputAmount,
319}
320
321/// Shielded transfer-specific arguments
322#[derive(Clone, Debug)]
323pub struct TxShieldedTarget<C: NamadaTypes = SdkTypes> {
324    /// Transfer target address
325    pub target: C::PaymentAddress,
326    /// Transferred token address
327    pub token: C::Address,
328    /// Transferred token amount
329    pub amount: InputAmount,
330}
331
332/// Shielded transfer transaction arguments
333#[derive(Clone, Debug)]
334pub struct TxShieldedTransfer<C: NamadaTypes = SdkTypes> {
335    /// Common tx arguments
336    pub tx: Tx<C>,
337    /// Transfer-specific data
338    pub sources: Vec<TxShieldedSource<C>>,
339    /// Transfer-specific data
340    pub targets: Vec<TxShieldedTarget<C>>,
341    /// Optional additional keys for gas payment
342    pub gas_spending_key: Option<C::SpendingKey>,
343    /// Path to the TX WASM code file
344    pub tx_code_path: PathBuf,
345}
346
347impl<C: NamadaTypes> TxBuilder<C> for TxShieldedTransfer<C> {
348    fn tx<F>(self, func: F) -> Self
349    where
350        F: FnOnce(Tx<C>) -> Tx<C>,
351    {
352        TxShieldedTransfer {
353            tx: func(self.tx),
354            ..self
355        }
356    }
357}
358
359impl TxShieldedTransfer {
360    /// Build a transaction from this builder
361    pub async fn build(
362        &mut self,
363        context: &impl Namada,
364        bparams: &mut impl BuildParams,
365    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
366        tx::build_shielded_transfer(context, self, bparams).await
367    }
368}
369
370/// Shielding transfer-specific arguments
371#[derive(Clone, Debug)]
372pub struct TxTransparentSource<C: NamadaTypes = SdkTypes> {
373    /// Transfer source spending key
374    pub source: C::Address,
375    /// Transferred token address
376    pub token: C::Address,
377    /// Transferred token amount
378    pub amount: InputAmount,
379}
380
381/// Shielding transfer transaction arguments
382#[derive(Clone, Debug)]
383pub struct TxShieldingTransfer<C: NamadaTypes = SdkTypes> {
384    /// Common tx arguments
385    pub tx: Tx<C>,
386    /// Transfer target data
387    pub targets: Vec<TxShieldedTarget<C>>,
388    /// Transfer source data
389    pub sources: Vec<TxTransparentSource<C>>,
390    /// The optional data for the frontend sustainability fee
391    pub frontend_sus_fee: Option<(C::TransferTarget, Dec)>,
392    /// Path to the TX WASM code file
393    pub tx_code_path: PathBuf,
394}
395
396impl<C: NamadaTypes> TxBuilder<C> for TxShieldingTransfer<C> {
397    fn tx<F>(self, func: F) -> Self
398    where
399        F: FnOnce(Tx<C>) -> Tx<C>,
400    {
401        TxShieldingTransfer {
402            tx: func(self.tx),
403            ..self
404        }
405    }
406}
407
408impl TxShieldingTransfer {
409    /// Build a transaction from this builder
410    pub async fn build(
411        &mut self,
412        context: &impl Namada,
413        bparams: &mut impl BuildParams,
414    ) -> crate::error::Result<(namada_tx::Tx, SigningData, MaspEpoch)> {
415        tx::build_shielding_transfer(context, self, bparams).await
416    }
417}
418
419/// Unshielding transfer-specific arguments
420#[derive(Clone, Debug)]
421pub struct TxTransparentTarget<C: NamadaTypes = SdkTypes> {
422    /// Transfer target address
423    pub target: C::Address,
424    /// Transferred token address
425    pub token: C::Address,
426    /// Transferred token amount
427    pub amount: InputAmount,
428}
429
430/// Unshielding transfer transaction arguments
431#[derive(Clone, Debug)]
432pub struct TxUnshieldingTransfer<C: NamadaTypes = SdkTypes> {
433    /// Common tx arguments
434    pub tx: Tx<C>,
435    /// Transfer source data
436    pub sources: Vec<TxShieldedSource<C>>,
437    /// Transfer target data
438    pub targets: Vec<TxTransparentTarget<C>>,
439    /// Optional additional key for gas payment
440    pub gas_spending_key: Option<C::SpendingKey>,
441    /// The optional data for the frontend sustainability fee
442    pub frontend_sus_fee: Option<(C::TransferTarget, Dec)>,
443    /// Path to the TX WASM code file
444    pub tx_code_path: PathBuf,
445}
446
447impl<C: NamadaTypes> TxBuilder<C> for TxUnshieldingTransfer<C> {
448    fn tx<F>(self, func: F) -> Self
449    where
450        F: FnOnce(Tx<C>) -> Tx<C>,
451    {
452        TxUnshieldingTransfer {
453            tx: func(self.tx),
454            ..self
455        }
456    }
457}
458
459impl TxUnshieldingTransfer {
460    /// Build a transaction from this builder
461    pub async fn build(
462        &mut self,
463        context: &impl Namada,
464        bparams: &mut impl BuildParams,
465    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
466        tx::build_unshielding_transfer(context, self, bparams).await
467    }
468}
469
470/// Individual hop of some route to take through Osmosis pools.
471#[derive(Serialize, Deserialize, Debug, Clone)]
472pub struct OsmosisPoolHop {
473    /// The id of the pool to use on Osmosis.
474    pub pool_id: String,
475    /// The output denomination expected from the
476    /// pool on Osmosis.
477    pub token_out_denom: String,
478}
479
480impl FromStr for OsmosisPoolHop {
481    type Err = String;
482
483    fn from_str(s: &str) -> Result<Self, Self::Err> {
484        s.split_once(':').map_or_else(
485            || {
486                Err(format!(
487                    "Expected <pool-id>:<output-denom> string, but found \
488                     {s:?} instead"
489                ))
490            },
491            |(pool_id, token_out_denom)| {
492                Ok(OsmosisPoolHop {
493                    pool_id: pool_id.to_owned(),
494                    token_out_denom: token_out_denom.to_owned(),
495                })
496            },
497        )
498    }
499}
500
501#[derive(Debug, Clone, Serialize, Deserialize)]
502#[serde(rename_all = "snake_case")]
503/// Constraints on the osmosis swap
504pub enum Slippage {
505    /// Specifies the minimum amount to be received
506    MinOutputAmount(Amount),
507    /// A time-weighted average price
508    Twap {
509        /// The maximum percentage difference allowed between the estimated and
510        /// actual trade price. This must be a decimal number in the range
511        /// `[0, 100]`.
512        slippage_percentage: Dec,
513    },
514}
515
516/// An token swap on Osmosis
517#[derive(Debug, Clone)]
518pub struct TxOsmosisSwap<C: NamadaTypes = SdkTypes> {
519    /// The IBC transfer data
520    pub transfer: TxIbcTransfer<C>,
521    /// The token we wish to receive (on Namada)
522    pub output_denom: String,
523    /// Address of the recipient on Namada
524    pub recipient: Either<C::Address, C::PaymentAddress>,
525    /// Address to receive funds exceeding the minimum amount,
526    /// in case of IBC shieldings
527    ///
528    /// If unspecified, a disposable address is generated to
529    /// receive funds with
530    pub overflow: Option<C::Address>,
531    ///  Constraints on the  osmosis swap
532    pub slippage: Option<Slippage>,
533    /// Recovery address (on Osmosis) in case of failure
534    pub local_recovery_addr: String,
535    /// The route to take through Osmosis pools
536    pub route: Option<Vec<OsmosisPoolHop>>,
537    /// REST rpc endpoint to the Osmosis GRPC gateway
538    pub osmosis_lcd_rpc: Option<String>,
539    /// REST rpc endpoint to Osmosis SQS
540    pub osmosis_sqs_rpc: Option<String>,
541    /// The optional data for the frontend sustainability fee
542    /// NOTE: if the swap is shielded (from MASP to MASP), no sustainability
543    /// fee should be taken
544    pub frontend_sus_fee: Option<(C::PaymentAddress, Dec)>,
545}
546
547impl TxOsmosisSwap<SdkTypes> {
548    /// Create an IBC transfer from the input arguments
549    pub async fn into_ibc_transfer<F>(
550        self,
551        ctx: &impl Namada,
552        confirm_swap: F,
553    ) -> crate::error::Result<TxIbcTransfer<SdkTypes>>
554    where
555        F: FnOnce(&[OsmosisPoolHop], &Amount, Option<&Amount>) -> bool,
556    {
557        #[derive(Serialize)]
558        struct Memo {
559            wasm: Wasm,
560        }
561
562        #[derive(Serialize)]
563        struct Wasm {
564            contract: String,
565            msg: Message,
566        }
567
568        #[derive(Serialize)]
569        struct Message {
570            osmosis_swap: OsmosisSwap,
571        }
572
573        #[derive(Serialize)]
574        struct OsmosisSwap {
575            receiver: String,
576            output_denom: String,
577            slippage: Slippage,
578            on_failed_delivery: LocalRecoveryAddr,
579            route: Vec<OsmosisPoolHop>,
580            #[serde(skip_serializing_if = "Option::is_none")]
581            final_memo: Option<serde_json::Map<String, serde_json::Value>>,
582        }
583
584        #[derive(Serialize)]
585        struct LocalRecoveryAddr {
586            local_recovery_addr: String,
587        }
588
589        #[inline]
590        fn assert_json_obj(
591            value: serde_json::Value,
592        ) -> serde_json::Map<String, serde_json::Value> {
593            match value {
594                serde_json::Value::Object(x) => x,
595                _ => unreachable!(),
596            }
597        }
598
599        const OSMOSIS_SQS_SERVER: &str = "https://sqsprod.osmosis.zone";
600        const OSMOSIS_LCD_SERVER: &str = "https://lcd.osmosis.zone";
601
602        let Self {
603            mut transfer,
604            recipient,
605            slippage,
606            local_recovery_addr,
607            route: fixed_route,
608            overflow,
609            osmosis_lcd_rpc,
610            osmosis_sqs_rpc,
611            output_denom: namada_output_denom,
612            frontend_sus_fee,
613        } = self;
614
615        let osmosis_lcd_rpc = osmosis_lcd_rpc
616            .map_or(Cow::Borrowed(OSMOSIS_LCD_SERVER), Cow::Owned);
617        let osmosis_sqs_rpc = osmosis_sqs_rpc
618            .map_or(Cow::Borrowed(OSMOSIS_SQS_SERVER), Cow::Owned);
619
620        let recipient = recipient.map_either(
621            |addr| addr,
622            |payment_addr| async move {
623                let overflow_receiver = if let Some(overflow) = overflow {
624                    overflow
625                } else {
626                    let addr = (&gen_disposable_signing_key(ctx).await).into();
627                    display_line!(
628                        ctx.io(),
629                        "Sending unshielded funds to disposable address {addr}",
630                    );
631                    addr
632                };
633                (payment_addr, overflow_receiver)
634            },
635        );
636
637        // validate `local_recovery_addr` and the contract addr
638        if !bech32::decode(&local_recovery_addr)
639            .is_ok_and(|(hrp, data)| hrp.as_str() == "osmo" && data.len() == 20)
640        {
641            return Err(Error::Other(format!(
642                "Invalid Osmosis recovery address {local_recovery_addr:?}"
643            )));
644        }
645        if !bech32::decode(&transfer.receiver)
646            .is_ok_and(|(hrp, data)| hrp.as_str() == "osmo" && data.len() == 32)
647        {
648            return Err(Error::Other(format!(
649                "Invalid Osmosis contract address {local_recovery_addr:?}"
650            )));
651        }
652
653        let registry_xcs_addr = get_registry_from_xcs_osmosis_contract(
654            &osmosis_lcd_rpc,
655            &transfer.receiver,
656        )
657        .await?;
658
659        let namada_input_denom =
660            query_ibc_denom(ctx, transfer.token.to_string(), None).await;
661
662        let (osmosis_input_denom, _) = osmosis_denom_from_namada_denom(
663            &osmosis_lcd_rpc,
664            &registry_xcs_addr,
665            &namada_input_denom,
666        )
667        .await?;
668
669        let (osmosis_output_denom, namada_output_addr) =
670            osmosis_denom_from_namada_denom(
671                &osmosis_lcd_rpc,
672                &registry_xcs_addr,
673                &namada_output_denom,
674            )
675            .await?;
676
677        let (route, trade_min_output_amount, quote) =
678            query_osmosis_route_and_min_out(
679                ctx,
680                &transfer.token,
681                &osmosis_input_denom,
682                transfer.amount,
683                &osmosis_output_denom,
684                &osmosis_sqs_rpc,
685                fixed_route,
686                slippage,
687            )
688            .await?;
689
690        if !confirm_swap(&route, &trade_min_output_amount, quote.as_ref()) {
691            return Err(Error::Other("Swap has been cancelled".to_owned()));
692        }
693
694        let (receiver, final_memo) = match recipient {
695            Either::Left(transparent_recipient) => {
696                (transparent_recipient.encode_compat(), None)
697            }
698            Either::Right(fut) => {
699                let (payment_addr, overflow_receiver) = fut.await;
700
701                let amount_to_shield = trade_min_output_amount;
702                let shielding_tx = tx::gen_ibc_shielding_transfer(
703                    ctx,
704                    GenIbcShieldingTransfer {
705                        query: Query {
706                            ledger_address: transfer.tx.ledger_address.clone(),
707                        },
708                        output_folder: None,
709                        target: payment_addr,
710                        asset: IbcShieldingTransferAsset::Address(
711                            namada_output_addr,
712                        ),
713                        amount: InputAmount::Validated(
714                            token::DenominatedAmount::new(
715                                amount_to_shield,
716                                0u8.into(),
717                            ),
718                        ),
719                        expiration: transfer.tx.expiration.clone(),
720                        frontend_sus_fee,
721                    },
722                )
723                .await?
724                .ok_or_else(|| {
725                    Error::Other(
726                        "Failed to generate IBC shielding transfer".to_owned(),
727                    )
728                })?;
729
730                let memo = assert_json_obj(
731                    serde_json::to_value(&NamadaMemo {
732                        namada: NamadaMemoData::OsmosisSwap {
733                            shielding_data: StringEncoded::new(
734                                IbcShieldingData(shielding_tx),
735                            ),
736                            shielded_amount: amount_to_shield,
737                            overflow_receiver,
738                        },
739                    })
740                    .unwrap(),
741                );
742
743                (MASP.encode_compat(), Some(memo))
744            }
745        };
746
747        let cosmwasm_memo = Memo {
748            wasm: Wasm {
749                contract: transfer.receiver.clone(),
750                msg: Message {
751                    osmosis_swap: OsmosisSwap {
752                        output_denom: osmosis_output_denom,
753                        slippage: Slippage::MinOutputAmount(
754                            trade_min_output_amount,
755                        ),
756                        final_memo,
757                        receiver,
758                        on_failed_delivery: LocalRecoveryAddr {
759                            local_recovery_addr,
760                        },
761                        route,
762                    },
763                },
764            },
765        };
766        let namada_memo = transfer.ibc_memo.take().map(|memo| {
767            assert_json_obj(
768                serde_json::to_value(&NamadaMemo {
769                    namada: NamadaMemoData::Memo(memo),
770                })
771                .unwrap(),
772            )
773        });
774
775        let memo = {
776            let mut m = serde_json::to_value(&cosmwasm_memo).unwrap();
777            let m_obj = m.as_object_mut().unwrap();
778
779            if let Some(mut namada_memo) = namada_memo {
780                m_obj.append(&mut namada_memo);
781            }
782
783            m
784        };
785
786        transfer.ibc_memo = Some(serde_json::to_string(&memo).unwrap());
787        Ok(transfer)
788    }
789}
790
791/// IBC transfer transaction arguments
792#[derive(Clone, Debug)]
793pub struct TxIbcTransfer<C: NamadaTypes = SdkTypes> {
794    /// Common tx arguments
795    pub tx: Tx<C>,
796    /// Transfer source address
797    pub source: C::TransferSource,
798    /// Transfer target address
799    pub receiver: String,
800    /// Transferred token address
801    pub token: C::Address,
802    /// Transferred token amount
803    pub amount: InputAmount,
804    /// Port ID
805    pub port_id: PortId,
806    /// Channel ID
807    pub channel_id: ChannelId,
808    /// Timeout height of the destination chain
809    pub timeout_height: Option<u64>,
810    /// Timeout timestamp offset
811    pub timeout_sec_offset: Option<u64>,
812    /// Refund target address when the shielded transfer failure
813    pub refund_target: Option<C::TransferTarget>,
814    /// IBC shielding transfer data for the destination chain
815    pub ibc_shielding_data: Option<IbcShieldingData>,
816    /// Memo for IBC transfer packet
817    pub ibc_memo: Option<String>,
818    /// Optional additional keys for gas payment
819    pub gas_spending_key: Option<C::SpendingKey>,
820    /// The optional data for the frontend sustainability fee
821    pub frontend_sus_fee: Option<(C::TransferTarget, Dec)>,
822    /// Path to the TX WASM code file
823    pub tx_code_path: PathBuf,
824}
825
826impl<C: NamadaTypes> TxBuilder<C> for TxIbcTransfer<C> {
827    fn tx<F>(self, func: F) -> Self
828    where
829        F: FnOnce(Tx<C>) -> Tx<C>,
830    {
831        TxIbcTransfer {
832            tx: func(self.tx),
833            ..self
834        }
835    }
836}
837
838impl<C: NamadaTypes> TxIbcTransfer<C> {
839    /// Transfer source address
840    pub fn source(self, source: C::TransferSource) -> Self {
841        Self { source, ..self }
842    }
843
844    /// Transfer target address
845    pub fn receiver(self, receiver: String) -> Self {
846        Self { receiver, ..self }
847    }
848
849    /// Transferred token address
850    pub fn token(self, token: C::Address) -> Self {
851        Self { token, ..self }
852    }
853
854    /// Transferred token amount
855    pub fn amount(self, amount: InputAmount) -> Self {
856        Self { amount, ..self }
857    }
858
859    /// Port ID
860    pub fn port_id(self, port_id: PortId) -> Self {
861        Self { port_id, ..self }
862    }
863
864    /// Channel ID
865    pub fn channel_id(self, channel_id: ChannelId) -> Self {
866        Self { channel_id, ..self }
867    }
868
869    /// Timeout height of the destination chain
870    pub fn timeout_height(self, timeout_height: u64) -> Self {
871        Self {
872            timeout_height: Some(timeout_height),
873            ..self
874        }
875    }
876
877    /// Timeout timestamp offset
878    pub fn timeout_sec_offset(self, timeout_sec_offset: u64) -> Self {
879        Self {
880            timeout_sec_offset: Some(timeout_sec_offset),
881            ..self
882        }
883    }
884
885    /// Refund target address
886    pub fn refund_target(self, refund_target: C::TransferTarget) -> Self {
887        Self {
888            refund_target: Some(refund_target),
889            ..self
890        }
891    }
892
893    /// IBC shielding transfer data
894    pub fn ibc_shielding_data(self, shielding_data: IbcShieldingData) -> Self {
895        Self {
896            ibc_shielding_data: Some(shielding_data),
897            ..self
898        }
899    }
900
901    /// Memo for IBC transfer packet
902    pub fn ibc_memo(self, ibc_memo: String) -> Self {
903        Self {
904            ibc_memo: Some(ibc_memo),
905            ..self
906        }
907    }
908
909    /// Gas spending keys
910    pub fn gas_spending_keys(self, gas_spending_key: C::SpendingKey) -> Self {
911        Self {
912            gas_spending_key: Some(gas_spending_key),
913            ..self
914        }
915    }
916
917    /// Path to the TX WASM code file
918    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
919        Self {
920            tx_code_path,
921            ..self
922        }
923    }
924}
925
926impl TxIbcTransfer {
927    /// Build a transaction from this builder
928    pub async fn build(
929        &self,
930        context: &impl Namada,
931        bparams: &mut impl BuildParams,
932    ) -> crate::error::Result<(namada_tx::Tx, SigningData, Option<MaspEpoch>)>
933    {
934        tx::build_ibc_transfer(context, self, bparams).await
935    }
936}
937
938/// Transaction to initialize create a new proposal
939#[derive(Clone, Debug)]
940pub struct InitProposal<C: NamadaTypes = SdkTypes> {
941    /// Common tx arguments
942    pub tx: Tx<C>,
943    /// The proposal data
944    pub proposal_data: C::Data,
945    /// Flag if proposal is of type Pgf stewards
946    pub is_pgf_stewards: bool,
947    /// Flag if proposal is of type Pgf funding
948    pub is_pgf_funding: bool,
949    /// Path to the tx WASM file
950    pub tx_code_path: PathBuf,
951}
952
953impl<C: NamadaTypes> TxBuilder<C> for InitProposal<C> {
954    fn tx<F>(self, func: F) -> Self
955    where
956        F: FnOnce(Tx<C>) -> Tx<C>,
957    {
958        InitProposal {
959            tx: func(self.tx),
960            ..self
961        }
962    }
963}
964
965impl<C: NamadaTypes> InitProposal<C> {
966    /// The proposal data
967    pub fn proposal_data(self, proposal_data: C::Data) -> Self {
968        Self {
969            proposal_data,
970            ..self
971        }
972    }
973
974    /// Flag if proposal is of type Pgf stewards
975    pub fn is_pgf_stewards(self, is_pgf_stewards: bool) -> Self {
976        Self {
977            is_pgf_stewards,
978            ..self
979        }
980    }
981
982    /// Flag if proposal is of type Pgf funding
983    pub fn is_pgf_funding(self, is_pgf_funding: bool) -> Self {
984        Self {
985            is_pgf_funding,
986            ..self
987        }
988    }
989
990    /// Path to the tx WASM file
991    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
992        Self {
993            tx_code_path,
994            ..self
995        }
996    }
997}
998
999impl InitProposal {
1000    /// Build a transaction from this builder
1001    pub async fn build(
1002        &self,
1003        context: &impl Namada,
1004    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1005        let current_epoch = rpc::query_epoch(context.client()).await?;
1006        let governance_parameters =
1007            rpc::query_governance_parameters(context.client()).await;
1008
1009        if self.is_pgf_funding {
1010            let proposal = PgfFundingProposal::try_from(
1011                self.proposal_data.as_ref(),
1012            )
1013            .map_err(|e| {
1014                crate::error::TxSubmitError::FailedGovernaneProposalDeserialize(
1015                    e.to_string(),
1016                )
1017            })?
1018            .validate(&governance_parameters, current_epoch, self.tx.force)
1019            .map_err(|e| {
1020                crate::error::TxSubmitError::InvalidProposal(e.to_string())
1021            })?;
1022
1023            tx::build_pgf_funding_proposal(context, self, proposal).await
1024        } else if self.is_pgf_stewards {
1025            let proposal = PgfStewardProposal::try_from(
1026                self.proposal_data.as_ref(),
1027            )
1028            .map_err(|e| {
1029                crate::error::TxSubmitError::FailedGovernaneProposalDeserialize(
1030                    e.to_string(),
1031                )
1032            })?;
1033            let nam_address = context.native_token();
1034            let author_balance = rpc::get_token_balance(
1035                context.client(),
1036                &nam_address,
1037                &proposal.proposal.author,
1038                None,
1039            )
1040            .await?;
1041            let proposal = proposal
1042                .validate(
1043                    &governance_parameters,
1044                    current_epoch,
1045                    author_balance,
1046                    self.tx.force,
1047                )
1048                .map_err(|e| {
1049                    crate::error::TxSubmitError::InvalidProposal(e.to_string())
1050                })?;
1051
1052            tx::build_pgf_stewards_proposal(context, self, proposal).await
1053        } else {
1054            let proposal = DefaultProposal::try_from(
1055                self.proposal_data.as_ref(),
1056            )
1057            .map_err(|e| {
1058                crate::error::TxSubmitError::FailedGovernaneProposalDeserialize(
1059                    e.to_string(),
1060                )
1061            })?;
1062            let nam_address = context.native_token();
1063            let author_balance = rpc::get_token_balance(
1064                context.client(),
1065                &nam_address,
1066                &proposal.proposal.author,
1067                None,
1068            )
1069            .await?;
1070            let proposal = proposal
1071                .validate(
1072                    &governance_parameters,
1073                    current_epoch,
1074                    author_balance,
1075                    self.tx.force,
1076                )
1077                .map_err(|e| {
1078                    crate::error::TxSubmitError::InvalidProposal(e.to_string())
1079                })?;
1080            tx::build_default_proposal(context, self, proposal).await
1081        }
1082    }
1083}
1084
1085/// Transaction to vote on a proposal
1086#[derive(Clone, Debug)]
1087pub struct VoteProposal<C: NamadaTypes = SdkTypes> {
1088    /// Common tx arguments
1089    pub tx: Tx<C>,
1090    /// Proposal id
1091    pub proposal_id: u64,
1092    /// The vote
1093    pub vote: String,
1094    /// The address of the voter
1095    pub voter_address: C::Address,
1096    /// Path to the TX WASM code file
1097    pub tx_code_path: PathBuf,
1098}
1099
1100impl<C: NamadaTypes> TxBuilder<C> for VoteProposal<C> {
1101    fn tx<F>(self, func: F) -> Self
1102    where
1103        F: FnOnce(Tx<C>) -> Tx<C>,
1104    {
1105        VoteProposal {
1106            tx: func(self.tx),
1107            ..self
1108        }
1109    }
1110}
1111
1112impl<C: NamadaTypes> VoteProposal<C> {
1113    /// Proposal id
1114    pub fn proposal_id(self, proposal_id: u64) -> Self {
1115        Self {
1116            proposal_id,
1117            ..self
1118        }
1119    }
1120
1121    /// The vote
1122    pub fn vote(self, vote: String) -> Self {
1123        Self { vote, ..self }
1124    }
1125
1126    /// The address of the voter
1127    pub fn voter(self, voter_address: C::Address) -> Self {
1128        Self {
1129            voter_address,
1130            ..self
1131        }
1132    }
1133
1134    /// Path to the TX WASM code file
1135    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1136        Self {
1137            tx_code_path,
1138            ..self
1139        }
1140    }
1141}
1142
1143impl VoteProposal {
1144    /// Build a transaction from this builder
1145    pub async fn build(
1146        &self,
1147        context: &impl Namada,
1148    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1149        let current_epoch = rpc::query_epoch(context.client()).await?;
1150        tx::build_vote_proposal(context, self, current_epoch).await
1151    }
1152}
1153
1154/// Transaction to initialize a new account
1155#[derive(Clone, Debug)]
1156pub struct TxInitAccount<C: NamadaTypes = SdkTypes> {
1157    /// Common tx arguments
1158    pub tx: Tx<C>,
1159    /// Path to the VP WASM code file for the new account
1160    pub vp_code_path: PathBuf,
1161    /// Path to the TX WASM code file
1162    pub tx_code_path: PathBuf,
1163    /// Public key for the new account
1164    pub public_keys: Vec<C::PublicKey>,
1165    /// The account multisignature threshold
1166    pub threshold: Option<u8>,
1167}
1168
1169impl<C: NamadaTypes> TxBuilder<C> for TxInitAccount<C> {
1170    fn tx<F>(self, func: F) -> Self
1171    where
1172        F: FnOnce(Tx<C>) -> Tx<C>,
1173    {
1174        TxInitAccount {
1175            tx: func(self.tx),
1176            ..self
1177        }
1178    }
1179}
1180
1181impl<C: NamadaTypes> TxInitAccount<C> {
1182    /// A vector of public key to associate with the new account
1183    pub fn public_keys(self, public_keys: Vec<C::PublicKey>) -> Self {
1184        Self {
1185            public_keys,
1186            ..self
1187        }
1188    }
1189
1190    /// A threshold to associate with the new account
1191    pub fn threshold(self, threshold: u8) -> Self {
1192        Self {
1193            threshold: Some(threshold),
1194            ..self
1195        }
1196    }
1197
1198    /// Path to the VP WASM code file
1199    pub fn vp_code_path(self, vp_code_path: PathBuf) -> Self {
1200        Self {
1201            vp_code_path,
1202            ..self
1203        }
1204    }
1205
1206    /// Path to the TX WASM code file
1207    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1208        Self {
1209            tx_code_path,
1210            ..self
1211        }
1212    }
1213}
1214
1215impl TxInitAccount {
1216    /// Build a transaction from this builder
1217    pub async fn build(
1218        &self,
1219        context: &impl Namada,
1220    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1221        tx::build_init_account(context, self).await
1222    }
1223}
1224
1225/// Transaction to initialize a new account
1226#[derive(Clone, Debug)]
1227pub struct TxBecomeValidator<C: NamadaTypes = SdkTypes> {
1228    /// Common tx arguments
1229    pub tx: Tx<C>,
1230    /// Address of an account that will become a validator.
1231    pub address: C::Address,
1232    /// Signature scheme
1233    pub scheme: SchemeType,
1234    /// Consensus key
1235    pub consensus_key: Option<C::PublicKey>,
1236    /// Ethereum cold key
1237    pub eth_cold_key: Option<C::PublicKey>,
1238    /// Ethereum hot key
1239    pub eth_hot_key: Option<C::PublicKey>,
1240    /// Protocol key
1241    pub protocol_key: Option<C::PublicKey>,
1242    /// Commission rate
1243    pub commission_rate: Dec,
1244    /// Maximum commission rate change
1245    pub max_commission_rate_change: Dec,
1246    /// The validator email
1247    pub email: String,
1248    /// The validator description
1249    pub description: Option<String>,
1250    /// The validator website
1251    pub website: Option<String>,
1252    /// The validator's discord handle
1253    pub discord_handle: Option<String>,
1254    /// The validator's avatar
1255    pub avatar: Option<String>,
1256    /// The validator's name
1257    pub name: Option<String>,
1258    /// Path to the TX WASM code file
1259    pub tx_code_path: PathBuf,
1260    /// Don't encrypt the keypair
1261    pub unsafe_dont_encrypt: bool,
1262}
1263
1264impl<C: NamadaTypes> TxBuilder<C> for TxBecomeValidator<C> {
1265    fn tx<F>(self, func: F) -> Self
1266    where
1267        F: FnOnce(Tx<C>) -> Tx<C>,
1268    {
1269        TxBecomeValidator {
1270            tx: func(self.tx),
1271            ..self
1272        }
1273    }
1274}
1275
1276impl<C: NamadaTypes> TxBecomeValidator<C> {
1277    /// Set the address
1278    pub fn address(self, address: C::Address) -> Self {
1279        Self { address, ..self }
1280    }
1281
1282    /// Set the commission rate
1283    pub fn commission_rate(self, commission_rate: Dec) -> Self {
1284        Self {
1285            commission_rate,
1286            ..self
1287        }
1288    }
1289
1290    /// Set the max commission rate change
1291    pub fn max_commission_rate_change(
1292        self,
1293        max_commission_rate_change: Dec,
1294    ) -> Self {
1295        Self {
1296            max_commission_rate_change,
1297            ..self
1298        }
1299    }
1300
1301    /// Set the email
1302    pub fn email(self, email: String) -> Self {
1303        Self { email, ..self }
1304    }
1305
1306    /// Path to the TX WASM code file
1307    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1308        Self {
1309            tx_code_path,
1310            ..self
1311        }
1312    }
1313}
1314
1315impl TxBecomeValidator {
1316    /// Build the tx
1317    pub async fn build(
1318        &self,
1319        context: &impl Namada,
1320    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1321        tx::build_become_validator(context, self).await
1322    }
1323}
1324
1325/// Transaction to initialize a new account
1326#[derive(Clone, Debug)]
1327pub struct TxInitValidator<C: NamadaTypes = SdkTypes> {
1328    /// Common tx arguments
1329    pub tx: Tx<C>,
1330    /// Signature scheme
1331    pub scheme: SchemeType,
1332    /// Account keys
1333    pub account_keys: Vec<C::PublicKey>,
1334    /// The account multisignature threshold
1335    pub threshold: Option<u8>,
1336    /// Consensus key
1337    pub consensus_key: Option<C::PublicKey>,
1338    /// Ethereum cold key
1339    pub eth_cold_key: Option<C::PublicKey>,
1340    /// Ethereum hot key
1341    pub eth_hot_key: Option<C::PublicKey>,
1342    /// Protocol key
1343    pub protocol_key: Option<C::PublicKey>,
1344    /// Commission rate
1345    pub commission_rate: Dec,
1346    /// Maximum commission rate change
1347    pub max_commission_rate_change: Dec,
1348    /// The validator email
1349    pub email: String,
1350    /// The validator description
1351    pub description: Option<String>,
1352    /// The validator website
1353    pub website: Option<String>,
1354    /// The validator's discord handle
1355    pub discord_handle: Option<String>,
1356    /// The validator's avatar
1357    pub avatar: Option<String>,
1358    /// The validator's name
1359    pub name: Option<String>,
1360    /// Path to the VP WASM code file
1361    pub validator_vp_code_path: PathBuf,
1362    /// Path to the TX WASM code file
1363    pub tx_init_account_code_path: PathBuf,
1364    /// Path to the TX WASM code file
1365    pub tx_become_validator_code_path: PathBuf,
1366    /// Don't encrypt the keypair
1367    pub unsafe_dont_encrypt: bool,
1368}
1369
1370/// Transaction to update a VP arguments
1371#[derive(Clone, Debug)]
1372pub struct TxUpdateAccount<C: NamadaTypes = SdkTypes> {
1373    /// Common tx arguments
1374    pub tx: Tx<C>,
1375    /// Path to the VP WASM code file
1376    pub vp_code_path: Option<PathBuf>,
1377    /// Path to the TX WASM code file
1378    pub tx_code_path: PathBuf,
1379    /// Address of the account whose VP is to be updated
1380    pub addr: C::Address,
1381    /// Public keys
1382    pub public_keys: Vec<C::PublicKey>,
1383    /// The account threshold
1384    pub threshold: Option<u8>,
1385}
1386
1387impl<C: NamadaTypes> TxBuilder<C> for TxUpdateAccount<C> {
1388    fn tx<F>(self, func: F) -> Self
1389    where
1390        F: FnOnce(Tx<C>) -> Tx<C>,
1391    {
1392        TxUpdateAccount {
1393            tx: func(self.tx),
1394            ..self
1395        }
1396    }
1397}
1398
1399impl<C: NamadaTypes> TxUpdateAccount<C> {
1400    /// Path to the VP WASM code file
1401    pub fn vp_code_path(self, vp_code_path: PathBuf) -> Self {
1402        Self {
1403            vp_code_path: Some(vp_code_path),
1404            ..self
1405        }
1406    }
1407
1408    /// Path to the TX WASM code file
1409    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1410        Self {
1411            tx_code_path,
1412            ..self
1413        }
1414    }
1415
1416    /// Address of the account whose VP is to be updated
1417    pub fn addr(self, addr: C::Address) -> Self {
1418        Self { addr, ..self }
1419    }
1420
1421    /// Public keys
1422    pub fn public_keys(self, public_keys: Vec<C::PublicKey>) -> Self {
1423        Self {
1424            public_keys,
1425            ..self
1426        }
1427    }
1428
1429    /// The account threshold
1430    pub fn threshold(self, threshold: u8) -> Self {
1431        Self {
1432            threshold: Some(threshold),
1433            ..self
1434        }
1435    }
1436}
1437
1438impl TxUpdateAccount {
1439    /// Build a transaction from this builder
1440    pub async fn build(
1441        &self,
1442        context: &impl Namada,
1443    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1444        tx::build_update_account(context, self).await
1445    }
1446}
1447
1448/// Bond arguments
1449#[derive(Clone, Debug)]
1450pub struct Bond<C: NamadaTypes = SdkTypes> {
1451    /// Common tx arguments
1452    pub tx: Tx<C>,
1453    /// Validator address
1454    pub validator: C::Address,
1455    /// Amount of tokens to stake in a bond
1456    pub amount: token::Amount,
1457    /// Source address for delegations. For self-bonds, the validator is
1458    /// also the source.
1459    pub source: Option<C::Address>,
1460    /// Path to the TX WASM code file
1461    pub tx_code_path: PathBuf,
1462}
1463
1464impl<C: NamadaTypes> TxBuilder<C> for Bond<C> {
1465    fn tx<F>(self, func: F) -> Self
1466    where
1467        F: FnOnce(Tx<C>) -> Tx<C>,
1468    {
1469        Bond {
1470            tx: func(self.tx),
1471            ..self
1472        }
1473    }
1474}
1475
1476impl<C: NamadaTypes> Bond<C> {
1477    /// Validator address
1478    pub fn validator(self, validator: C::Address) -> Self {
1479        Self { validator, ..self }
1480    }
1481
1482    /// Amount of tokens to stake in a bond
1483    pub fn amount(self, amount: token::Amount) -> Self {
1484        Self { amount, ..self }
1485    }
1486
1487    /// Source address for delegations. For self-bonds, the validator is
1488    /// also the source.
1489    pub fn source(self, source: C::Address) -> Self {
1490        Self {
1491            source: Some(source),
1492            ..self
1493        }
1494    }
1495
1496    /// Path to the TX WASM code file
1497    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1498        Self {
1499            tx_code_path,
1500            ..self
1501        }
1502    }
1503}
1504
1505impl Bond {
1506    /// Build a transaction from this builder
1507    pub async fn build(
1508        &self,
1509        context: &impl Namada,
1510    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1511        tx::build_bond(context, self).await
1512    }
1513}
1514
1515/// Unbond arguments
1516#[derive(Clone, Debug)]
1517pub struct Unbond<C: NamadaTypes = SdkTypes> {
1518    /// Common tx arguments
1519    pub tx: Tx<C>,
1520    /// Validator address
1521    pub validator: C::Address,
1522    /// Amount of tokens to unbond from a bond
1523    pub amount: token::Amount,
1524    /// Source address for unbonding from delegations. For unbonding from
1525    /// self-bonds, the validator is also the source
1526    pub source: Option<C::Address>,
1527    /// Path to the TX WASM code file
1528    pub tx_code_path: PathBuf,
1529}
1530
1531impl Unbond {
1532    /// Build a transaction from this builder
1533    pub async fn build(
1534        &self,
1535        context: &impl Namada,
1536    ) -> crate::error::Result<(
1537        namada_tx::Tx,
1538        SigningData,
1539        Option<(Epoch, token::Amount)>,
1540    )> {
1541        tx::build_unbond(context, self).await
1542    }
1543}
1544
1545impl<C: NamadaTypes> TxBuilder<C> for Unbond<C> {
1546    fn tx<F>(self, func: F) -> Self
1547    where
1548        F: FnOnce(Tx<C>) -> Tx<C>,
1549    {
1550        Unbond {
1551            tx: func(self.tx),
1552            ..self
1553        }
1554    }
1555}
1556
1557impl<C: NamadaTypes> Unbond<C> {
1558    /// Validator address
1559    pub fn validator(self, validator: C::Address) -> Self {
1560        Self { validator, ..self }
1561    }
1562
1563    /// Amount of tokens to unbond from a bond
1564    pub fn amount(self, amount: token::Amount) -> Self {
1565        Self { amount, ..self }
1566    }
1567
1568    /// Source address for unbonding from delegations. For unbonding from
1569    /// self-bonds, the validator is also the source
1570    pub fn source(self, source: C::Address) -> Self {
1571        Self {
1572            source: Some(source),
1573            ..self
1574        }
1575    }
1576
1577    /// Path to the TX WASM code file
1578    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1579        Self {
1580            tx_code_path,
1581            ..self
1582        }
1583    }
1584}
1585
1586/// Redelegation arguments
1587#[derive(Clone, Debug)]
1588pub struct Redelegate<C: NamadaTypes = SdkTypes> {
1589    /// Common tx arguments
1590    pub tx: Tx<C>,
1591    /// Source validator address
1592    pub src_validator: C::Address,
1593    /// Destination validator address
1594    pub dest_validator: C::Address,
1595    /// Owner of the bonds that are being redelegated
1596    pub owner: C::Address,
1597    /// The amount of tokens to redelegate
1598    pub amount: token::Amount,
1599    /// Path to the TX WASM code file
1600    pub tx_code_path: PathBuf,
1601}
1602
1603impl Redelegate {
1604    /// Build a transaction from this builder
1605    pub async fn build(
1606        &self,
1607        context: &impl Namada,
1608    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1609        tx::build_redelegation(context, self).await
1610    }
1611}
1612
1613impl<C: NamadaTypes> Redelegate<C> {
1614    /// Src validator address
1615    pub fn src_validator(self, src_validator: C::Address) -> Self {
1616        Self {
1617            src_validator,
1618            ..self
1619        }
1620    }
1621
1622    /// Dest validator address
1623    pub fn dest_validator(self, dest_validator: C::Address) -> Self {
1624        Self {
1625            dest_validator,
1626            ..self
1627        }
1628    }
1629
1630    /// Owner (or delegator or source) of the redelegation
1631    pub fn owner(self, owner: C::Address) -> Self {
1632        Self { owner, ..self }
1633    }
1634
1635    /// Path to the TX WASM code file
1636    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1637        Self {
1638            tx_code_path,
1639            ..self
1640        }
1641    }
1642}
1643
1644impl<C: NamadaTypes> TxBuilder<C> for Redelegate<C> {
1645    fn tx<F>(self, func: F) -> Self
1646    where
1647        F: FnOnce(Tx<C>) -> Tx<C>,
1648    {
1649        Redelegate {
1650            tx: func(self.tx),
1651            ..self
1652        }
1653    }
1654}
1655
1656/// Reveal public key
1657#[derive(Clone, Debug)]
1658pub struct RevealPk<C: NamadaTypes = SdkTypes> {
1659    /// Common tx arguments
1660    pub tx: Tx<C>,
1661    /// A public key to be revealed on-chain
1662    pub public_key: C::PublicKey,
1663}
1664
1665impl<C: NamadaTypes> TxBuilder<C> for RevealPk<C> {
1666    fn tx<F>(self, func: F) -> Self
1667    where
1668        F: FnOnce(Tx<C>) -> Tx<C>,
1669    {
1670        RevealPk {
1671            tx: func(self.tx),
1672            ..self
1673        }
1674    }
1675}
1676
1677impl<C: NamadaTypes> RevealPk<C> {
1678    /// A public key to be revealed on-chain
1679    pub fn public_key(self, public_key: C::PublicKey) -> Self {
1680        Self { public_key, ..self }
1681    }
1682}
1683
1684impl RevealPk {
1685    /// Build a transaction from this builder
1686    pub async fn build(
1687        &self,
1688        context: &impl Namada,
1689    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1690        tx::build_reveal_pk(context, &self.tx, &self.public_key).await
1691    }
1692}
1693
1694/// Generate shell completions
1695#[derive(Clone, Debug)]
1696pub struct Complete {
1697    /// Which shell
1698    pub shell: Shell,
1699}
1700
1701/// Supported shell types
1702#[allow(missing_docs)]
1703#[derive(Clone, Copy, Debug)]
1704pub enum Shell {
1705    Bash,
1706    Elvish,
1707    Fish,
1708    PowerShell,
1709    Zsh,
1710    Nushell,
1711}
1712
1713impl Display for Shell {
1714    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1715        self.possible_value().get_name().fmt(f)
1716    }
1717}
1718
1719impl FromStr for Shell {
1720    type Err = String;
1721
1722    fn from_str(s: &str) -> Result<Self, Self::Err> {
1723        use clap::ValueEnum;
1724
1725        for variant in Self::value_variants() {
1726            if variant.possible_value().matches(s, false) {
1727                return Ok(*variant);
1728            }
1729        }
1730        Err(format!("invalid variant: {s}"))
1731    }
1732}
1733
1734impl Shell {
1735    fn possible_value(&self) -> clap::builder::PossibleValue {
1736        use clap::builder::PossibleValue;
1737        match self {
1738            Shell::Bash => PossibleValue::new("bash"),
1739            Shell::Elvish => PossibleValue::new("elvish"),
1740            Shell::Fish => PossibleValue::new("fish"),
1741            Shell::PowerShell => PossibleValue::new("powershell"),
1742            Shell::Zsh => PossibleValue::new("zsh"),
1743            Shell::Nushell => PossibleValue::new("nushell"),
1744        }
1745    }
1746}
1747
1748impl clap::ValueEnum for Shell {
1749    fn value_variants<'a>() -> &'a [Self] {
1750        &[
1751            Shell::Bash,
1752            Shell::Elvish,
1753            Shell::Fish,
1754            Shell::PowerShell,
1755            Shell::Zsh,
1756            Shell::Nushell,
1757        ]
1758    }
1759
1760    fn to_possible_value<'a>(&self) -> Option<clap::builder::PossibleValue> {
1761        Some(self.possible_value())
1762    }
1763}
1764
1765/// Query proposal votes
1766#[derive(Clone, Debug)]
1767pub struct QueryProposalVotes<C: NamadaTypes = SdkTypes> {
1768    /// Common query args
1769    pub query: Query<C>,
1770    /// Proposal id
1771    pub proposal_id: u64,
1772    /// Voter address
1773    pub voter: Option<C::Address>,
1774}
1775
1776/// Query proposal
1777#[derive(Clone, Debug)]
1778pub struct QueryProposal<C: NamadaTypes = SdkTypes> {
1779    /// Common query args
1780    pub query: Query<C>,
1781    /// Proposal id
1782    pub proposal_id: Option<u64>,
1783}
1784
1785/// Query protocol parameters
1786#[derive(Clone, Debug)]
1787pub struct QueryProtocolParameters<C: NamadaTypes = SdkTypes> {
1788    /// Common query args
1789    pub query: Query<C>,
1790}
1791
1792/// Query pgf data
1793#[derive(Clone, Debug)]
1794pub struct QueryPgf<C: NamadaTypes = SdkTypes> {
1795    /// Common query args
1796    pub query: Query<C>,
1797}
1798
1799/// Withdraw arguments
1800#[derive(Clone, Debug)]
1801pub struct Withdraw<C: NamadaTypes = SdkTypes> {
1802    /// Common tx arguments
1803    pub tx: Tx<C>,
1804    /// Validator address
1805    pub validator: C::Address,
1806    /// Source address for withdrawing from delegations. For withdrawing
1807    /// from self-bonds, the validator is also the source
1808    pub source: Option<C::Address>,
1809    /// Path to the TX WASM code file
1810    pub tx_code_path: PathBuf,
1811}
1812
1813impl<C: NamadaTypes> TxBuilder<C> for Withdraw<C> {
1814    fn tx<F>(self, func: F) -> Self
1815    where
1816        F: FnOnce(Tx<C>) -> Tx<C>,
1817    {
1818        Withdraw {
1819            tx: func(self.tx),
1820            ..self
1821        }
1822    }
1823}
1824
1825impl<C: NamadaTypes> Withdraw<C> {
1826    /// Validator address
1827    pub fn validator(self, validator: C::Address) -> Self {
1828        Self { validator, ..self }
1829    }
1830
1831    /// Source address for withdrawing from delegations. For withdrawing
1832    /// from self-bonds, the validator is also the source
1833    pub fn source(self, source: C::Address) -> Self {
1834        Self {
1835            source: Some(source),
1836            ..self
1837        }
1838    }
1839
1840    /// Path to the TX WASM code file
1841    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
1842        Self {
1843            tx_code_path,
1844            ..self
1845        }
1846    }
1847}
1848
1849impl Withdraw {
1850    /// Build a transaction from this builder
1851    pub async fn build(
1852        &self,
1853        context: &impl Namada,
1854    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1855        tx::build_withdraw(context, self).await
1856    }
1857}
1858
1859/// Claim arguments
1860#[derive(Clone, Debug)]
1861pub struct ClaimRewards<C: NamadaTypes = SdkTypes> {
1862    /// Common tx arguments
1863    pub tx: Tx<C>,
1864    /// Validator address
1865    pub validator: C::Address,
1866    /// Source address for claiming rewards due to bonds. For self-bonds, the
1867    /// validator is also the source
1868    pub source: Option<C::Address>,
1869    /// Path to the TX WASM code file
1870    pub tx_code_path: PathBuf,
1871}
1872
1873impl<C: NamadaTypes> TxBuilder<C> for ClaimRewards<C> {
1874    fn tx<F>(self, func: F) -> Self
1875    where
1876        F: FnOnce(Tx<C>) -> Tx<C>,
1877    {
1878        ClaimRewards {
1879            tx: func(self.tx),
1880            ..self
1881        }
1882    }
1883}
1884
1885impl ClaimRewards {
1886    /// Build a transaction from this builder
1887    pub async fn build(
1888        &self,
1889        context: &impl Namada,
1890    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
1891        tx::build_claim_rewards(context, self).await
1892    }
1893}
1894
1895/// Query asset conversions
1896#[derive(Clone, Debug)]
1897pub struct QueryConversions<C: NamadaTypes = SdkTypes> {
1898    /// Common query args
1899    pub query: Query<C>,
1900    /// Address of a token
1901    pub token: Option<C::Address>,
1902    /// Epoch of the asset
1903    pub epoch: Option<MaspEpoch>,
1904    /// Flag to dump the conversion tree
1905    pub dump_tree: bool,
1906}
1907
1908/// Query token balance(s)
1909#[derive(Clone, Debug)]
1910pub struct QueryAccount<C: NamadaTypes = SdkTypes> {
1911    /// Common query args
1912    pub query: Query<C>,
1913    /// Address of an owner
1914    pub owner: C::Address,
1915}
1916
1917/// Query token balance(s)
1918#[derive(Clone, Debug)]
1919pub struct QueryBalance<C: NamadaTypes = SdkTypes> {
1920    /// Common query args
1921    pub query: Query<C>,
1922    /// Address of an owner
1923    pub owner: C::BalanceOwner,
1924    /// Address of a token
1925    pub token: C::Address,
1926    /// Whether not to convert balances
1927    pub no_conversions: bool,
1928    /// Optional height to query balances at
1929    pub height: Option<C::BlockHeight>,
1930}
1931
1932/// Get an estimate for the MASP rewards for the next
1933/// MASP epoch.
1934#[derive(Clone, Debug)]
1935pub struct QueryShieldingRewardsEstimate<C: NamadaTypes = SdkTypes> {
1936    /// Common query args
1937    pub query: Query<C>,
1938    /// Viewing key
1939    pub owner: C::ViewingKey,
1940}
1941
1942/// Query historical transfer(s)
1943#[derive(Clone, Debug)]
1944pub struct QueryTransfers<C: NamadaTypes = SdkTypes> {
1945    /// Common query args
1946    pub query: Query<C>,
1947    /// Address of an owner
1948    pub owner: Option<C::BalanceOwner>,
1949    /// Address of a token
1950    pub token: Option<C::Address>,
1951}
1952
1953/// Query PoS bond(s)
1954#[derive(Clone, Debug)]
1955pub struct QueryBonds<C: NamadaTypes = SdkTypes> {
1956    /// Common query args
1957    pub query: Query<C>,
1958    /// Address of an owner
1959    pub owner: Option<C::Address>,
1960    /// Address of a validator
1961    pub validator: Option<C::Address>,
1962}
1963
1964/// Query PoS bonded stake
1965#[derive(Clone, Debug)]
1966pub struct QueryBondedStake<C: NamadaTypes = SdkTypes> {
1967    /// Common query args
1968    pub query: Query<C>,
1969    /// Address of a validator
1970    pub validator: Option<C::Address>,
1971    /// Epoch in which to find bonded stake
1972    pub epoch: Option<Epoch>,
1973}
1974
1975/// Query the state of a validator (its validator set or if it is jailed)
1976#[derive(Clone, Debug)]
1977pub struct QueryValidatorState<C: NamadaTypes = SdkTypes> {
1978    /// Common query args
1979    pub query: Query<C>,
1980    /// Address of a validator
1981    pub validator: C::Address,
1982    /// Epoch in which to find the validator state
1983    pub epoch: Option<Epoch>,
1984}
1985
1986#[derive(Clone, Debug)]
1987/// Commission rate change args
1988pub struct CommissionRateChange<C: NamadaTypes = SdkTypes> {
1989    /// Common tx arguments
1990    pub tx: Tx<C>,
1991    /// Validator address (should be self)
1992    pub validator: C::Address,
1993    /// Value to which the tx changes the commission rate
1994    pub rate: Dec,
1995    /// Path to the TX WASM code file
1996    pub tx_code_path: PathBuf,
1997}
1998
1999impl<C: NamadaTypes> TxBuilder<C> for CommissionRateChange<C> {
2000    fn tx<F>(self, func: F) -> Self
2001    where
2002        F: FnOnce(Tx<C>) -> Tx<C>,
2003    {
2004        CommissionRateChange {
2005            tx: func(self.tx),
2006            ..self
2007        }
2008    }
2009}
2010
2011impl<C: NamadaTypes> CommissionRateChange<C> {
2012    /// Validator address (should be self)
2013    pub fn validator(self, validator: C::Address) -> Self {
2014        Self { validator, ..self }
2015    }
2016
2017    /// Value to which the tx changes the commission rate
2018    pub fn rate(self, rate: Dec) -> Self {
2019        Self { rate, ..self }
2020    }
2021
2022    /// Path to the TX WASM code file
2023    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2024        Self {
2025            tx_code_path,
2026            ..self
2027        }
2028    }
2029}
2030
2031impl CommissionRateChange {
2032    /// Build a transaction from this builder
2033    pub async fn build(
2034        &self,
2035        context: &impl Namada,
2036    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2037        tx::build_validator_commission_change(context, self).await
2038    }
2039}
2040
2041#[derive(Clone, Debug)]
2042/// Consensus key change args
2043pub struct ConsensusKeyChange<C: NamadaTypes = SdkTypes> {
2044    /// Common tx arguments
2045    pub tx: Tx<C>,
2046    /// Validator address (should be self)
2047    pub validator: C::Address,
2048    /// New consensus key
2049    pub consensus_key: Option<C::PublicKey>,
2050    /// Don't encrypt the keypair
2051    pub unsafe_dont_encrypt: bool,
2052    /// Path to the TX WASM code file
2053    pub tx_code_path: PathBuf,
2054}
2055
2056impl<C: NamadaTypes> TxBuilder<C> for ConsensusKeyChange<C> {
2057    fn tx<F>(self, func: F) -> Self
2058    where
2059        F: FnOnce(Tx<C>) -> Tx<C>,
2060    {
2061        ConsensusKeyChange {
2062            tx: func(self.tx),
2063            ..self
2064        }
2065    }
2066}
2067
2068impl<C: NamadaTypes> ConsensusKeyChange<C> {
2069    /// Validator address (should be self)
2070    pub fn validator(self, validator: C::Address) -> Self {
2071        Self { validator, ..self }
2072    }
2073
2074    /// Value to which the tx changes the commission rate
2075    pub fn consensus_key(self, consensus_key: C::PublicKey) -> Self {
2076        Self {
2077            consensus_key: Some(consensus_key),
2078            ..self
2079        }
2080    }
2081
2082    /// Path to the TX WASM code file
2083    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2084        Self {
2085            tx_code_path,
2086            ..self
2087        }
2088    }
2089}
2090
2091impl ConsensusKeyChange {
2092    /// Build a transaction from this builder
2093    pub async fn build(
2094        &self,
2095        context: &impl Namada,
2096    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2097        tx::build_change_consensus_key(context, self).await
2098    }
2099}
2100
2101#[derive(Clone, Debug)]
2102/// Commission rate change args
2103pub struct MetaDataChange<C: NamadaTypes = SdkTypes> {
2104    /// Common tx arguments
2105    pub tx: Tx<C>,
2106    /// Validator address (should be self)
2107    pub validator: C::Address,
2108    /// New validator email
2109    pub email: Option<String>,
2110    /// New validator description
2111    pub description: Option<String>,
2112    /// New validator website
2113    pub website: Option<String>,
2114    /// New validator discord handle
2115    pub discord_handle: Option<String>,
2116    /// New validator avatar url
2117    pub avatar: Option<String>,
2118    /// New validator name
2119    pub name: Option<String>,
2120    /// New validator commission rate
2121    pub commission_rate: Option<Dec>,
2122    /// Path to the TX WASM code file
2123    pub tx_code_path: PathBuf,
2124}
2125
2126impl<C: NamadaTypes> TxBuilder<C> for MetaDataChange<C> {
2127    fn tx<F>(self, func: F) -> Self
2128    where
2129        F: FnOnce(Tx<C>) -> Tx<C>,
2130    {
2131        MetaDataChange {
2132            tx: func(self.tx),
2133            ..self
2134        }
2135    }
2136}
2137
2138impl<C: NamadaTypes> MetaDataChange<C> {
2139    /// Validator address (should be self)
2140    pub fn validator(self, validator: C::Address) -> Self {
2141        Self { validator, ..self }
2142    }
2143
2144    /// Path to the TX WASM code file
2145    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2146        Self {
2147            tx_code_path,
2148            ..self
2149        }
2150    }
2151
2152    /// New validator email
2153    pub fn email(self, email: String) -> Self {
2154        Self {
2155            email: Some(email),
2156            ..self
2157        }
2158    }
2159
2160    /// New validator description
2161    pub fn description(self, description: String) -> Self {
2162        Self {
2163            description: Some(description),
2164            ..self
2165        }
2166    }
2167
2168    /// New validator website
2169    pub fn website(self, website: String) -> Self {
2170        Self {
2171            website: Some(website),
2172            ..self
2173        }
2174    }
2175
2176    /// New validator discord handle
2177    pub fn discord_handle(self, discord_handle: String) -> Self {
2178        Self {
2179            discord_handle: Some(discord_handle),
2180            ..self
2181        }
2182    }
2183
2184    /// New validator avatar url
2185    pub fn avatar(self, avatar: String) -> Self {
2186        Self {
2187            avatar: Some(avatar),
2188            ..self
2189        }
2190    }
2191
2192    /// New validator name
2193    pub fn name(self, name: String) -> Self {
2194        Self {
2195            name: Some(name),
2196            ..self
2197        }
2198    }
2199
2200    /// New validator commission rate
2201    pub fn commission_rate(self, commission_rate: Dec) -> Self {
2202        Self {
2203            commission_rate: Some(commission_rate),
2204            ..self
2205        }
2206    }
2207}
2208
2209impl MetaDataChange {
2210    /// Build a transaction from this builder
2211    pub async fn build(
2212        &self,
2213        context: &impl Namada,
2214    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2215        tx::build_validator_metadata_change(context, self).await
2216    }
2217}
2218
2219#[derive(Clone, Debug)]
2220/// Commission rate change args
2221pub struct UpdateStewardCommission<C: NamadaTypes = SdkTypes> {
2222    /// Common tx arguments
2223    pub tx: Tx<C>,
2224    /// Steward address
2225    pub steward: C::Address,
2226    /// Value to which the tx changes the commission rate
2227    pub commission: C::Data,
2228    /// Path to the TX WASM code file
2229    pub tx_code_path: PathBuf,
2230}
2231
2232impl<C: NamadaTypes> TxBuilder<C> for UpdateStewardCommission<C> {
2233    fn tx<F>(self, func: F) -> Self
2234    where
2235        F: FnOnce(Tx<C>) -> Tx<C>,
2236    {
2237        UpdateStewardCommission {
2238            tx: func(self.tx),
2239            ..self
2240        }
2241    }
2242}
2243
2244impl<C: NamadaTypes> UpdateStewardCommission<C> {
2245    /// Steward address
2246    pub fn steward(self, steward: C::Address) -> Self {
2247        Self { steward, ..self }
2248    }
2249
2250    /// Value to which the tx changes the commission rate
2251    pub fn commission(self, commission: C::Data) -> Self {
2252        Self { commission, ..self }
2253    }
2254
2255    /// Path to the TX WASM code file
2256    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2257        Self {
2258            tx_code_path,
2259            ..self
2260        }
2261    }
2262}
2263
2264impl UpdateStewardCommission {
2265    /// Build a transaction from this builder
2266    pub async fn build(
2267        &self,
2268        context: &impl Namada,
2269    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2270        tx::build_update_steward_commission(context, self).await
2271    }
2272}
2273
2274#[derive(Clone, Debug)]
2275/// Commission rate change args
2276pub struct ResignSteward<C: NamadaTypes = SdkTypes> {
2277    /// Common tx arguments
2278    pub tx: Tx<C>,
2279    /// Validator address
2280    pub steward: C::Address,
2281    /// Path to the TX WASM code file
2282    pub tx_code_path: PathBuf,
2283}
2284
2285impl<C: NamadaTypes> TxBuilder<C> for ResignSteward<C> {
2286    fn tx<F>(self, func: F) -> Self
2287    where
2288        F: FnOnce(Tx<C>) -> Tx<C>,
2289    {
2290        ResignSteward {
2291            tx: func(self.tx),
2292            ..self
2293        }
2294    }
2295}
2296
2297impl<C: NamadaTypes> ResignSteward<C> {
2298    /// Validator address
2299    pub fn steward(self, steward: C::Address) -> Self {
2300        Self { steward, ..self }
2301    }
2302
2303    /// Path to the TX WASM code file
2304    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2305        Self {
2306            tx_code_path,
2307            ..self
2308        }
2309    }
2310}
2311
2312impl ResignSteward {
2313    /// Build a transaction from this builder
2314    pub async fn build(
2315        &self,
2316        context: &impl Namada,
2317    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2318        tx::build_resign_steward(context, self).await
2319    }
2320}
2321
2322#[derive(Clone, Debug)]
2323/// Re-activate a jailed validator args
2324pub struct TxUnjailValidator<C: NamadaTypes = SdkTypes> {
2325    /// Common tx arguments
2326    pub tx: Tx<C>,
2327    /// Validator address (should be self)
2328    pub validator: C::Address,
2329    /// Path to the TX WASM code file
2330    pub tx_code_path: PathBuf,
2331}
2332
2333impl<C: NamadaTypes> TxBuilder<C> for TxUnjailValidator<C> {
2334    fn tx<F>(self, func: F) -> Self
2335    where
2336        F: FnOnce(Tx<C>) -> Tx<C>,
2337    {
2338        TxUnjailValidator {
2339            tx: func(self.tx),
2340            ..self
2341        }
2342    }
2343}
2344
2345impl<C: NamadaTypes> TxUnjailValidator<C> {
2346    /// Validator address (should be self)
2347    pub fn validator(self, validator: C::Address) -> Self {
2348        Self { validator, ..self }
2349    }
2350
2351    /// Path to the TX WASM code file
2352    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2353        Self {
2354            tx_code_path,
2355            ..self
2356        }
2357    }
2358}
2359
2360impl TxUnjailValidator {
2361    /// Build a transaction from this builder
2362    pub async fn build(
2363        &self,
2364        context: &impl Namada,
2365    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2366        tx::build_unjail_validator(context, self).await
2367    }
2368}
2369
2370#[derive(Clone, Debug)]
2371/// Deactivate validator args
2372pub struct TxDeactivateValidator<C: NamadaTypes = SdkTypes> {
2373    /// Common tx arguments
2374    pub tx: Tx<C>,
2375    /// Validator address (should be self)
2376    pub validator: C::Address,
2377    /// Path to the TX WASM code file
2378    pub tx_code_path: PathBuf,
2379}
2380
2381impl<C: NamadaTypes> TxBuilder<C> for TxDeactivateValidator<C> {
2382    fn tx<F>(self, func: F) -> Self
2383    where
2384        F: FnOnce(Tx<C>) -> Tx<C>,
2385    {
2386        TxDeactivateValidator {
2387            tx: func(self.tx),
2388            ..self
2389        }
2390    }
2391}
2392
2393impl<C: NamadaTypes> TxDeactivateValidator<C> {
2394    /// Validator address (should be self)
2395    pub fn validator(self, validator: C::Address) -> Self {
2396        Self { validator, ..self }
2397    }
2398
2399    /// Path to the TX WASM code file
2400    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2401        Self {
2402            tx_code_path,
2403            ..self
2404        }
2405    }
2406}
2407
2408impl TxDeactivateValidator {
2409    /// Build a transaction from this builder
2410    pub async fn build(
2411        &self,
2412        context: &impl Namada,
2413    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2414        tx::build_deactivate_validator(context, self).await
2415    }
2416}
2417
2418#[derive(Clone, Debug)]
2419/// Re-activate a deactivated validator args
2420pub struct TxReactivateValidator<C: NamadaTypes = SdkTypes> {
2421    /// Common tx arguments
2422    pub tx: Tx<C>,
2423    /// Validator address (should be self)
2424    pub validator: C::Address,
2425    /// Path to the TX WASM code file
2426    pub tx_code_path: PathBuf,
2427}
2428
2429impl<C: NamadaTypes> TxBuilder<C> for TxReactivateValidator<C> {
2430    fn tx<F>(self, func: F) -> Self
2431    where
2432        F: FnOnce(Tx<C>) -> Tx<C>,
2433    {
2434        TxReactivateValidator {
2435            tx: func(self.tx),
2436            ..self
2437        }
2438    }
2439}
2440
2441impl<C: NamadaTypes> TxReactivateValidator<C> {
2442    /// Validator address (should be self)
2443    pub fn validator(self, validator: C::Address) -> Self {
2444        Self { validator, ..self }
2445    }
2446
2447    /// Path to the TX WASM code file
2448    pub fn tx_code_path(self, tx_code_path: PathBuf) -> Self {
2449        Self {
2450            tx_code_path,
2451            ..self
2452        }
2453    }
2454}
2455
2456impl TxReactivateValidator {
2457    /// Build a transaction from this builder
2458    pub async fn build(
2459        &self,
2460        context: &impl Namada,
2461    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
2462        tx::build_reactivate_validator(context, self).await
2463    }
2464}
2465
2466#[derive(Clone, Debug)]
2467/// Sync notes from MASP owned by the provided spending /
2468/// viewing keys. Syncing can be told to stop at a given
2469/// block height.
2470pub struct ShieldedSync<C: NamadaTypes = SdkTypes> {
2471    /// The ledger address
2472    pub ledger_address: C::ConfigRpcTendermintAddress,
2473    /// Height to sync up to. Defaults to most recent
2474    pub last_query_height: Option<BlockHeight>,
2475    /// Spending keys used to determine note ownership
2476    pub spending_keys: Vec<C::DatedSpendingKey>,
2477    /// Viewing keys used to determine note ownership
2478    pub viewing_keys: Vec<C::DatedViewingKey>,
2479    /// Address of a `namada-masp-indexer` live instance
2480    ///
2481    /// If present, the shielded sync will be performed
2482    /// using data retrieved from the given indexer
2483    pub with_indexer: Option<C::MaspIndexerAddress>,
2484    /// Wait for the last query height.
2485    pub wait_for_last_query_height: bool,
2486    /// Maximum number of fetch jobs that will ever
2487    /// execute concurrently during the shielded sync.
2488    pub max_concurrent_fetches: usize,
2489    /// Number of blocks fetched per concurrent fetch job.
2490    pub block_batch_size: usize,
2491    /// Maximum number of times to retry fetching. If `None`
2492    /// is provided, defaults to "forever".
2493    pub retry_strategy: RetryStrategy,
2494}
2495
2496/// Query PoS commission rate
2497#[derive(Clone, Debug)]
2498pub struct QueryCommissionRate<C: NamadaTypes = SdkTypes> {
2499    /// Common query args
2500    pub query: Query<C>,
2501    /// Address of a validator
2502    pub validator: C::Address,
2503    /// Epoch in which to find commission rate
2504    pub epoch: Option<Epoch>,
2505}
2506
2507/// Query validator metadata
2508#[derive(Clone, Debug)]
2509pub struct QueryMetaData<C: NamadaTypes = SdkTypes> {
2510    /// Common query args
2511    pub query: Query<C>,
2512    /// Address of a validator
2513    pub validator: C::Address,
2514}
2515
2516/// Query PoS slashes
2517#[derive(Clone, Debug)]
2518pub struct QuerySlashes<C: NamadaTypes = SdkTypes> {
2519    /// Common query args
2520    pub query: Query<C>,
2521    /// Address of a validator
2522    pub validator: Option<C::Address>,
2523}
2524
2525/// Query PoS rewards
2526#[derive(Clone, Debug)]
2527pub struct QueryRewards<C: NamadaTypes = SdkTypes> {
2528    /// Common query args
2529    pub query: Query<C>,
2530    /// Address of the source
2531    pub source: Option<C::Address>,
2532    /// Address of the validator
2533    pub validator: C::Address,
2534    /// Epoch in which to find rewards
2535    pub epoch: Option<Epoch>,
2536}
2537
2538/// Query PoS delegations
2539#[derive(Clone, Debug)]
2540pub struct QueryDelegations<C: NamadaTypes = SdkTypes> {
2541    /// Common query args
2542    pub query: Query<C>,
2543    /// Address of an owner
2544    pub owner: C::Address,
2545}
2546
2547/// Query token total supply
2548#[derive(Clone, Debug)]
2549pub struct QueryTotalSupply<C: NamadaTypes = SdkTypes> {
2550    /// Common query args
2551    pub query: Query<C>,
2552    /// Token address
2553    pub token: C::Address,
2554}
2555
2556/// Query effective native supply
2557#[derive(Clone, Debug)]
2558pub struct QueryEffNativeSupply<C: NamadaTypes = SdkTypes> {
2559    /// Common query args
2560    pub query: Query<C>,
2561}
2562
2563/// Query estimate of staking rewards rate
2564#[derive(Clone, Debug)]
2565pub struct QueryStakingRewardsRate<C: NamadaTypes = SdkTypes> {
2566    /// Common query args
2567    pub query: Query<C>,
2568}
2569
2570/// Query PoS to find a validator
2571#[derive(Clone, Debug)]
2572pub struct QueryFindValidator<C: NamadaTypes = SdkTypes> {
2573    /// Common query args
2574    pub query: Query<C>,
2575    /// Validator address, either Comet or native
2576    pub addr: Either<String, C::Address>,
2577}
2578
2579/// Query the raw bytes of given storage key
2580#[derive(Clone, Debug)]
2581pub struct QueryRawBytes<C: NamadaTypes = SdkTypes> {
2582    /// The storage key to query
2583    pub storage_key: storage::Key,
2584    /// Common query args
2585    pub query: Query<C>,
2586}
2587
2588/// Query the IBC rate limit for the specified token
2589#[derive(Clone, Debug)]
2590pub struct QueryIbcRateLimit<C: NamadaTypes = SdkTypes> {
2591    /// Common query args
2592    pub query: Query<C>,
2593    /// Token address
2594    pub token: C::Address,
2595}
2596
2597/// The possible values for the tx expiration
2598#[derive(Clone, Debug, Default)]
2599pub enum TxExpiration {
2600    /// Force the tx to have no expiration
2601    NoExpiration,
2602    /// Request the default expiration
2603    #[default]
2604    Default,
2605    /// User-provided custom expiration
2606    Custom(DateTimeUtc),
2607}
2608
2609impl TxExpiration {
2610    /// Converts the expiration argument into an optional [`DateTimeUtc`]
2611    pub fn to_datetime(&self) -> Option<DateTimeUtc> {
2612        match self {
2613            TxExpiration::NoExpiration => None,
2614            // Default to 1 hour
2615            TxExpiration::Default =>
2616            {
2617                #[allow(clippy::disallowed_methods)]
2618                Some(DateTimeUtc::now() + namada_core::time::Duration::hours(1))
2619            }
2620            TxExpiration::Custom(exp) => Some(exp.to_owned()),
2621        }
2622    }
2623}
2624
2625/// Argument for dry-runs
2626#[derive(Clone, Debug)]
2627pub enum DryRun {
2628    /// Request a dry run of the inner transaction(s) only
2629    Inner,
2630    /// Request a dry run of both the inner transaction(s) and the wrapper
2631    Wrapper,
2632}
2633
2634/// Argument for dumping transactions
2635#[derive(Clone, Debug)]
2636pub enum DumpTx {
2637    /// Dump the raw transaction
2638    Inner,
2639    /// Dump the wrapper transaction
2640    Wrapper,
2641}
2642
2643/// Arguments to request wrapping a transaction
2644#[derive(Clone, Debug)]
2645pub struct Wrapper<C: NamadaTypes = SdkTypes> {
2646    /// Do not wait for the transaction to be added to the blockchain
2647    pub broadcast_only: bool,
2648    /// The amount being paid (for gas unit) to include the transaction
2649    pub fee_amount: Option<InputAmount>,
2650    /// The fee payer signing key
2651    pub wrapper_fee_payer: Option<C::PublicKey>,
2652    /// The token in which the fee is being paid
2653    pub fee_token: C::AddrOrNativeToken,
2654    /// The max amount of gas used to process tx
2655    pub gas_limit: GasLimit,
2656}
2657
2658/// Common transaction arguments
2659#[derive(Clone, Debug)]
2660pub struct Tx<C: NamadaTypes = SdkTypes> {
2661    /// Simulate applying the transaction (possibly the wrapper too)
2662    pub dry_run: Option<DryRun>,
2663    /// Dump the transaction bytes to file, either the raw or the whole wrapper
2664    /// transaction
2665    pub dump_tx: Option<DumpTx>,
2666    /// The output directory path to where serialize the data
2667    pub output_folder: Option<PathBuf>,
2668    /// Build the transaction even if it doesn't pass client checks
2669    pub force: bool,
2670    /// The address of the ledger node as host:port
2671    pub ledger_address: C::ConfigRpcTendermintAddress,
2672    /// If any new account is initialized by the tx, use the given alias to
2673    /// save it in the wallet.
2674    pub initialized_account_alias: Option<String>,
2675    /// Whether to force overwrite the above alias, if it is provided, in the
2676    /// wallet.
2677    pub wallet_alias_force: bool,
2678    /// Requests wrapping the transaction, optional in case only the raw tx
2679    /// should be built
2680    pub wrap_tx: Option<Wrapper<C>>,
2681    /// The optional expiration of the transaction
2682    pub expiration: TxExpiration,
2683    /// The chain id for which the transaction is intended
2684    pub chain_id: Option<ChainId>,
2685    /// Sign the tx with the key for the given alias from your wallet
2686    pub signing_keys: Vec<C::PublicKey>,
2687    /// Path to the TX WASM code file to reveal PK
2688    pub tx_reveal_code_path: PathBuf,
2689    /// Password to decrypt key
2690    pub password: Option<Zeroizing<String>>,
2691    /// Optional memo to be included in the transaction
2692    pub memo: Option<Memo>,
2693    /// Use device to sign the transaction
2694    pub use_device: bool,
2695    /// Hardware Wallet transport - HID (USB) or TCP
2696    pub device_transport: DeviceTransport,
2697}
2698
2699/// Hardware Wallet transport - HID (USB) or TCP
2700#[derive(Debug, Clone, Copy, Default)]
2701pub enum DeviceTransport {
2702    /// HID transport (USB connected hardware wallet)
2703    #[default]
2704    Hid,
2705    /// TCP transport
2706    Tcp,
2707}
2708
2709impl FromStr for DeviceTransport {
2710    type Err = String;
2711
2712    fn from_str(s: &str) -> Result<Self, Self::Err> {
2713        match s.trim().to_ascii_lowercase().as_str() {
2714            "hid" => Ok(Self::Hid),
2715            "tcp" => Ok(Self::Tcp),
2716            raw => Err(format!(
2717                "Unexpected device transport \"{raw}\". Valid options are \
2718                 \"hid\" or \"tcp\"."
2719            )),
2720        }
2721    }
2722}
2723
2724/// Builder functions for Tx
2725pub trait TxBuilder<C: NamadaTypes>: Sized {
2726    /// Apply the given function to the Tx inside self
2727    fn tx<F>(self, func: F) -> Self
2728    where
2729        F: FnOnce(Tx<C>) -> Tx<C>;
2730    /// Simulate applying the transaction
2731    fn dry_run(self, dry_run: Option<DryRun>) -> Self {
2732        self.tx(|x| Tx { dry_run, ..x })
2733    }
2734    /// Dump the transaction bytes to file
2735    fn dump_tx(self, dump_tx: Option<DumpTx>) -> Self {
2736        self.tx(|x| Tx { dump_tx, ..x })
2737    }
2738    /// The output directory path to where serialize the data
2739    fn output_folder(self, output_folder: PathBuf) -> Self {
2740        self.tx(|x| Tx {
2741            output_folder: Some(output_folder),
2742            ..x
2743        })
2744    }
2745    /// Submit the transaction even if it doesn't pass client checks
2746    fn force(self, force: bool) -> Self {
2747        self.tx(|x| Tx { force, ..x })
2748    }
2749    /// Wrap the transaction
2750    fn wrap_it(self, wrapper: Option<Wrapper<C>>) -> Self {
2751        self.tx(|x| Tx {
2752            wrap_tx: wrapper,
2753            ..x
2754        })
2755    }
2756    /// The address of the ledger node as host:port
2757    fn ledger_address(self, ledger_address: C::TendermintAddress) -> Self {
2758        self.tx(|x| Tx {
2759            ledger_address: C::ConfigRpcTendermintAddress::from(ledger_address),
2760            ..x
2761        })
2762    }
2763    /// If any new account is initialized by the tx, use the given alias to
2764    /// save it in the wallet.
2765    fn initialized_account_alias(
2766        self,
2767        initialized_account_alias: String,
2768    ) -> Self {
2769        self.tx(|x| Tx {
2770            initialized_account_alias: Some(initialized_account_alias),
2771            ..x
2772        })
2773    }
2774    /// Whether to force overwrite the above alias, if it is provided, in the
2775    /// wallet.
2776    fn wallet_alias_force(self, wallet_alias_force: bool) -> Self {
2777        self.tx(|x| Tx {
2778            wallet_alias_force,
2779            ..x
2780        })
2781    }
2782    /// The chain id for which the transaction is intended
2783    fn chain_id(self, chain_id: ChainId) -> Self {
2784        self.tx(|x| Tx {
2785            chain_id: Some(chain_id),
2786            ..x
2787        })
2788    }
2789    /// Sign the tx with the key for the given alias from your wallet
2790    fn signing_keys(self, signing_keys: Vec<C::PublicKey>) -> Self {
2791        self.tx(|x| Tx { signing_keys, ..x })
2792    }
2793    /// Path to the TX WASM code file to reveal PK
2794    fn tx_reveal_code_path(self, tx_reveal_code_path: PathBuf) -> Self {
2795        self.tx(|x| Tx {
2796            tx_reveal_code_path,
2797            ..x
2798        })
2799    }
2800    /// Password to decrypt key
2801    fn password(self, password: Zeroizing<String>) -> Self {
2802        self.tx(|x| Tx {
2803            password: Some(password),
2804            ..x
2805        })
2806    }
2807    /// Change memo
2808    fn memo(self, memo: Vec<u8>) -> Self {
2809        self.tx(|x| Tx {
2810            memo: Some(memo),
2811            ..x
2812        })
2813    }
2814}
2815
2816impl<C: NamadaTypes> TxBuilder<C> for Tx<C> {
2817    fn tx<F>(self, func: F) -> Self
2818    where
2819        F: FnOnce(Tx<C>) -> Tx<C>,
2820    {
2821        func(self)
2822    }
2823}
2824
2825/// Wallet generate key and implicit address arguments
2826#[derive(Clone, Debug)]
2827pub struct KeyGen {
2828    /// Scheme type
2829    pub scheme: SchemeType,
2830    /// Whether to generate a spending key for the shielded pool
2831    pub shielded: bool,
2832    /// Whether to generate a raw non-hd key
2833    pub raw: bool,
2834    /// Key alias
2835    pub alias: String,
2836    /// Whether to force overwrite the alias
2837    pub alias_force: bool,
2838    /// Don't encrypt the keypair
2839    pub unsafe_dont_encrypt: bool,
2840    /// BIP44 / ZIP32 derivation path
2841    pub derivation_path: String,
2842    /// Prompt for BIP39 passphrase
2843    pub prompt_bip39_passphrase: bool,
2844    /// Allow non-compliant derivation path
2845    pub allow_non_compliant: bool,
2846    /// Optional block height after which this key was created.
2847    /// Only used for MASP keys.
2848    pub birthday: Option<BlockHeight>,
2849}
2850
2851/// Wallet restore key and implicit address arguments
2852#[derive(Clone, Debug)]
2853pub struct KeyDerive {
2854    /// Scheme type
2855    pub scheme: SchemeType,
2856    /// Whether to generate a MASP spending key
2857    pub shielded: bool,
2858    /// Key alias
2859    pub alias: String,
2860    /// Whether to force overwrite the alias
2861    pub alias_force: bool,
2862    /// Don't encrypt the keypair
2863    pub unsafe_dont_encrypt: bool,
2864    /// Use the deprecated pure ZIP 32 algorithm
2865    pub unsafe_pure_zip32: bool,
2866    /// BIP44 / ZIP32 derivation path
2867    pub derivation_path: String,
2868    /// Allow non-compliant derivation path
2869    pub allow_non_compliant: bool,
2870    /// Prompt for BIP39 passphrase
2871    pub prompt_bip39_passphrase: bool,
2872    /// Use device to generate key and address
2873    pub use_device: bool,
2874    /// Hardware Wallet transport - HID (USB) or TCP
2875    pub device_transport: DeviceTransport,
2876    /// Optional blockheight after which this key was created.
2877    /// Only used for MASP keys
2878    pub birthday: Option<BlockHeight>,
2879}
2880
2881/// Wallet list arguments
2882#[derive(Clone, Copy, Debug)]
2883pub struct KeyAddressList {
2884    /// Whether to list transparent secret keys only
2885    pub transparent_only: bool,
2886    /// Whether to list MASP spending keys only
2887    pub shielded_only: bool,
2888    /// List keys only
2889    pub keys_only: bool,
2890    /// List addresses only
2891    pub addresses_only: bool,
2892    /// Whether to decrypt secret / spending keys
2893    pub decrypt: bool,
2894    /// Show secret keys to user
2895    pub unsafe_show_secret: bool,
2896}
2897
2898/// Wallet key / address lookup arguments
2899#[derive(Clone, Debug)]
2900pub struct KeyAddressFind {
2901    /// Alias to find
2902    pub alias: Option<String>,
2903    /// Address to find
2904    pub address: Option<Address>,
2905    /// Public key to lookup keypair with
2906    pub public_key: Option<common::PublicKey>,
2907    /// Public key hash to lookup keypair with
2908    pub public_key_hash: Option<String>,
2909    /// Payment address to find
2910    pub payment_address: Option<PaymentAddress>,
2911    /// Find keys only
2912    pub keys_only: bool,
2913    /// Find addresses only
2914    pub addresses_only: bool,
2915    /// Whether to decrypt secret / spending keys
2916    pub decrypt: bool,
2917    /// Show secret keys to user
2918    pub unsafe_show_secret: bool,
2919}
2920/// Wallet key export arguments
2921#[derive(Clone, Debug)]
2922pub struct KeyExport {
2923    /// Key alias
2924    pub alias: String,
2925}
2926
2927/// Wallet key export arguments
2928#[derive(Clone, Debug)]
2929pub struct KeyConvert {
2930    /// Key alias
2931    pub alias: String,
2932}
2933
2934/// Wallet key import arguments
2935#[derive(Clone, Debug)]
2936pub struct KeyImport {
2937    /// File name
2938    pub file_path: String,
2939    /// Key alias
2940    pub alias: String,
2941    /// Whether to force overwrite the alias
2942    pub alias_force: bool,
2943    /// Don't encrypt the key
2944    pub unsafe_dont_encrypt: bool,
2945}
2946
2947/// Wallet key / address add arguments
2948#[derive(Clone, Debug)]
2949pub struct KeyAddressAdd {
2950    /// Address alias
2951    pub alias: String,
2952    /// Whether to force overwrite the alias
2953    pub alias_force: bool,
2954    /// Any supported value
2955    pub value: String,
2956    /// Optional block height after which this key was created.
2957    /// Only used for MASP keys.
2958    pub birthday: Option<BlockHeight>,
2959    /// Don't encrypt the key
2960    pub unsafe_dont_encrypt: bool,
2961}
2962
2963/// Wallet key / address remove arguments
2964#[derive(Clone, Debug)]
2965pub struct KeyAddressRemove {
2966    /// Address alias
2967    pub alias: String,
2968    /// Confirmation to remove the alias
2969    pub do_it: bool,
2970}
2971
2972/// Generate payment address arguments
2973#[derive(Clone, Debug)]
2974pub struct PayAddressGen {
2975    /// Payment address alias
2976    pub alias: String,
2977    /// Whether to force overwrite the alias
2978    pub alias_force: bool,
2979    /// Viewing key
2980    pub viewing_key: String,
2981    /// Diversifier index to start search at
2982    pub diversifier_index: Option<DiversifierIndex>,
2983}
2984
2985/// Bridge pool batch recommendation.
2986#[derive(Clone, Debug)]
2987pub struct RecommendBatch<C: NamadaTypes = SdkTypes> {
2988    /// The query parameters.
2989    pub query: Query<C>,
2990    /// The maximum amount of gas to spend.
2991    pub max_gas: Option<u64>,
2992    /// An optional parameter indicating how much net
2993    /// gas the relayer is willing to pay.
2994    pub gas: Option<u64>,
2995    /// Bridge pool recommendations conversion rates table.
2996    pub conversion_table: C::BpConversionTable,
2997}
2998
2999/// A transfer to be added to the Ethereum bridge pool.
3000#[derive(Clone, Debug)]
3001pub struct EthereumBridgePool<C: NamadaTypes = SdkTypes> {
3002    /// Whether the transfer is for a NUT.
3003    ///
3004    /// By default, we add wrapped ERC20s onto the
3005    /// Bridge pool.
3006    pub nut: bool,
3007    /// The args for building a tx to the bridge pool
3008    pub tx: Tx<C>,
3009    /// The type of token
3010    pub asset: EthAddress,
3011    /// The recipient address
3012    pub recipient: EthAddress,
3013    /// The sender of the transfer
3014    pub sender: C::Address,
3015    /// The amount to be transferred
3016    pub amount: InputAmount,
3017    /// The amount of gas fees
3018    pub fee_amount: InputAmount,
3019    /// The account of fee payer.
3020    ///
3021    /// If unset, it is the same as the sender.
3022    pub fee_payer: Option<C::Address>,
3023    /// The token in which the gas is being paid
3024    pub fee_token: C::AddrOrNativeToken,
3025    /// Path to the tx WASM code file
3026    pub code_path: PathBuf,
3027}
3028
3029impl<C: NamadaTypes> TxBuilder<C> for EthereumBridgePool<C> {
3030    fn tx<F>(self, func: F) -> Self
3031    where
3032        F: FnOnce(Tx<C>) -> Tx<C>,
3033    {
3034        EthereumBridgePool {
3035            tx: func(self.tx),
3036            ..self
3037        }
3038    }
3039}
3040
3041impl<C: NamadaTypes> EthereumBridgePool<C> {
3042    /// Whether the transfer is for a NUT.
3043    ///
3044    /// By default, we add wrapped ERC20s onto the
3045    /// Bridge pool.
3046    pub fn nut(self, nut: bool) -> Self {
3047        Self { nut, ..self }
3048    }
3049
3050    /// The type of token
3051    pub fn asset(self, asset: EthAddress) -> Self {
3052        Self { asset, ..self }
3053    }
3054
3055    /// The recipient address
3056    pub fn recipient(self, recipient: EthAddress) -> Self {
3057        Self { recipient, ..self }
3058    }
3059
3060    /// The sender of the transfer
3061    pub fn sender(self, sender: C::Address) -> Self {
3062        Self { sender, ..self }
3063    }
3064
3065    /// The amount to be transferred
3066    pub fn amount(self, amount: InputAmount) -> Self {
3067        Self { amount, ..self }
3068    }
3069
3070    /// The amount of gas fees
3071    pub fn fee_amount(self, fee_amount: InputAmount) -> Self {
3072        Self { fee_amount, ..self }
3073    }
3074
3075    /// The account of fee payer.
3076    ///
3077    /// If unset, it is the same as the sender.
3078    pub fn fee_payer(self, fee_payer: C::Address) -> Self {
3079        Self {
3080            fee_payer: Some(fee_payer),
3081            ..self
3082        }
3083    }
3084
3085    /// The token in which the gas is being paid
3086    pub fn fee_token(self, fee_token: C::Address) -> Self {
3087        Self {
3088            fee_token: fee_token.into(),
3089            ..self
3090        }
3091    }
3092
3093    /// Path to the tx WASM code file
3094    pub fn code_path(self, code_path: PathBuf) -> Self {
3095        Self { code_path, ..self }
3096    }
3097}
3098
3099impl EthereumBridgePool {
3100    /// Build a transaction from this builder
3101    pub async fn build(
3102        self,
3103        context: &impl Namada,
3104    ) -> crate::error::Result<(namada_tx::Tx, SigningData)> {
3105        bridge_pool::build_bridge_pool_tx(context, self).await
3106    }
3107}
3108
3109/// Bridge pool proof arguments.
3110#[derive(Debug, Clone)]
3111pub struct BridgePoolProof<C: NamadaTypes = SdkTypes> {
3112    /// The address of the ledger node as host:port
3113    pub ledger_address: C::TendermintAddress,
3114    /// The keccak hashes of transfers to
3115    /// acquire a proof of.
3116    pub transfers: Vec<KeccakHash>,
3117    /// The address of the node responsible for relaying
3118    /// the transfers.
3119    ///
3120    /// This node will receive the gas fees escrowed in
3121    /// the Bridge pool, to compensate the Ethereum relay
3122    /// procedure.
3123    pub relayer: Address,
3124}
3125
3126/// Arguments to an Ethereum Bridge pool relay operation.
3127#[derive(Debug, Clone)]
3128pub struct RelayBridgePoolProof<C: NamadaTypes = SdkTypes> {
3129    /// The address of the ledger node as host:port
3130    pub ledger_address: C::TendermintAddress,
3131    /// The hashes of the transfers to be relayed
3132    pub transfers: Vec<KeccakHash>,
3133    /// The Namada address for receiving fees for relaying
3134    pub relayer: Address,
3135    /// The number of confirmations to wait for on Ethereum
3136    pub confirmations: u64,
3137    /// The Ethereum RPC endpoint.
3138    pub eth_rpc_endpoint: C::EthereumAddress,
3139    /// The Ethereum gas that can be spent during
3140    /// the relay call.
3141    pub gas: Option<u64>,
3142    /// The price of Ethereum gas, during the
3143    /// relay call.
3144    pub gas_price: Option<u64>,
3145    /// The address of the Ethereum wallet to pay the gas fees.
3146    /// If unset, the default wallet is used.
3147    pub eth_addr: Option<EthAddress>,
3148    /// Synchronize with the network, or exit immediately,
3149    /// if the Ethereum node has fallen behind.
3150    pub sync: bool,
3151}
3152
3153/// Bridge validator set arguments.
3154#[derive(Debug, Clone)]
3155pub struct BridgeValidatorSet<C: NamadaTypes = SdkTypes> {
3156    /// The address of the ledger node as host:port
3157    pub ledger_address: C::TendermintAddress,
3158    /// The epoch to query.
3159    pub epoch: Option<Epoch>,
3160}
3161
3162/// Governance validator set arguments.
3163#[derive(Debug, Clone)]
3164pub struct GovernanceValidatorSet<C: NamadaTypes = SdkTypes> {
3165    /// The address of the ledger node as host:port
3166    pub ledger_address: C::TendermintAddress,
3167    /// The epoch to query.
3168    pub epoch: Option<Epoch>,
3169}
3170
3171/// Validator set proof arguments.
3172#[derive(Debug, Clone)]
3173pub struct ValidatorSetProof<C: NamadaTypes = SdkTypes> {
3174    /// The address of the ledger node as host:port
3175    pub ledger_address: C::TendermintAddress,
3176    /// The epoch to query.
3177    pub epoch: Option<Epoch>,
3178}
3179
3180/// Validator set update relayer arguments.
3181#[derive(Debug, Clone)]
3182pub struct ValidatorSetUpdateRelay<C: NamadaTypes = SdkTypes> {
3183    /// Run in daemon mode, which will continuously
3184    /// perform validator set updates.
3185    pub daemon: bool,
3186    /// The address of the ledger node as host:port
3187    pub ledger_address: C::TendermintAddress,
3188    /// The number of block confirmations on Ethereum.
3189    pub confirmations: u64,
3190    /// The Ethereum RPC endpoint.
3191    pub eth_rpc_endpoint: C::EthereumAddress,
3192    /// The epoch of the validator set to relay.
3193    pub epoch: Option<Epoch>,
3194    /// The Ethereum gas that can be spent during
3195    /// the relay call.
3196    pub gas: Option<u64>,
3197    /// The price of Ethereum gas, during the
3198    /// relay call.
3199    pub gas_price: Option<u64>,
3200    /// The address of the Ethereum wallet to pay the gas fees.
3201    /// If unset, the default wallet is used.
3202    pub eth_addr: Option<EthAddress>,
3203    /// Synchronize with the network, or exit immediately,
3204    /// if the Ethereum node has fallen behind.
3205    pub sync: bool,
3206    /// The amount of time to sleep between failed
3207    /// daemon mode relays.
3208    pub retry_dur: Option<StdDuration>,
3209    /// The amount of time to sleep between successful
3210    /// daemon mode relays.
3211    pub success_dur: Option<StdDuration>,
3212}
3213
3214/// IBC shielding transfer generation arguments
3215#[derive(Clone, Debug)]
3216pub struct GenIbcShieldingTransfer<C: NamadaTypes = SdkTypes> {
3217    /// The query parameters.
3218    pub query: Query<C>,
3219    /// The output directory path to where serialize the data
3220    pub output_folder: Option<PathBuf>,
3221    /// The target address
3222    pub target: C::PaymentAddress,
3223    /// Transferred token amount
3224    pub amount: InputAmount,
3225    /// The optional expiration of the masp shielding transaction
3226    pub expiration: TxExpiration,
3227    /// Asset to shield over IBC to Namada
3228    pub asset: IbcShieldingTransferAsset<C>,
3229    /// The optional data for the frontend sustainability fee (the target and
3230    /// the amount, the token must be the same as the one involved in the
3231    /// shielding transaction since ics-20 only supports a single asset)
3232    /// NOTE: if the shielding operation is part of a swap, and this is
3233    /// shielded (from MASP to MASP), no sustainability fee should be taken
3234    pub frontend_sus_fee: Option<(C::PaymentAddress, Dec)>,
3235}
3236
3237/// IBC shielding transfer asset, to be used by [`GenIbcShieldingTransfer`]
3238#[derive(Clone, Debug)]
3239pub enum IbcShieldingTransferAsset<C: NamadaTypes = SdkTypes> {
3240    /// Attempt to look-up the address of the asset to shield on Namada
3241    LookupNamadaAddress {
3242        /// The token address which could be a non-namada address
3243        token: String,
3244        /// Port ID via which the token is received
3245        port_id: PortId,
3246        /// Channel ID via which the token is received
3247        channel_id: ChannelId,
3248    },
3249    /// Namada address of the token that will be received.
3250    Address(C::Address),
3251}