From 34cedcad9e05104a7aaecfd908203e7e5e127056 Mon Sep 17 00:00:00 2001 From: Mohit Yadav Date: Fri, 15 May 2026 16:23:01 +0530 Subject: [PATCH 1/3] fix: update is_approved in _add_token_transfer accumulation branch Signed-off-by: Mohit Yadav --- .../abstract_token_transfer_transaction.py | 1 + tests/unit/transfer_transaction_test.py | 54 ++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py index a423b51d3..4a7a312af 100644 --- a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py +++ b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py @@ -155,6 +155,7 @@ def _add_token_transfer( if transfer.account_id == account_id: transfer.amount += amount transfer.expected_decimals = expected_decimals + transfer.is_approved = is_approved return self.token_transfers[token_id].append( diff --git a/tests/unit/transfer_transaction_test.py b/tests/unit/transfer_transaction_test.py index 5e9a7cc31..4b9f2b60e 100644 --- a/tests/unit/transfer_transaction_test.py +++ b/tests/unit/transfer_transaction_test.py @@ -465,7 +465,7 @@ def test_approved_token_transfer_accumulation(mock_account_ids): transfer_1 = transfer_tx.token_transfers[token_id_1][0] transfer_2 = transfer_tx.token_transfers[token_id_1][1] assert transfer_1.amount == 500 - assert transfer_1.is_approved is False + assert transfer_1.is_approved is True assert transfer_1.expected_decimals is None assert transfer_2.amount == 300 assert transfer_2.is_approved is False @@ -485,6 +485,58 @@ def test_approved_token_transfer_accumulation(mock_account_ids): assert transfer_2.expected_decimals is None # unchanged +def test_is_approved_updated_normal_then_approved(mock_account_ids): + """is_approved becomes True when an approved call follows a normal one (last-call-wins).""" + account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids + transfer_tx = TransferTransaction() + + transfer_tx.add_token_transfer(token_id_1, account_id_1, 500) + transfer_tx.add_token_transfer(token_id_1, account_id_2, -500) + + transfer_1 = transfer_tx.token_transfers[token_id_1][0] + assert transfer_1.is_approved is False + + transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 200) + transfer_tx.add_token_transfer(token_id_1, account_id_2, -200) + + transfer_1 = transfer_tx.token_transfers[token_id_1][0] + assert transfer_1.amount == 700 + assert transfer_1.is_approved is True + + +def test_is_approved_updated_approved_then_normal(mock_account_ids): + """is_approved becomes False when a normal call follows an approved one (last-call-wins).""" + account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids + transfer_tx = TransferTransaction() + + transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 500) + transfer_tx.add_token_transfer(token_id_1, account_id_2, -500) + + transfer_1 = transfer_tx.token_transfers[token_id_1][0] + assert transfer_1.is_approved is True + + transfer_tx.add_token_transfer(token_id_1, account_id_1, 200) + transfer_tx.add_token_transfer(token_id_1, account_id_2, -200) + + transfer_1 = transfer_tx.token_transfers[token_id_1][0] + assert transfer_1.amount == 700 + assert transfer_1.is_approved is False + + +def test_add_approved_token_transfer_no_decimals(mock_account_ids): + """add_approved_token_transfer (non-decimal variant) sets is_approved=True.""" + account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids + transfer_tx = TransferTransaction() + + transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, -1000) + transfer_tx.add_token_transfer(token_id_1, account_id_2, 1000) + + transfer = transfer_tx.token_transfers[token_id_1][0] + assert transfer.amount == -1000 + assert transfer.is_approved is True + assert transfer.expected_decimals is None + + def test_approved_token_transfer_validation(mock_account_ids): """Test validation for approved token transfers with decimals.""" account_id_1, _, _, token_id_1, _ = mock_account_ids From 98b2ca3e5bdea626bd95b9198b5999c5a55b79fc Mon Sep 17 00:00:00 2001 From: Mohit Yadav Date: Fri, 15 May 2026 23:13:50 +0530 Subject: [PATCH 2/3] fix: accumulate only when account_id and is_approved both match Fixes #2253 Signed-off-by: Mohit Yadav --- .../abstract_token_transfer_transaction.py | 4 +- tests/unit/transfer_transaction_test.py | 68 ++++++++++--------- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py index 4a7a312af..42f34b34c 100644 --- a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py +++ b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py @@ -155,7 +155,9 @@ def _add_token_transfer( if transfer.account_id == account_id: transfer.amount += amount transfer.expected_decimals = expected_decimals - transfer.is_approved = is_approved + if transfer.account_id == account_id and transfer.is_approved == is_approved: + transfer.amount += amount + transfer.expected_decimals = expected_decimals return self.token_transfers[token_id].append( diff --git a/tests/unit/transfer_transaction_test.py b/tests/unit/transfer_transaction_test.py index 4b9f2b60e..6a2f349ae 100644 --- a/tests/unit/transfer_transaction_test.py +++ b/tests/unit/transfer_transaction_test.py @@ -453,7 +453,7 @@ def test_approved_token_transfer_with_decimals(mock_account_ids): def test_approved_token_transfer_accumulation(mock_account_ids): - """Test that approved token transfers accumulate for the same account.""" + """Test that approved token transfers are stored as separate entries from normal ones.""" account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids transfer_tx = TransferTransaction() @@ -465,62 +465,68 @@ def test_approved_token_transfer_accumulation(mock_account_ids): transfer_1 = transfer_tx.token_transfers[token_id_1][0] transfer_2 = transfer_tx.token_transfers[token_id_1][1] assert transfer_1.amount == 500 - assert transfer_1.is_approved is True + assert transfer_1.is_approved is False assert transfer_1.expected_decimals is None assert transfer_2.amount == 300 assert transfer_2.is_approved is False assert transfer_2.expected_decimals is None - # Add approved transfer with decimals for account_1 (accumulates) + # Add approved transfer with decimals for account_1 (separate entry, not merged) transfer_tx.add_approved_token_transfer_with_decimals(token_id_1, account_id_1, 200, 8) - # Verify accumulation - transfer_1 = transfer_tx.token_transfers[token_id_1][0] - transfer_2 = transfer_tx.token_transfers[token_id_1][1] - assert transfer_1.amount == 700 # 500 + 200 - assert transfer_1.is_approved is False # unchanged - assert transfer_1.expected_decimals == 8 # updated from the accumulation - assert transfer_2.amount == 300 # unchanged - assert transfer_2.is_approved is False # unchanged - assert transfer_2.expected_decimals is None # unchanged + # Verify stored as separate entries + transfers = transfer_tx.token_transfers[token_id_1] + assert len(transfers) == 3 # account_1 normal, account_2 normal, account_1 approved + + assert transfers[0].amount == 500 # unchanged + assert transfers[0].is_approved is False # unchanged + assert transfers[1].amount == 300 # unchanged + assert transfers[1].is_approved is False # unchanged + assert transfers[2].amount == 200 + assert transfers[2].is_approved is True + assert transfers[2].expected_decimals == 8 -def test_is_approved_updated_normal_then_approved(mock_account_ids): - """is_approved becomes True when an approved call follows a normal one (last-call-wins).""" +def test_normal_and_approved_transfers_kept_separate(mock_account_ids): + """Normal and approved transfers for the same account are stored as separate entries.""" account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids transfer_tx = TransferTransaction() transfer_tx.add_token_transfer(token_id_1, account_id_1, 500) transfer_tx.add_token_transfer(token_id_1, account_id_2, -500) - - transfer_1 = transfer_tx.token_transfers[token_id_1][0] - assert transfer_1.is_approved is False - transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 200) transfer_tx.add_token_transfer(token_id_1, account_id_2, -200) - transfer_1 = transfer_tx.token_transfers[token_id_1][0] - assert transfer_1.amount == 700 - assert transfer_1.is_approved is True + transfers = transfer_tx.token_transfers[token_id_1] + assert len(transfers) == 3 # account_1 normal, account_2 accumulated, account_1 approved + assert transfers[0].amount == 500 + assert transfers[0].is_approved is False -def test_is_approved_updated_approved_then_normal(mock_account_ids): - """is_approved becomes False when a normal call follows an approved one (last-call-wins).""" + assert transfers[1].amount == -700 # -500 + -200 accumulated + assert transfers[1].is_approved is False + + assert transfers[2].amount == 200 + assert transfers[2].is_approved is True + + +def test_same_approved_transfers_accumulate(mock_account_ids): + """Two approved transfers for the same account DO accumulate.""" account_id_1, account_id_2, _, token_id_1, _ = mock_account_ids transfer_tx = TransferTransaction() - transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 500) + transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 300) + transfer_tx.add_approved_token_transfer(token_id_1, account_id_1, 200) transfer_tx.add_token_transfer(token_id_1, account_id_2, -500) - transfer_1 = transfer_tx.token_transfers[token_id_1][0] - assert transfer_1.is_approved is True + transfers = transfer_tx.token_transfers[token_id_1] + assert len(transfers) == 2 # account_1 approved (merged), account_2 normal - transfer_tx.add_token_transfer(token_id_1, account_id_1, 200) - transfer_tx.add_token_transfer(token_id_1, account_id_2, -200) + assert transfers[0].amount == 500 # 300 + 200 accumulated + assert transfers[0].is_approved is True - transfer_1 = transfer_tx.token_transfers[token_id_1][0] - assert transfer_1.amount == 700 - assert transfer_1.is_approved is False + assert transfers[1].amount == -500 + assert transfers[1].is_approved is False def test_add_approved_token_transfer_no_decimals(mock_account_ids): From e6bc36d36edcfbc2b95d8ed182c99f870c734c68 Mon Sep 17 00:00:00 2001 From: Mohit Yadav Date: Tue, 19 May 2026 14:52:59 +0530 Subject: [PATCH 3/3] Update abstract_token_transfer_transaction.py Signed-off-by: Mohit Yadav --- .../tokens/abstract_token_transfer_transaction.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py index 42f34b34c..0dae53618 100644 --- a/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py +++ b/src/hiero_sdk_python/tokens/abstract_token_transfer_transaction.py @@ -152,9 +152,6 @@ def _add_token_transfer( raise TypeError("is_approved must be a boolean.") for transfer in self.token_transfers[token_id]: - if transfer.account_id == account_id: - transfer.amount += amount - transfer.expected_decimals = expected_decimals if transfer.account_id == account_id and transfer.is_approved == is_approved: transfer.amount += amount transfer.expected_decimals = expected_decimals