Skip to content

Commit 1f05f77

Browse files
committed
Account for masp digits in masp change
1 parent dc7220d commit 1f05f77

1 file changed

Lines changed: 52 additions & 24 deletions

File tree

crates/shielded_token/src/masp/shielded_wallet.rs

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,10 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
651651
async fn is_amount_required(
652652
&mut self,
653653
client: &(impl Client + Sync),
654-
src: ValueSum<Address, Change>,
655-
dest: ValueSum<Address, Change>,
654+
src: ValueSum<(MaspDigitPos, Address), Change>,
655+
dest: ValueSum<(MaspDigitPos, Address), Change>,
656656
delta: I128Sum,
657-
) -> Option<ValueSum<Address, Change>> {
657+
) -> Option<ValueSum<(MaspDigitPos, Address), Change>> {
658658
// If the delta causes any regression, then do not use it
659659
#[allow(clippy::neg_cmp_op_on_partial_ord)]
660660
if !(delta >= I128Sum::zero()) {
@@ -664,17 +664,18 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
664664
let (decoded_delta, _rem_delta) = self.decode_sum(client, delta).await;
665665
for ((_, asset_data), value) in decoded_delta.components() {
666666
// Check that this component of the delta helps close the gap
667-
if *value > 0 && gap.get(&asset_data.token).is_positive() {
667+
if *value > 0
668+
&& gap
669+
.get(&(asset_data.position, asset_data.token.clone()))
670+
.is_positive()
671+
{
668672
// Convert the delta into Namada amounts
669673
let mut converted_delta = ValueSum::zero();
670674
for ((_, asset_data), value) in decoded_delta.components() {
671-
let amt = Change::from_masp_denominated(
672-
*value,
673-
asset_data.position,
674-
)
675-
.ok()?;
676-
converted_delta +=
677-
ValueSum::from_pair(asset_data.token.clone(), amt);
675+
converted_delta += ValueSum::from_pair(
676+
(asset_data.position, asset_data.token.clone()),
677+
Change::from(*value),
678+
);
678679
}
679680
return Some(converted_delta);
680681
}
@@ -693,7 +694,7 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
693694
context: &impl NamadaIo,
694695
spent_notes: &mut SpentNotesTracker,
695696
sk: namada_core::masp::ExtendedSpendingKey,
696-
target: ValueSum<Address, Change>,
697+
target: ValueSum<(MaspDigitPos, Address), Change>,
697698
target_epoch: MaspEpoch,
698699
) -> Result<
699700
(
@@ -1206,27 +1207,31 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
12061207
&mut self,
12071208
client: &(impl Client + Sync),
12081209
added_amt: I128Sum,
1209-
mut required_amt: ValueSum<Address, Change>,
1210+
mut required_amt: ValueSum<(MaspDigitPos, Address), Change>,
12101211
) -> Result<I128Sum, TransferErr> {
12111212
// Compute the amount of change due to the sender.
12121213
let (decoded_amount, mut change) =
12131214
self.decode_sum(client, added_amt.clone()).await;
12141215
for ((asset_type, asset_data), value) in decoded_amount.components() {
12151216
// Get current component of the required amount
1216-
let req = asset_data
1217-
.position
1218-
.denominate(&Amount::from(required_amt.get(&asset_data.token)));
1217+
let req = required_amt
1218+
.get(&(asset_data.position, asset_data.token.clone()));
12191219
// Compute how much this decoded component covers of the requirement
1220-
let covered = std::cmp::min(i128::from(req), *value);
1220+
let covered = std::cmp::min(
1221+
i128::try_from(req).expect("Masp digit value overflow"),
1222+
*value,
1223+
);
12211224
// Record how far in excess of the requirement we are. This is
12221225
// change.
12231226
change += ValueSum::from_pair(*asset_type, value - covered);
12241227
// Denominate the cover and decrease the required amount accordingly
12251228
let covered =
12261229
Change::from_masp_denominated(covered, asset_data.position)
12271230
.map_err(|e| TransferErr::General(e.to_string()))?;
1228-
required_amt -=
1229-
ValueSum::from_pair(asset_data.token.clone(), covered);
1231+
required_amt -= ValueSum::from_pair(
1232+
(asset_data.position, asset_data.token.clone()),
1233+
covered,
1234+
);
12301235
}
12311236
// Error out if the required amount was not covered by the added amount
12321237
if !required_amt.is_zero() {
@@ -1279,11 +1284,34 @@ pub trait ShieldedApi<U: ShieldedUtils + MaybeSend + MaybeSync>:
12791284

12801285
// If there are shielded inputs
12811286
let added_amt = if let Some(sk) = spending_key {
1282-
// Make the target amount vectorial
1283-
let required_amt = ValueSum::<Address, Change>::from_pair(
1284-
token.clone(),
1285-
(*amount).into(),
1286-
);
1287+
// Compute the target amount to spend from the
1288+
// input token address and namada amount. We
1289+
// collect all words from the namada amount
1290+
// whose values are non-zero, and pair them
1291+
// with their corresponding masp digit position.
1292+
let required_amt = amount
1293+
.iter_words()
1294+
.enumerate()
1295+
.filter_map(|(masp_digit_pos, value)| {
1296+
if value != 0 {
1297+
Some((
1298+
MaspDigitPos::from(masp_digit_pos),
1299+
Change::from(value),
1300+
))
1301+
} else {
1302+
None
1303+
}
1304+
})
1305+
.fold(
1306+
ValueSum::zero(),
1307+
|mut accum, (masp_digit_pos, value)| {
1308+
accum += ValueSum::from_pair(
1309+
(masp_digit_pos, token.clone()),
1310+
value,
1311+
);
1312+
accum
1313+
},
1314+
);
12871315
// Locate unspent notes that can help us meet the transaction
12881316
// amount
12891317
let (added_amt, unspent_notes, used_convs) = self

0 commit comments

Comments
 (0)