Skip to content

Commit 32c44b4

Browse files
committed
Integration tests for frontend fees and fixes to the sdk builders
1 parent 61cb10e commit 32c44b4

File tree

3 files changed

+344
-42
lines changed

3 files changed

+344
-42
lines changed

crates/apps_lib/src/cli.rs

Lines changed: 113 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3548,6 +3548,9 @@ pub mod args {
35483548
pub const FEE_PAYER_OPT: ArgOpt<WalletPublicKey> = arg_opt("gas-payer");
35493549
pub const FILE_PATH: Arg<String> = arg("file");
35503550
pub const FORCE: ArgFlag = flag("force");
3551+
#[cfg(any(test, feature = "testing"))]
3552+
pub const FRONTEND_SUS_FEE: ArgOpt<WalletAddress> =
3553+
arg_opt("frontend-sus-fee");
35513554
pub const FULL_RESET: ArgFlag = flag("full-reset");
35523555
pub const GAS_LIMIT: ArgDefault<GasLimit> = arg_default(
35533556
"gas-limit",
@@ -4930,11 +4933,11 @@ pub mod args {
49304933
ctx: &mut Context,
49314934
) -> Result<TxShieldingTransfer<SdkTypes>, Self::Error> {
49324935
let tx = self.tx.to_sdk(ctx)?;
4933-
let mut data = vec![];
4936+
let mut sources = vec![];
49344937
let chain_ctx = ctx.borrow_mut_chain_or_exit();
49354938

49364939
for transfer_data in self.sources {
4937-
data.push(TxTransparentSource {
4940+
sources.push(TxTransparentSource {
49384941
source: chain_ctx.get(&transfer_data.source),
49394942
token: chain_ctx.get(&transfer_data.token),
49404943
amount: transfer_data.amount,
@@ -4949,13 +4952,19 @@ pub mod args {
49494952
amount: transfer_data.amount,
49504953
});
49514954
}
4955+
let frontend_sus_fee =
4956+
self.frontend_sus_fee.map(|fee| TxTransparentTarget {
4957+
target: chain_ctx.get(&fee.target),
4958+
token: chain_ctx.get(&fee.token),
4959+
amount: fee.amount,
4960+
});
49524961

49534962
Ok(TxShieldingTransfer::<SdkTypes> {
49544963
tx,
4955-
sources: data,
4964+
sources,
49564965
targets,
49574966
tx_code_path: self.tx_code_path.to_path_buf(),
4958-
frontend_sus_fee: None,
4967+
frontend_sus_fee,
49594968
})
49604969
}
49614970
}
@@ -4966,13 +4975,49 @@ pub mod args {
49664975
let source = SOURCE.parse(matches);
49674976
let target = PAYMENT_ADDRESS_TARGET.parse(matches);
49684977
let token = TOKEN.parse(matches);
4969-
let amount = InputAmount::Unvalidated(AMOUNT.parse(matches));
4978+
let raw_amount = AMOUNT.parse(matches);
4979+
let amount = InputAmount::Unvalidated(raw_amount);
49704980
let tx_code_path = PathBuf::from(TX_TRANSFER_WASM);
4971-
let data = vec![TxTransparentSource {
4981+
4982+
#[cfg(any(test, feature = "testing"))]
4983+
let frontend_sus_fee = FRONTEND_SUS_FEE.parse(matches).map(
4984+
|target| // Take a constant fee of 1 on top of the input amount
4985+
TxTransparentTarget {
4986+
target,
4987+
token: token.clone(),
4988+
amount: InputAmount::Unvalidated(
4989+
token::DenominatedAmount::new(
4990+
1.into(),
4991+
raw_amount.denom(),
4992+
),
4993+
),
4994+
},
4995+
);
4996+
4997+
#[cfg(not(any(test, feature = "testing")))]
4998+
let frontend_sus_fee = None;
4999+
5000+
let mut sources = if frontend_sus_fee.is_some() {
5001+
// Adjust the inputs to account for the extra token
5002+
vec![TxTransparentSource {
5003+
source: source.clone(),
5004+
token: token.clone(),
5005+
amount: InputAmount::Unvalidated(
5006+
token::DenominatedAmount::new(
5007+
1.into(),
5008+
raw_amount.denom(),
5009+
),
5010+
),
5011+
}]
5012+
} else {
5013+
vec![]
5014+
};
5015+
5016+
sources.push(TxTransparentSource {
49725017
source,
49735018
token: token.clone(),
49745019
amount,
4975-
}];
5020+
});
49765021
let targets = vec![TxShieldedTarget {
49775022
target,
49785023
token,
@@ -4981,15 +5026,16 @@ pub mod args {
49815026

49825027
Self {
49835028
tx,
4984-
sources: data,
5029+
sources,
49855030
targets,
49865031
tx_code_path,
4987-
frontend_sus_fee: None,
5032+
frontend_sus_fee,
49885033
}
49895034
}
49905035

49915036
fn def(app: App) -> App {
4992-
app.add_args::<Tx<CliTypes>>()
5037+
let app = app
5038+
.add_args::<Tx<CliTypes>>()
49935039
.arg(SOURCE.def().help(wrap!(
49945040
"The transparent source account address. The source's key \
49955041
will be used to produce the signature."
@@ -5004,7 +5050,15 @@ pub mod args {
50045050
AMOUNT
50055051
.def()
50065052
.help(wrap!("The amount to transfer in decimal.")),
5007-
)
5053+
);
5054+
5055+
#[cfg(any(test, feature = "testing"))]
5056+
let app = app.arg(FRONTEND_SUS_FEE.def().help(wrap!(
5057+
"The optional address of the frontend provider that will take \
5058+
the masp sustainability fee."
5059+
)));
5060+
5061+
app
50085062
}
50095063
}
50105064

@@ -5056,31 +5110,63 @@ pub mod args {
50565110
let source = SPENDING_KEY_SOURCE.parse(matches);
50575111
let target = TARGET.parse(matches);
50585112
let token = TOKEN.parse(matches);
5059-
let amount = InputAmount::Unvalidated(AMOUNT.parse(matches));
5113+
let raw_amount = AMOUNT.parse(matches);
5114+
let amount = InputAmount::Unvalidated(raw_amount);
50605115
let tx_code_path = PathBuf::from(TX_TRANSFER_WASM);
5061-
let data = vec![TxTransparentTarget {
5062-
target,
5116+
let targets = vec![TxTransparentTarget {
5117+
target: target.clone(),
50635118
token: token.clone(),
50645119
amount,
50655120
}];
50665121
let sources = vec![TxShieldedSource {
5067-
source,
5068-
token,
5122+
source: source.clone(),
5123+
token: token.clone(),
50695124
amount,
50705125
}];
50715126
let gas_spending_key = GAS_SPENDING_KEY.parse(matches);
50725127

5128+
#[cfg(any(test, feature = "testing"))]
5129+
let mut sources = sources;
5130+
#[cfg(any(test, feature = "testing"))]
5131+
let mut targets = targets;
5132+
#[cfg(any(test, feature = "testing"))]
5133+
if let Some(fee_target) = FRONTEND_SUS_FEE.parse(matches) {
5134+
// Take a constant fee of 1 on top of the input amount
5135+
targets.push(TxTransparentTarget {
5136+
target: fee_target,
5137+
token: token.clone(),
5138+
amount: InputAmount::Unvalidated(
5139+
token::DenominatedAmount::new(
5140+
1.into(),
5141+
raw_amount.denom(),
5142+
),
5143+
),
5144+
});
5145+
5146+
sources.push(TxShieldedSource {
5147+
source,
5148+
token,
5149+
amount: InputAmount::Unvalidated(
5150+
token::DenominatedAmount::new(
5151+
1.into(),
5152+
raw_amount.denom(),
5153+
),
5154+
),
5155+
})
5156+
};
5157+
50735158
Self {
50745159
tx,
50755160
sources,
5076-
targets: data,
5161+
targets,
50775162
gas_spending_key,
50785163
tx_code_path,
50795164
}
50805165
}
50815166

50825167
fn def(app: App) -> App {
5083-
app.add_args::<Tx<CliTypes>>()
5168+
let app = app
5169+
.add_args::<Tx<CliTypes>>()
50845170
.arg(
50855171
SPENDING_KEY_SOURCE
50865172
.def()
@@ -5101,7 +5187,15 @@ pub mod args {
51015187
"The optional spending key that will be used for gas \
51025188
payment. When not provided the source spending key will \
51035189
be used."
5104-
)))
5190+
)));
5191+
5192+
#[cfg(any(test, feature = "testing"))]
5193+
let app = app.arg(FRONTEND_SUS_FEE.def().help(wrap!(
5194+
"The optional address of the frontend provider that will take \
5195+
the masp sustainability fee."
5196+
)));
5197+
5198+
app
51055199
}
51065200
}
51075201

crates/sdk/src/tx.rs

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,6 +2827,7 @@ pub async fn build_ibc_transfer(
28272827
masp_fee_data
28282828
};
28292829

2830+
// FIXME: adjust this
28302831
if let Some(TxTransparentTarget {
28312832
target,
28322833
token,
@@ -3473,7 +3474,6 @@ async fn get_masp_fee_payment_amount<N: Namada>(
34733474
}
34743475

34753476
/// Build a shielding transfer
3476-
// FIXME: need to test the fee
34773477
pub async fn build_shielding_transfer<N: Namada>(
34783478
context: &N,
34793479
args: &mut args::TxShieldingTransfer,
@@ -3512,11 +3512,14 @@ pub async fn build_shielding_transfer<N: Namada>(
35123512

35133513
let mut transfer_data = MaspTransferData::default();
35143514
let mut data = token::Transfer::default();
3515-
for TxTransparentSource {
3516-
source,
3517-
token,
3518-
amount,
3519-
} in &args.sources
3515+
for (
3516+
id,
3517+
TxTransparentSource {
3518+
source,
3519+
token,
3520+
amount,
3521+
},
3522+
) in args.sources.iter().enumerate()
35203523
{
35213524
// Validate the amount given
35223525
let validated_amount =
@@ -3544,10 +3547,53 @@ pub async fn build_shielding_transfer<N: Namada>(
35443547
.await?;
35453548
}
35463549

3550+
// The frontend sustainability fee (when provided) must be paid by the
3551+
// first source
3552+
let masp_shield_amount = match (id, &args.frontend_sus_fee) {
3553+
(
3554+
0,
3555+
Some(TxTransparentTarget {
3556+
target: sus_fee_target,
3557+
token: sus_fee_token,
3558+
amount: sus_fee_amt,
3559+
}),
3560+
) => {
3561+
if sus_fee_token != token {
3562+
return Err(Error::Other(
3563+
"The sustainability fee token does not match the \
3564+
token of the first transaction's source"
3565+
.to_string(),
3566+
));
3567+
}
3568+
3569+
// Validate the amount given
3570+
let validated_fee_amount = validate_amount(
3571+
context,
3572+
sus_fee_amt.to_owned(),
3573+
sus_fee_token,
3574+
args.tx.force,
3575+
)
3576+
.await?;
3577+
3578+
data = data
3579+
.credit(
3580+
sus_fee_target.to_owned(),
3581+
sus_fee_token.to_owned(),
3582+
validated_fee_amount,
3583+
)
3584+
.ok_or(Error::Other(
3585+
"Combined transfer overflows".to_string(),
3586+
))?;
3587+
3588+
checked!(validated_amount - validated_fee_amount)?
3589+
}
3590+
_ => validated_amount,
3591+
};
3592+
35473593
transfer_data.sources.push((
35483594
TransferSource::Address(source.to_owned()),
35493595
token.to_owned(),
3550-
validated_amount,
3596+
masp_shield_amount,
35513597
));
35523598

35533599
data = data
@@ -3576,22 +3622,6 @@ pub async fn build_shielding_transfer<N: Namada>(
35763622
.ok_or(Error::Other("Combined transfer overflows".to_string()))?;
35773623
}
35783624

3579-
if let Some(TxTransparentTarget {
3580-
target,
3581-
token,
3582-
amount,
3583-
}) = &args.frontend_sus_fee
3584-
{
3585-
// Validate the amount given
3586-
let validated_amount =
3587-
validate_amount(context, amount.to_owned(), token, args.tx.force)
3588-
.await?;
3589-
3590-
data = data
3591-
.credit(target.to_owned(), token.to_owned(), validated_amount)
3592-
.ok_or(Error::Other("Combined transfer overflows".to_string()))?;
3593-
}
3594-
35953625
let shielded_parts = construct_shielded_parts(
35963626
context,
35973627
transfer_data,
@@ -4217,6 +4247,7 @@ pub async fn gen_ibc_shielding_transfer<N: Namada>(
42174247
.precompute_asset_types(context.client(), tokens)
42184248
.await;
42194249

4250+
// FIXME: need to adjust this
42204251
let extra_target = match &args.frontend_sus_fee {
42214252
Some(TxTransparentTarget {
42224253
target,

0 commit comments

Comments
 (0)