Skip to content

Commit ba73b10

Browse files
xxAVOGADROxxnielstroncffls
authored
Fixed transaction imbalance when burning assets from the same policy (#376)
* Fixed tx imbalance when burning multiple tokens * Added cases and format * Added unit test * Correct unit test * Removed redundant filtering zero-quantity asset * Improved name function (unit test) * Improved unit test * Fix __iadd__ in assets --------- Co-authored-by: Niels <niels.muendler@inf.ethz.ch> Co-authored-by: Jerry <jerrycgh@gmail.com>
1 parent 46c453d commit ba73b10

File tree

3 files changed

+39
-39
lines changed

3 files changed

+39
-39
lines changed

pycardano/transaction.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def __add__(self, other: Asset) -> Asset:
107107

108108
def __iadd__(self, other: Asset) -> Asset:
109109
new_item = self + other
110-
self.update(new_item)
110+
self.data = new_item.data
111111
return self.normalize()
112112

113113
def __sub__(self, other: Asset) -> Asset:
@@ -173,7 +173,7 @@ def __add__(self, other):
173173

174174
def __iadd__(self, other):
175175
new_item = self + other
176-
self.update(new_item)
176+
self.data = new_item.data
177177
return self.normalize()
178178

179179
def __sub__(self, other: MultiAsset) -> MultiAsset:

pycardano/txbuilder.py

+2
Original file line numberDiff line numberDiff line change
@@ -556,8 +556,10 @@ def _calc_change(
556556
provided = Value()
557557
for i in inputs:
558558
provided += i.output.amount
559+
559560
if self.mint:
560561
provided.multi_asset += self.mint
562+
561563
if self.withdrawals:
562564
for v in self.withdrawals.values():
563565
provided.coin += v

test/pycardano/test_txbuilder.py

+35-37
Original file line numberDiff line numberDiff line change
@@ -1943,28 +1943,23 @@ def test_transaction_witness_set_no_redeemers(chain_context):
19431943
assert witness_set.redeemer is None
19441944

19451945

1946-
def test_minting_and_burning_zero_quantity_assets(chain_context):
1946+
def test_burning_all_assets_under_single_policy(chain_context):
19471947
"""
1948-
Test the minting and burning of multiple assets using the TransactionBuilder.
1948+
Test burning all assets under a single policy with TransactionBuilder.
19491949
1950-
This test ensures that assets are correctly minted and burned under the same policy ID.
1951-
Specifically, it verifies that after burning certain assets (AssetName1, AssetName2, and AssetName3),
1952-
they are removed from the multi-asset map, and the correct amount of the minted asset (AssetName4) remains.
1950+
This test ensures that burning multiple assets (AssetName1, AssetName2, AssetName3, AssetName4)
1951+
under policy_id_1 removes them from the multi-asset map.
19531952
19541953
Steps:
1955-
1. Define a policy ID and several assets (AssetName1, AssetName2, AssetName3, and AssetName4) using the AssetName class.
1956-
2. Simulate minting of 2 units of AssetName4 and burning 1 unit each of AssetName1, AssetName2, and AssetName3.
1957-
3. Add corresponding UTXOs for each asset as inputs.
1958-
4. Add minting instructions to the TransactionBuilder.
1959-
5. Build the transaction and verify that the burnt assets are removed from the multi-asset map.
1960-
6. Check that the correct quantity of AssetName4 is minted and included in the transaction outputs.
1954+
1. Define assets under policy_id_1 and simulate burning 1 unit of each.
1955+
2. Add UTXOs for the assets and burning instructions.
1956+
3. Build the transaction and verify that all burned assets are removed.
19611957
19621958
Args:
1963-
chain_context: The blockchain context used for constructing and verifying the transaction.
1959+
chain_context: The blockchain context.
19641960
19651961
Assertions:
1966-
- AssetName1, AssetName2, and AssetName3 are not present in the multi-asset map after burning.
1967-
- AssetName4 has exactly 2 units minted.
1962+
- AssetName1, AssetName2, AssetName3, and AssetName4 are removed after burning.
19681963
"""
19691964
tx_builder = TransactionBuilder(chain_context)
19701965

@@ -1986,43 +1981,48 @@ def test_minting_and_burning_zero_quantity_assets(chain_context):
19861981
["d6cbe6cadecd3f89b60e08e68e5e6c7d72d730aaa1ad21431590f7e6643438ef", 3]
19871982
)
19881983
# Define a policy ID and asset names
1989-
policy_id = plutus_script_hash(PlutusV1Script(b"dummy script"))
1990-
multi_asset1 = MultiAsset.from_primitive({policy_id.payload: {b"AssetName1": 1}})
1991-
multi_asset2 = MultiAsset.from_primitive({policy_id.payload: {b"AssetName2": 2}})
1992-
multi_asset3 = MultiAsset.from_primitive({policy_id.payload: {b"AssetName3": 1}})
1993-
multi_asset4 = MultiAsset.from_primitive({policy_id.payload: {b"AssetName4": 3}})
1984+
policy_id_1 = plutus_script_hash(PlutusV1Script(b"dummy script1"))
1985+
multi_asset1 = MultiAsset.from_primitive({policy_id_1.payload: {b"AssetName1": 1}})
1986+
multi_asset2 = MultiAsset.from_primitive({policy_id_1.payload: {b"AssetName2": 1}})
1987+
multi_asset3 = MultiAsset.from_primitive(
1988+
{
1989+
policy_id_1.payload: {b"AssetName3": 1},
1990+
}
1991+
)
1992+
multi_asset4 = MultiAsset.from_primitive(
1993+
{
1994+
policy_id_1.payload: {b"AssetName4": 1},
1995+
}
1996+
)
19941997

19951998
# Simulate minting and burning of assets
19961999
mint = MultiAsset.from_primitive(
19972000
{
1998-
policy_id.payload: {
2001+
policy_id_1.payload: {
19992002
b"AssetName1": -1,
2000-
b"AssetName2": -2,
2003+
b"AssetName2": -1,
20012004
b"AssetName3": -1,
2002-
b"AssetName4": 2,
2005+
b"AssetName4": -1,
20032006
}
20042007
}
20052008
)
20062009

20072010
# Set UTXO for the inputs
20082011
utxo1 = UTxO(
2009-
tx_in1, TransactionOutput(Address(policy_id), Value(10000000, multi_asset1))
2012+
tx_in1, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset1))
20102013
)
20112014
utxo2 = UTxO(
2012-
tx_in2, TransactionOutput(Address(policy_id), Value(10000000, multi_asset2))
2015+
tx_in2, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset2))
20132016
)
20142017
utxo3 = UTxO(
2015-
tx_in3, TransactionOutput(Address(policy_id), Value(10000000, multi_asset3))
2018+
tx_in3, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset3))
20162019
)
20172020
utxo4 = UTxO(
2018-
tx_in4, TransactionOutput(Address(policy_id), Value(10000000, multi_asset4))
2021+
tx_in4, TransactionOutput(Address(policy_id_1), Value(10000000, multi_asset4))
20192022
)
20202023

20212024
# Add UTXO inputs
2022-
tx_builder.add_input(utxo1)
2023-
tx_builder.add_input(utxo2)
2024-
tx_builder.add_input(utxo3)
2025-
tx_builder.add_input(utxo4)
2025+
tx_builder.add_input(utxo1).add_input(utxo2).add_input(utxo3).add_input(utxo4)
20262026

20272027
# Add the minting to the builder
20282028
tx_builder.mint = mint
@@ -2037,10 +2037,8 @@ def test_minting_and_burning_zero_quantity_assets(chain_context):
20372037
for output in tx.outputs:
20382038
multi_asset = output.amount.multi_asset
20392039

2040-
# Ensure that AssetName1, Node2, and Node3 were burnt (removed)
2041-
assert AssetName(b"AssetName1") not in multi_asset.get(policy_id, {})
2042-
assert AssetName(b"AssetName2") not in multi_asset.get(policy_id, {})
2043-
assert AssetName(b"AssetName3") not in multi_asset.get(policy_id, {})
2044-
2045-
# Ensure that AssetName4 has 5 units after minting
2046-
assert multi_asset.get(policy_id, {}).get(AssetName(b"AssetName4"), 0) == 5
2040+
# Ensure that AssetName1, AssetName2, AssetName3 and AssetName4 were burnt (removed)
2041+
assert AssetName(b"AssetName1") not in multi_asset.get(policy_id_1, {})
2042+
assert AssetName(b"AssetName2") not in multi_asset.get(policy_id_1, {})
2043+
assert AssetName(b"AssetName3") not in multi_asset.get(policy_id_1, {})
2044+
assert AssetName(b"AseetName4") not in multi_asset.get(policy_id_1, {})

0 commit comments

Comments
 (0)