From e1e323560a43db5a3830f18a5e4ccb35a80b7fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:05:32 +0100 Subject: [PATCH 01/15] Add functions to automatically add required signers and validity range --- pycardano/txbuilder.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 0ebd7ff9..758e129f 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -869,6 +869,8 @@ def build( change_address: Optional[Address] = None, merge_change: Optional[bool] = False, collateral_change_address: Optional[Address] = None, + auto_validity = True, + auto_required_signers=True, ) -> TransactionBody: """Build a transaction body from all constraints set through the builder. @@ -878,11 +880,27 @@ def build( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. + auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a reasonable value + auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs to required signatories Returns: TransactionBody: A transaction body. """ self._ensure_no_input_exclusion_conflict() + + if auto_validity: + # Automatically set the validity range to a tight value around transaction creation + last_slot = self.context.last_block_slot + if self.validity_start is None: + self.validity_start = last_slot - 1000 + if self.ttl is None: + self.ttl = last_slot + 10000 + + if auto_required_signers: + # collect all signatories from explicitly defined transaction inputs and collateral inputs + required_signers = set(i.output.address.payment_part for i in self.inputs + self.collaterals) + self.required_signers = required_signers + selected_utxos = [] selected_amount = Value() for i in self.inputs: From 70167cd7185d2cf86dc747644c14522569190b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:09:16 +0100 Subject: [PATCH 02/15] Filter out signatures of script hashes --- pycardano/txbuilder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 758e129f..3cbe366f 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -898,8 +898,8 @@ def build( if auto_required_signers: # collect all signatories from explicitly defined transaction inputs and collateral inputs - required_signers = set(i.output.address.payment_part for i in self.inputs + self.collaterals) - self.required_signers = required_signers + required_signers = set(i.output.address.payment_part for i in self.inputs + self.collaterals if not isinstance(i.output.address.payment_part, ScriptHash)) + self.required_signers = list(required_signers) selected_utxos = [] selected_amount = Value() From 832b211454aa026b573c215b4c89906ba9edeb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:13:50 +0100 Subject: [PATCH 03/15] Fix implementation of last slot no in fixed chain context --- test/pycardano/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/pycardano/util.py b/test/pycardano/util.py index 24de8053..a691415c 100644 --- a/test/pycardano/util.py +++ b/test/pycardano/util.py @@ -90,7 +90,7 @@ def epoch(self) -> int: return 300 @property - def slot(self) -> int: + def last_block_slot(self) -> int: """Current slot number""" return 2000 From 9d6b3619000d97602169d6841ad92c611e58254c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:26:23 +0100 Subject: [PATCH 04/15] Adjust test cases --- pycardano/txbuilder.py | 10 ++++++-- test/pycardano/test_txbuilder.py | 40 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 3cbe366f..d3c93dad 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -869,8 +869,8 @@ def build( change_address: Optional[Address] = None, merge_change: Optional[bool] = False, collateral_change_address: Optional[Address] = None, - auto_validity = True, - auto_required_signers=True, + auto_validity: Optional[bool] = True, + auto_required_signers: Optional[bool] = True, ) -> TransactionBody: """Build a transaction body from all constraints set through the builder. @@ -1183,6 +1183,8 @@ def build_and_sign( change_address: Optional[Address] = None, merge_change: Optional[bool] = False, collateral_change_address: Optional[Address] = None, + auto_validity: Optional[bool] = True, + auto_required_signers: Optional[bool] = True, ) -> Transaction: """Build a transaction body from all constraints set through the builder and sign the transaction with provided signing keys. @@ -1195,6 +1197,8 @@ def build_and_sign( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. + auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a reasonable value + auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs to required signatories Returns: Transaction: A signed transaction. @@ -1204,6 +1208,8 @@ def build_and_sign( change_address=change_address, merge_change=merge_change, collateral_change_address=collateral_change_address, + auto_validity=auto_validity, + auto_required_signers=auto_required_signers, ) witness_set = self.build_witness_set() witness_set.vkey_witnesses = [] diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index 0d2957a5..9e712f5d 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -59,7 +59,7 @@ def test_tx_builder(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -100,7 +100,7 @@ def test_tx_builder_with_certain_input(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -136,7 +136,7 @@ def test_tx_builder_multi_asset(chain_context): ) ) - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [ @@ -178,7 +178,7 @@ def test_tx_builder_raises_utxo_selection(chain_context): ) with pytest.raises(UTxOSelectionException) as e: - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) # The unfulfilled amount includes requested (991000000) and estimated fees (161277) assert "Unfulfilled amount:\n {\n 'coin': 991161277" in e.value.args[0] @@ -214,7 +214,7 @@ def test_tx_small_utxo_precise_fee(chain_context): # This will not fail as we replace max fee constraint with more precise fee calculation # And remainder is greater than minimum ada required for change - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expect = { 0: [ @@ -266,7 +266,7 @@ def test_tx_small_utxo_balance_pass(chain_context): # Balance is smaller than minimum ada required in change # Additional UTxOs are selected from the input address - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [ @@ -312,7 +312,7 @@ def test_tx_builder_mint_multi_asset(chain_context): tx_builder.native_scripts = [script] tx_builder.ttl = 123456789 - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [ @@ -354,7 +354,7 @@ def test_tx_add_change_split_nfts(chain_context): TransactionOutput.from_primitive([sender, 7000000]) ) - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [ @@ -786,7 +786,7 @@ def test_excluded_input(chain_context): tx_builder.excluded_inputs.append(chain_context.utxos(sender)[0]) - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -819,7 +819,7 @@ def test_build_and_sign(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder1.build(change_address=sender_address) + tx_body = tx_builder1.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) tx_builder2 = TransactionBuilder( chain_context, [RandomImproveMultiAsset([0, 0, 0, 0, 0])] @@ -827,7 +827,7 @@ def test_build_and_sign(chain_context): tx_builder2.add_input_address(sender).add_output( TransactionOutput.from_primitive([sender, 500000]) ) - tx = tx_builder2.build_and_sign([SK], change_address=sender_address) + tx = tx_builder2.build_and_sign([SK], change_address=sender_address, auto_validity=False, auto_required_signers=False) assert tx.transaction_witness_set.vkey_witnesses == [ VerificationKeyWitness(SK.to_verification_key(), SK.sign(tx_body.hash())) @@ -883,7 +883,7 @@ def test_tx_builder_exact_fee_no_change(chain_context): tx_builder.add_output(TransactionOutput.from_primitive([sender, 5000000])) - tx_body = tx_builder.build() + tx_body = tx_builder.build(auto_validity=False, auto_required_signers=False) tx_builder = TransactionBuilder(chain_context) @@ -897,7 +897,7 @@ def test_tx_builder_exact_fee_no_change(chain_context): TransactionOutput.from_primitive([sender, input_amount - tx_body.fee]) ) - tx = tx_builder.build_and_sign([SK]) + tx = tx_builder.build_and_sign([SK], auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -933,7 +933,7 @@ def test_tx_builder_certificates(chain_context): tx_builder.certificates = [stake_registration, stake_delegation] - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -970,7 +970,7 @@ def test_tx_builder_withdrawal(chain_context): withdrawals = Withdrawals({bytes(stake_address): 10000}) tx_builder.withdrawals = withdrawals - tx_body = tx_builder.build(change_address=sender_address) + tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -1002,7 +1002,7 @@ def test_tx_builder_no_output(chain_context): tx_builder.add_input(utxo1) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True) + tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1029,7 +1029,7 @@ def test_tx_builder_merge_change_to_output(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 10000])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True) + tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1060,7 +1060,7 @@ def test_tx_builder_merge_change_to_output_2(chain_context): tx_builder.add_output(TransactionOutput.from_primitive([receiver, 10000])) tx_builder.add_output(TransactionOutput.from_primitive([sender, 0])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True) + tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1089,7 +1089,7 @@ def test_tx_builder_merge_change_to_zero_amount_output(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 0])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True) + tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1116,7 +1116,7 @@ def test_tx_builder_merge_change_smaller_than_min_utxo(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 9800000])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True) + tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) expected = { 0: [[b"11111111111111111111111111111111", 3]], From db546d37b725275f5bd4530564da4c4dbfd1d018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:32:16 +0100 Subject: [PATCH 05/15] Formatting --- pycardano/txbuilder.py | 6 +- test/pycardano/test_txbuilder.py | 96 +++++++++++++++++++++++++------- 2 files changed, 82 insertions(+), 20 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index d3c93dad..5da3c3dd 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -898,7 +898,11 @@ def build( if auto_required_signers: # collect all signatories from explicitly defined transaction inputs and collateral inputs - required_signers = set(i.output.address.payment_part for i in self.inputs + self.collaterals if not isinstance(i.output.address.payment_part, ScriptHash)) + required_signers = set( + i.output.address.payment_part + for i in self.inputs + self.collaterals + if not isinstance(i.output.address.payment_part, ScriptHash) + ) self.required_signers = list(required_signers) selected_utxos = [] diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index 9e712f5d..ab782af6 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -59,7 +59,9 @@ def test_tx_builder(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -100,7 +102,9 @@ def test_tx_builder_with_certain_input(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -136,7 +140,9 @@ def test_tx_builder_multi_asset(chain_context): ) ) - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [ @@ -178,7 +184,11 @@ def test_tx_builder_raises_utxo_selection(chain_context): ) with pytest.raises(UTxOSelectionException) as e: - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + auto_validity=False, + auto_required_signers=False, + ) # The unfulfilled amount includes requested (991000000) and estimated fees (161277) assert "Unfulfilled amount:\n {\n 'coin': 991161277" in e.value.args[0] @@ -214,7 +224,9 @@ def test_tx_small_utxo_precise_fee(chain_context): # This will not fail as we replace max fee constraint with more precise fee calculation # And remainder is greater than minimum ada required for change - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expect = { 0: [ @@ -266,7 +278,9 @@ def test_tx_small_utxo_balance_pass(chain_context): # Balance is smaller than minimum ada required in change # Additional UTxOs are selected from the input address - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [ @@ -312,7 +326,9 @@ def test_tx_builder_mint_multi_asset(chain_context): tx_builder.native_scripts = [script] tx_builder.ttl = 123456789 - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [ @@ -354,7 +370,9 @@ def test_tx_add_change_split_nfts(chain_context): TransactionOutput.from_primitive([sender, 7000000]) ) - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [ @@ -786,7 +804,9 @@ def test_excluded_input(chain_context): tx_builder.excluded_inputs.append(chain_context.utxos(sender)[0]) - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -819,7 +839,9 @@ def test_build_and_sign(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder1.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder1.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) tx_builder2 = TransactionBuilder( chain_context, [RandomImproveMultiAsset([0, 0, 0, 0, 0])] @@ -827,7 +849,12 @@ def test_build_and_sign(chain_context): tx_builder2.add_input_address(sender).add_output( TransactionOutput.from_primitive([sender, 500000]) ) - tx = tx_builder2.build_and_sign([SK], change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx = tx_builder2.build_and_sign( + [SK], + change_address=sender_address, + auto_validity=False, + auto_required_signers=False, + ) assert tx.transaction_witness_set.vkey_witnesses == [ VerificationKeyWitness(SK.to_verification_key(), SK.sign(tx_body.hash())) @@ -897,7 +924,9 @@ def test_tx_builder_exact_fee_no_change(chain_context): TransactionOutput.from_primitive([sender, input_amount - tx_body.fee]) ) - tx = tx_builder.build_and_sign([SK], auto_validity=False, auto_required_signers=False) + tx = tx_builder.build_and_sign( + [SK], auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -933,7 +962,9 @@ def test_tx_builder_certificates(chain_context): tx_builder.certificates = [stake_registration, stake_delegation] - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -970,7 +1001,9 @@ def test_tx_builder_withdrawal(chain_context): withdrawals = Withdrawals({bytes(stake_address): 10000}) tx_builder.withdrawals = withdrawals - tx_body = tx_builder.build(change_address=sender_address, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, auto_validity=False, auto_required_signers=False + ) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -1002,7 +1035,12 @@ def test_tx_builder_no_output(chain_context): tx_builder.add_input(utxo1) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + merge_change=True, + auto_validity=False, + auto_required_signers=False, + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1029,7 +1067,12 @@ def test_tx_builder_merge_change_to_output(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 10000])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + merge_change=True, + auto_validity=False, + auto_required_signers=False, + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1060,7 +1103,12 @@ def test_tx_builder_merge_change_to_output_2(chain_context): tx_builder.add_output(TransactionOutput.from_primitive([receiver, 10000])) tx_builder.add_output(TransactionOutput.from_primitive([sender, 0])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + merge_change=True, + auto_validity=False, + auto_required_signers=False, + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1089,7 +1137,12 @@ def test_tx_builder_merge_change_to_zero_amount_output(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 0])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + merge_change=True, + auto_validity=False, + auto_required_signers=False, + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -1116,7 +1169,12 @@ def test_tx_builder_merge_change_smaller_than_min_utxo(chain_context): tx_builder.add_input(utxo1) tx_builder.add_output(TransactionOutput.from_primitive([sender, 9800000])) - tx_body = tx_builder.build(change_address=sender_address, merge_change=True, auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build( + change_address=sender_address, + merge_change=True, + auto_validity=False, + auto_required_signers=False, + ) expected = { 0: [[b"11111111111111111111111111111111", 3]], From 57d4c0def1cf7cee98f331a83fb8731577f7ef4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 09:33:41 +0100 Subject: [PATCH 06/15] Fix types --- pycardano/txbuilder.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 5da3c3dd..e15846e5 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -880,8 +880,10 @@ def build( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. - auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a reasonable value - auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs to required signatories + auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a + reasonable value + auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs + to required signatories Returns: TransactionBody: A transaction body. @@ -902,6 +904,7 @@ def build( i.output.address.payment_part for i in self.inputs + self.collaterals if not isinstance(i.output.address.payment_part, ScriptHash) + and i.output.address.payment_part is not None ) self.required_signers = list(required_signers) @@ -1201,8 +1204,10 @@ def build_and_sign( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. - auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a reasonable value - auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs to required signatories + auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to + a reasonable value + auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs + to required signatories Returns: Transaction: A signed transaction. From 3fe6ed43d54c43c2195b6cdbef19f9199eb252be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Tue, 14 Mar 2023 10:13:22 +0100 Subject: [PATCH 07/15] prevent negative validity start --- pycardano/txbuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index e15846e5..6acd89da 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -894,7 +894,7 @@ def build( # Automatically set the validity range to a tight value around transaction creation last_slot = self.context.last_block_slot if self.validity_start is None: - self.validity_start = last_slot - 1000 + self.validity_start = max(0, last_slot - 1000) if self.ttl is None: self.ttl = last_slot + 10000 From 09d3b6fe3a71756432ac9b3cdaa62e5f2a097ea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 12:13:17 +0100 Subject: [PATCH 08/15] Update txbuilder to only add signatures and validity when building smart transactions --- pycardano/txbuilder.py | 79 +++++++++++++++++++++----------- test/pycardano/test_txbuilder.py | 72 ++++++++--------------------- 2 files changed, 71 insertions(+), 80 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 6acd89da..c2ea17bd 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -869,8 +869,9 @@ def build( change_address: Optional[Address] = None, merge_change: Optional[bool] = False, collateral_change_address: Optional[Address] = None, - auto_validity: Optional[bool] = True, - auto_required_signers: Optional[bool] = True, + auto_validity_start_offset: Optional[int] = None, + auto_ttl_offset: Optional[int] = None, + auto_required_signers: Optional[bool] = None, ) -> TransactionBody: """Build a transaction body from all constraints set through the builder. @@ -880,33 +881,40 @@ def build( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. - auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to a - reasonable value + auto_validity_start_offset (Optional[int]): Automatically set the validity start interval of the transaction + to the current slot number + the given offset (default -1000). + A manually set validity start will always take precedence. + auto_ttl_offset (Optional[int]): Automatically set the validity end interval (ttl) of the transaction + to the current slot number + the given offset (default 10_000). + A manually set ttl will always take precedence. auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs - to required signatories + to required signatories (default only for Smart Contract transactions). + Manually set required signers will always take precedence. Returns: TransactionBody: A transaction body. """ self._ensure_no_input_exclusion_conflict() - if auto_validity: - # Automatically set the validity range to a tight value around transaction creation + # only automatically set the validity interval and required signers if scripts are involved + is_smart = bool(self.scripts) + + # Automatically set the validity range to a tight value around transaction creation + if ( + is_smart or auto_validity_start_offset is not None + ) and self.validity_start is None: last_slot = self.context.last_block_slot - if self.validity_start is None: - self.validity_start = max(0, last_slot - 1000) - if self.ttl is None: - self.ttl = last_slot + 10000 + # If None is provided, the default value is -1000 + if auto_validity_start_offset is None: + auto_validity_start_offset = -1000 + self.validity_start = max(0, last_slot + auto_validity_start_offset) - if auto_required_signers: - # collect all signatories from explicitly defined transaction inputs and collateral inputs - required_signers = set( - i.output.address.payment_part - for i in self.inputs + self.collaterals - if not isinstance(i.output.address.payment_part, ScriptHash) - and i.output.address.payment_part is not None - ) - self.required_signers = list(required_signers) + if (is_smart or auto_ttl_offset is not None) and self.ttl is None: + last_slot = self.context.last_block_slot + # If None is provided, the default value is 10_000 + if auto_ttl_offset is None: + auto_ttl_offset = 10_000 + self.ttl = max(0, last_slot + auto_ttl_offset) selected_utxos = [] selected_amount = Value() @@ -1039,6 +1047,18 @@ def build( self.inputs[:] = selected_utxos[:] + # Automatically set the required signers for smart transactions + if ( + is_smart or auto_required_signers is not None + ) and self.required_signers is None: + # Collect all signatories from explicitly defined transaction inputs and collateral inputs + required_signers = set( + i.output.address.payment_part + for i in self.inputs + self.collaterals + if isinstance(i.output.address.payment_part, VerificationKeyHash) + ) + self.required_signers = list(required_signers) + self._set_redeemer_index() self._set_collateral_return(collateral_change_address or change_address) @@ -1190,8 +1210,9 @@ def build_and_sign( change_address: Optional[Address] = None, merge_change: Optional[bool] = False, collateral_change_address: Optional[Address] = None, - auto_validity: Optional[bool] = True, - auto_required_signers: Optional[bool] = True, + auto_validity_start_offset: Optional[int] = None, + auto_ttl_offset: Optional[int] = None, + auto_required_signers: Optional[bool] = None, ) -> Transaction: """Build a transaction body from all constraints set through the builder and sign the transaction with provided signing keys. @@ -1204,10 +1225,15 @@ def build_and_sign( merge_change (Optional[bool]): If the change address match one of the transaction output, the change amount will be directly added to that transaction output, instead of being added as a separate output. collateral_change_address (Optional[Address]): Address to which collateral changes will be returned. - auto_validity (Optional[bool]): Automatically set the validity interval of the transaction to - a reasonable value + auto_validity_start_offset (Optional[int]): Automatically set the validity start interval of the transaction + to the current slot number + the given offset (default -1000). + A manually set validity start will always take precedence. + auto_ttl_offset (Optional[int]): Automatically set the validity end interval (ttl) of the transaction + to the current slot number + the given offset (default 10_000). + A manually set ttl will always take precedence. auto_required_signers (Optional[bool]): Automatically add all pubkeyhashes of transaction inputs - to required signatories + to required signatories (default only for Smart Contract transactions). + Manually set required signers will always take precedence. Returns: Transaction: A signed transaction. @@ -1217,7 +1243,8 @@ def build_and_sign( change_address=change_address, merge_change=merge_change, collateral_change_address=collateral_change_address, - auto_validity=auto_validity, + auto_validity_start_offset=auto_validity_start_offset, + auto_ttl_offset=auto_ttl_offset, auto_required_signers=auto_required_signers, ) witness_set = self.build_witness_set() diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index ab782af6..7c96bbb7 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -59,9 +59,7 @@ def test_tx_builder(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -102,9 +100,7 @@ def test_tx_builder_with_certain_input(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -140,9 +136,7 @@ def test_tx_builder_multi_asset(chain_context): ) ) - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [ @@ -186,8 +180,6 @@ def test_tx_builder_raises_utxo_selection(chain_context): with pytest.raises(UTxOSelectionException) as e: tx_body = tx_builder.build( change_address=sender_address, - auto_validity=False, - auto_required_signers=False, ) # The unfulfilled amount includes requested (991000000) and estimated fees (161277) @@ -224,9 +216,7 @@ def test_tx_small_utxo_precise_fee(chain_context): # This will not fail as we replace max fee constraint with more precise fee calculation # And remainder is greater than minimum ada required for change - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expect = { 0: [ @@ -278,9 +268,7 @@ def test_tx_small_utxo_balance_pass(chain_context): # Balance is smaller than minimum ada required in change # Additional UTxOs are selected from the input address - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [ @@ -315,7 +303,7 @@ def test_tx_builder_mint_multi_asset(chain_context): tx_builder = TransactionBuilder(chain_context) sender = "addr_test1vrm9x2zsux7va6w892g38tvchnzahvcd9tykqf3ygnmwtaqyfg52x" - sender_address = Address.from_primitive(sender) + sender_address: Address = Address.from_primitive(sender) # Add sender address as input mint = {policy_id.payload: {b"Token1": 1}} @@ -326,9 +314,7 @@ def test_tx_builder_mint_multi_asset(chain_context): tx_builder.native_scripts = [script] tx_builder.ttl = 123456789 - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [ @@ -344,14 +330,16 @@ def test_tx_builder_mint_multi_asset(chain_context): [ sender_address.to_primitive(), [ - 5811267, + 5809683, {b"1111111111111111111111111111": {b"Token1": 1, b"Token2": 2}}, ], ], ], - 2: 188733, + 2: 190317, 3: 123456789, + 8: 1000, 9: mint, + 14: [sender_address.payment_part.to_primitive()], } assert expected == tx_body.to_primitive() @@ -370,9 +358,7 @@ def test_tx_add_change_split_nfts(chain_context): TransactionOutput.from_primitive([sender, 7000000]) ) - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [ @@ -804,9 +790,7 @@ def test_excluded_input(chain_context): tx_builder.excluded_inputs.append(chain_context.utxos(sender)[0]) - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [[b"22222222222222222222222222222222", 1]], @@ -839,9 +823,7 @@ def test_build_and_sign(chain_context): TransactionOutput.from_primitive([sender, 500000]) ) - tx_body = tx_builder1.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder1.build(change_address=sender_address) tx_builder2 = TransactionBuilder( chain_context, [RandomImproveMultiAsset([0, 0, 0, 0, 0])] @@ -852,8 +834,6 @@ def test_build_and_sign(chain_context): tx = tx_builder2.build_and_sign( [SK], change_address=sender_address, - auto_validity=False, - auto_required_signers=False, ) assert tx.transaction_witness_set.vkey_witnesses == [ @@ -910,7 +890,7 @@ def test_tx_builder_exact_fee_no_change(chain_context): tx_builder.add_output(TransactionOutput.from_primitive([sender, 5000000])) - tx_body = tx_builder.build(auto_validity=False, auto_required_signers=False) + tx_body = tx_builder.build() tx_builder = TransactionBuilder(chain_context) @@ -924,9 +904,7 @@ def test_tx_builder_exact_fee_no_change(chain_context): TransactionOutput.from_primitive([sender, input_amount - tx_body.fee]) ) - tx = tx_builder.build_and_sign( - [SK], auto_validity=False, auto_required_signers=False - ) + tx = tx_builder.build_and_sign([SK]) expected = { 0: [[b"11111111111111111111111111111111", 3]], @@ -962,9 +940,7 @@ def test_tx_builder_certificates(chain_context): tx_builder.certificates = [stake_registration, stake_delegation] - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -1001,9 +977,7 @@ def test_tx_builder_withdrawal(chain_context): withdrawals = Withdrawals({bytes(stake_address): 10000}) tx_builder.withdrawals = withdrawals - tx_body = tx_builder.build( - change_address=sender_address, auto_validity=False, auto_required_signers=False - ) + tx_body = tx_builder.build(change_address=sender_address) expected = { 0: [[b"11111111111111111111111111111111", 0]], @@ -1038,8 +1012,6 @@ def test_tx_builder_no_output(chain_context): tx_body = tx_builder.build( change_address=sender_address, merge_change=True, - auto_validity=False, - auto_required_signers=False, ) expected = { @@ -1070,8 +1042,6 @@ def test_tx_builder_merge_change_to_output(chain_context): tx_body = tx_builder.build( change_address=sender_address, merge_change=True, - auto_validity=False, - auto_required_signers=False, ) expected = { @@ -1106,8 +1076,6 @@ def test_tx_builder_merge_change_to_output_2(chain_context): tx_body = tx_builder.build( change_address=sender_address, merge_change=True, - auto_validity=False, - auto_required_signers=False, ) expected = { @@ -1140,8 +1108,6 @@ def test_tx_builder_merge_change_to_zero_amount_output(chain_context): tx_body = tx_builder.build( change_address=sender_address, merge_change=True, - auto_validity=False, - auto_required_signers=False, ) expected = { @@ -1172,8 +1138,6 @@ def test_tx_builder_merge_change_smaller_than_min_utxo(chain_context): tx_body = tx_builder.build( change_address=sender_address, merge_change=True, - auto_validity=False, - auto_required_signers=False, ) expected = { From d75c6b915ed513806efc4b4e9d231b00078e8092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 12:17:40 +0100 Subject: [PATCH 09/15] Use all input_addresses instead of actually selected inputs --- pycardano/txbuilder.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index c2ea17bd..e3a9d77c 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -916,6 +916,22 @@ def build( auto_ttl_offset = 10_000 self.ttl = max(0, last_slot + auto_ttl_offset) + # Automatically set the required signers for smart transactions + if ( + is_smart or auto_required_signers is not None + ) and self.required_signers is None: + # Collect all signatories from explicitly defined + # transaction inputs and collateral inputs, and input addresses + input_addresses = [ + i.output.address for i in self.inputs + self.collaterals + ] + [Address.from_primitive(a) for a in self.input_addresses] + required_signers = set( + a.payment_part + for a in input_addresses + if isinstance(a.payment_part, VerificationKeyHash) + ) + self.required_signers = list(required_signers) + selected_utxos = [] selected_amount = Value() for i in self.inputs: @@ -1047,18 +1063,6 @@ def build( self.inputs[:] = selected_utxos[:] - # Automatically set the required signers for smart transactions - if ( - is_smart or auto_required_signers is not None - ) and self.required_signers is None: - # Collect all signatories from explicitly defined transaction inputs and collateral inputs - required_signers = set( - i.output.address.payment_part - for i in self.inputs + self.collaterals - if isinstance(i.output.address.payment_part, VerificationKeyHash) - ) - self.required_signers = list(required_signers) - self._set_redeemer_index() self._set_collateral_return(collateral_change_address or change_address) From b6cec5b2154ffe692d9a7aca070255a58cde7342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 12:18:50 +0100 Subject: [PATCH 10/15] Require auto_required_signers to be set to True or None --- pycardano/txbuilder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index e3a9d77c..1ffa33f7 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -918,7 +918,7 @@ def build( # Automatically set the required signers for smart transactions if ( - is_smart or auto_required_signers is not None + is_smart and auto_required_signers is not False ) and self.required_signers is None: # Collect all signatories from explicitly defined # transaction inputs and collateral inputs, and input addresses From bf5d83a629cd8d79bec29ebee7bac94676322537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 13:03:25 +0100 Subject: [PATCH 11/15] Correctly transform to Address --- pycardano/txbuilder.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 1ffa33f7..374759d7 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -924,7 +924,10 @@ def build( # transaction inputs and collateral inputs, and input addresses input_addresses = [ i.output.address for i in self.inputs + self.collaterals - ] + [Address.from_primitive(a) for a in self.input_addresses] + ] + [ + Address.from_primitive(a) if isinstance(a, str) else a + for a in self.input_addresses + ] required_signers = set( a.payment_part for a in input_addresses From f95e8edb1b5ece46c64b8241904cdeb17014938a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 17:47:29 +0100 Subject: [PATCH 12/15] Use _input_vkey_hashes --- pycardano/txbuilder.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 374759d7..283e8160 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -923,8 +923,6 @@ def build( # Collect all signatories from explicitly defined # transaction inputs and collateral inputs, and input addresses input_addresses = [ - i.output.address for i in self.inputs + self.collaterals - ] + [ Address.from_primitive(a) if isinstance(a, str) else a for a in self.input_addresses ] @@ -932,7 +930,7 @@ def build( a.payment_part for a in input_addresses if isinstance(a.payment_part, VerificationKeyHash) - ) + ) | self._input_vkey_hashes() self.required_signers = list(required_signers) selected_utxos = [] From bd6b1c4ffa3efb35e6c215e1581a6fd5aab06e83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Wed, 15 Mar 2023 17:48:44 +0100 Subject: [PATCH 13/15] Use _input_vkey_hashes --- pycardano/txbuilder.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 283e8160..d51798d4 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -926,11 +926,11 @@ def build( Address.from_primitive(a) if isinstance(a, str) else a for a in self.input_addresses ] - required_signers = set( + required_signers = self._input_vkey_hashes() | set( a.payment_part for a in input_addresses if isinstance(a.payment_part, VerificationKeyHash) - ) | self._input_vkey_hashes() + ) self.required_signers = list(required_signers) selected_utxos = [] From 48ae7ff3ffbcdad35e9af8970b348f94e5201d95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Thu, 16 Mar 2023 08:47:20 +0100 Subject: [PATCH 14/15] Remove input_addresses from tx_builder required signers --- pycardano/txbuilder.py | 11 +---------- test/pycardano/test_txbuilder.py | 6 +++--- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index d51798d4..f8465d2a 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -922,16 +922,7 @@ def build( ) and self.required_signers is None: # Collect all signatories from explicitly defined # transaction inputs and collateral inputs, and input addresses - input_addresses = [ - Address.from_primitive(a) if isinstance(a, str) else a - for a in self.input_addresses - ] - required_signers = self._input_vkey_hashes() | set( - a.payment_part - for a in input_addresses - if isinstance(a.payment_part, VerificationKeyHash) - ) - self.required_signers = list(required_signers) + self.required_signers = list(self._input_vkey_hashes()) selected_utxos = [] selected_amount = Value() diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index 7c96bbb7..d32d4fd5 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -330,16 +330,16 @@ def test_tx_builder_mint_multi_asset(chain_context): [ sender_address.to_primitive(), [ - 5809683, + 5811003, {b"1111111111111111111111111111": {b"Token1": 1, b"Token2": 2}}, ], ], ], - 2: 190317, + 2: 188997, 3: 123456789, 8: 1000, 9: mint, - 14: [sender_address.payment_part.to_primitive()], + 14: [], } assert expected == tx_body.to_primitive() From fe3e0327bc01894a7cd6db49e551ce7a5fa0085d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=BCndler?= Date: Thu, 16 Mar 2023 19:40:56 +0100 Subject: [PATCH 15/15] Move signer key hash addition to later --- pycardano/txbuilder.py | 16 ++++++++-------- test/pycardano/test_txbuilder.py | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index f8465d2a..8ea8c94c 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -916,14 +916,6 @@ def build( auto_ttl_offset = 10_000 self.ttl = max(0, last_slot + auto_ttl_offset) - # Automatically set the required signers for smart transactions - if ( - is_smart and auto_required_signers is not False - ) and self.required_signers is None: - # Collect all signatories from explicitly defined - # transaction inputs and collateral inputs, and input addresses - self.required_signers = list(self._input_vkey_hashes()) - selected_utxos = [] selected_amount = Value() for i in self.inputs: @@ -1055,6 +1047,14 @@ def build( self.inputs[:] = selected_utxos[:] + # Automatically set the required signers for smart transactions + if ( + is_smart and auto_required_signers is not False + ) and self.required_signers is None: + # Collect all signatories from explicitly defined + # transaction inputs and collateral inputs, and input addresses + self.required_signers = list(self._input_vkey_hashes()) + self._set_redeemer_index() self._set_collateral_return(collateral_change_address or change_address) diff --git a/test/pycardano/test_txbuilder.py b/test/pycardano/test_txbuilder.py index d32d4fd5..7c96bbb7 100644 --- a/test/pycardano/test_txbuilder.py +++ b/test/pycardano/test_txbuilder.py @@ -330,16 +330,16 @@ def test_tx_builder_mint_multi_asset(chain_context): [ sender_address.to_primitive(), [ - 5811003, + 5809683, {b"1111111111111111111111111111": {b"Token1": 1, b"Token2": 2}}, ], ], ], - 2: 188997, + 2: 190317, 3: 123456789, 8: 1000, 9: mint, - 14: [], + 14: [sender_address.payment_part.to_primitive()], } assert expected == tx_body.to_primitive()