From 9a99258312e2227240c528573a1dc1589253f362 Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Tue, 20 Aug 2024 13:05:15 +0200 Subject: [PATCH 1/2] token: fix transfer to self --- crates/trans_token/src/storage.rs | 135 +++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/crates/trans_token/src/storage.rs b/crates/trans_token/src/storage.rs index b4f6d67893..940eb3a1c5 100644 --- a/crates/trans_token/src/storage.rs +++ b/crates/trans_token/src/storage.rs @@ -237,9 +237,10 @@ pub fn transfer( where S: StorageRead + StorageWrite, { - if amount.is_zero() { + if amount.is_zero() || src == dest { return Ok(()); } + let src_key = balance_key(token, src); let src_balance = read_balance(storage, token, src)?; match src_balance.checked_sub(amount) { @@ -279,6 +280,7 @@ where let mut accounts = BTreeSet::new(); accounts.extend(sources.keys().cloned()); accounts.extend(dests.keys().cloned()); + let unexpected_err = || { storage::Error::new_const( "Computing difference between amounts should never overflow", @@ -424,10 +426,139 @@ pub fn denom_to_amount( #[cfg(test)] mod testing { + use std::collections::BTreeMap; + use namada_core::{address, token}; use namada_storage::testing::TestStorage; - use super::{burn_tokens, credit_tokens, read_balance, read_total_supply}; + use super::{ + burn_tokens, credit_tokens, multi_transfer, read_balance, + read_total_supply, transfer, + }; + + #[test] + fn test_multi_transfer() { + let mut storage = TestStorage::default(); + let native_token = address::testing::nam(); + + // Get one account + let addr = address::testing::gen_implicit_address(); + + // Credit the account some balance + let pre_balance = token::Amount::native_whole(1); + credit_tokens(&mut storage, &native_token, &addr, pre_balance).unwrap(); + + let pre_balance_check = + read_balance(&storage, &native_token, &addr).unwrap(); + + assert_eq!(pre_balance_check, pre_balance); + + // sources + let sources = BTreeMap::from_iter([( + (addr.clone(), native_token.clone()), + pre_balance, + )]); + + // targets + let targets = BTreeMap::from_iter([( + (addr.clone(), native_token.clone()), + pre_balance, + )]); + + multi_transfer(&mut storage, &sources, &targets).unwrap(); + + let post_balance_check = + read_balance(&storage, &native_token, &addr).unwrap(); + + assert_eq!(post_balance_check, pre_balance); + } + + #[test] + fn test_credit() { + let mut storage = TestStorage::default(); + let native_token = address::testing::nam(); + + // Get one account + let addr = address::testing::gen_implicit_address(); + + // Credit the account some balance + let pre_balance = token::Amount::native_whole(1); + credit_tokens(&mut storage, &native_token, &addr, pre_balance).unwrap(); + + let total_supply_post = + read_total_supply(&storage, &native_token).unwrap(); + + assert_eq!(total_supply_post, pre_balance); + + let post_balance = + read_balance(&storage, &native_token, &addr).unwrap(); + + assert_eq!(post_balance, pre_balance); + } + + #[test] + fn test_transfer_to_self_is_no_op() { + let mut storage = TestStorage::default(); + let native_token = address::testing::nam(); + + // Get one account + let addr = address::testing::gen_implicit_address(); + + // Credit the account some balance + let pre_balance = token::Amount::native_whole(1); + credit_tokens(&mut storage, &native_token, &addr, pre_balance).unwrap(); + + let total_supply_pre = + read_total_supply(&storage, &native_token).unwrap(); + + let transfer_result = + transfer(&mut storage, &native_token, &addr, &addr, pre_balance); + assert!(transfer_result.is_ok()); + + let total_supply_post = + read_total_supply(&storage, &native_token).unwrap(); + + assert_eq!(total_supply_post, total_supply_pre); + + let post_balance = + read_balance(&storage, &native_token, &addr).unwrap(); + + assert_eq!(post_balance, pre_balance); + } + + #[test] + fn test_transfer() { + let mut storage = TestStorage::default(); + let native_token = address::testing::nam(); + + // Get one account + let source = address::testing::gen_implicit_address(); + let target = address::testing::gen_implicit_address(); + + // Credit the account some balance + let pre_balance = token::Amount::native_whole(1); + credit_tokens(&mut storage, &native_token, &source, pre_balance) + .unwrap(); + + let total_supply_pre = + read_total_supply(&storage, &native_token).unwrap(); + + transfer(&mut storage, &native_token, &source, &target, pre_balance) + .unwrap(); + + let total_supply_post = + read_total_supply(&storage, &native_token).unwrap(); + + assert_eq!(total_supply_post, total_supply_pre); + + let post_balance_target = + read_balance(&storage, &native_token, &target).unwrap(); + let post_balance_source = + read_balance(&storage, &native_token, &source).unwrap(); + + assert_eq!(post_balance_target, pre_balance); + assert_eq!(post_balance_source, token::Amount::native_whole(0)); + } #[test] fn test_burn_native_tokens() { From f5268cda1cab7cfc1d7670d8b4034f8c81b8ef1c Mon Sep 17 00:00:00 2001 From: Gianmarco Fraccaroli Date: Tue, 20 Aug 2024 15:19:43 +0200 Subject: [PATCH 2/2] added changelog --- .../bug-fixes/3675-improve-init-proposal-validation.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/bug-fixes/3675-improve-init-proposal-validation.md diff --git a/.changelog/unreleased/bug-fixes/3675-improve-init-proposal-validation.md b/.changelog/unreleased/bug-fixes/3675-improve-init-proposal-validation.md new file mode 100644 index 0000000000..b23f977158 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/3675-improve-init-proposal-validation.md @@ -0,0 +1,2 @@ +- Make transfers with same source and destion a no-op. + ([\#3675](https://github.com/anoma/namada/pull/3675)) \ No newline at end of file