diff --git a/README.md b/README.md index 720afd8c..0febf158 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ builder = TransactionBuilder(context) builder.add_input_address(address) # Get all UTxOs currently sitting at this address -utxos = context.utxos(str(address)) +utxos = context.utxos(address) # We can also tell the builder to include a specific UTxO in the transaction. # Similarly, "add_input" could be called multiple times. @@ -156,7 +156,7 @@ builder.add_output( signed_tx = builder.build_and_sign([psk], change_address=address) # Submit signed transaction to the network -context.submit_tx(signed_tx.to_cbor()) +context.submit_tx(signed_tx) ``` diff --git a/examples/delegator_loyalty_rewards.py b/examples/delegator_loyalty_rewards.py index 91a72cc8..24feff28 100644 --- a/examples/delegator_loyalty_rewards.py +++ b/examples/delegator_loyalty_rewards.py @@ -101,5 +101,5 @@ print("#### Transaction id ####") print(signed_tx.id) -context.submit_tx(signed_tx.to_cbor()) +context.submit_tx(signed_tx) print("Transaction successfully submitted!") diff --git a/examples/full_stack/server.py b/examples/full_stack/server.py index 9f50f0f5..e67792c3 100644 --- a/examples/full_stack/server.py +++ b/examples/full_stack/server.py @@ -77,5 +77,5 @@ def submit_tx(): print(f"Transaction: \n {tx}") print(f"Transaction cbor: {tx.to_cbor()}") print(f"Transaction ID: {tx_id}") - chain_context.submit_tx(tx.to_cbor()) + chain_context.submit_tx(tx) return {"tx_id": tx_id} diff --git a/examples/native_token.py b/examples/native_token.py index 69a4b943..dbf6e4b3 100644 --- a/examples/native_token.py +++ b/examples/native_token.py @@ -172,4 +172,4 @@ def load_or_create_key_pair(base_dir, base_name): # Submit signed transaction to the network print("############### Submitting transaction ###############") -chain_context.submit_tx(signed_tx.to_cbor()) +chain_context.submit_tx(signed_tx) diff --git a/examples/plutus/forty_two/forty_two.py b/examples/plutus/forty_two/forty_two.py index 8175c13b..2d723978 100644 --- a/examples/plutus/forty_two/forty_two.py +++ b/examples/plutus/forty_two/forty_two.py @@ -43,7 +43,7 @@ def submit_tx(tx): print(tx) print(tx.to_cbor()) print("############### Submitting transaction ###############") - chain_context.submit_tx(tx.to_cbor()) + chain_context.submit_tx(tx) wait_for_tx(str(tx.id)) @@ -91,7 +91,7 @@ def submit_tx(tx): utxo_to_spend = None # Spend the utxo with datum 42 sitting at the script address -for utxo in chain_context.utxos(str(script_address)): +for utxo in chain_context.utxos(script_address): print(utxo) if utxo.output.datum: utxo_to_spend = utxo @@ -99,7 +99,7 @@ def submit_tx(tx): # Find the reference script utxo reference_script_utxo = None -for utxo in chain_context.utxos(str(giver_address)): +for utxo in chain_context.utxos(giver_address): if utxo.output.script and utxo.output.script == forty_two_script: reference_script_utxo = utxo break diff --git a/examples/tx_builder.py b/examples/tx_builder.py index d49ec955..70da94e0 100644 --- a/examples/tx_builder.py +++ b/examples/tx_builder.py @@ -31,7 +31,7 @@ builder.add_input_address(address) # Get all UTxOs currently sitting at this address -utxos = context.utxos(str(address)) +utxos = context.utxos(address) # We can also tell the builder to include a specific UTxO in the transaction. # Similarly, "add_input" could be called multiple times. @@ -82,4 +82,4 @@ signed_tx = builder.build_and_sign([psk], change_address=address) # Submit signed transaction to the network -context.submit_tx(signed_tx.to_cbor()) +context.submit_tx(signed_tx) diff --git a/integration-test/test/base.py b/integration-test/test/base.py index ae6b457d..0aaa2a2b 100644 --- a/integration-test/test/base.py +++ b/integration-test/test/base.py @@ -45,7 +45,7 @@ class TestBase: @retry(tries=TEST_RETRIES, delay=3) def assert_output(self, target_address, target_output): - utxos = self.chain_context.utxos(str(target_address)) + utxos = self.chain_context.utxos(target_address) found = False for utxo in utxos: @@ -69,5 +69,5 @@ def fund(self, source_address, source_key, target_address, amount=5000000): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(target_address, target_output=output) diff --git a/integration-test/test/test_certificate.py b/integration-test/test/test_certificate.py index 8aac5452..3897e98c 100644 --- a/integration-test/test/test_certificate.py +++ b/integration-test/test/test_certificate.py @@ -17,7 +17,7 @@ def test_stake_delegation(self): self.NETWORK, ) - utxos = self.chain_context.utxos(str(address)) + utxos = self.chain_context.utxos(address) if not utxos: giver_address = Address(self.payment_vkey.hash(), network=self.NETWORK) @@ -33,7 +33,7 @@ def test_stake_delegation(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) @@ -60,7 +60,7 @@ def test_stake_delegation(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(8) @@ -86,4 +86,4 @@ def test_stake_delegation(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) diff --git a/integration-test/test/test_min_utxo.py b/integration-test/test/test_min_utxo.py index f54bb00c..cbd88447 100644 --- a/integration-test/test/test_min_utxo.py +++ b/integration-test/test/test_min_utxo.py @@ -102,6 +102,6 @@ class MyPlutusData(PlutusData): # Submit signed transaction to the network print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(address, nft_output) diff --git a/integration-test/test/test_mint.py b/integration-test/test/test_mint.py index 3d16fba9..37b493ba 100644 --- a/integration-test/test/test_mint.py +++ b/integration-test/test/test_mint.py @@ -136,7 +136,7 @@ def load_or_create_key_pair(base_dir, base_name): # Submit signed transaction to the network print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(address, nft_output) @@ -162,7 +162,7 @@ def load_or_create_key_pair(base_dir, base_name): # Submit signed transaction to the network print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(address, nft_to_send) @@ -233,7 +233,7 @@ def test_mint_nft_with_script(self): self.fund(address, self.payment_skey, address) non_nft_utxo = None - for utxo in self.chain_context.utxos(str(address)): + for utxo in self.chain_context.utxos(address): # multi_asset should be empty for collateral utxo if not utxo.output.amount.multi_asset: non_nft_utxo = utxo @@ -251,7 +251,7 @@ def test_mint_nft_with_script(self): # Submit signed transaction to the network print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(address, nft_output) @@ -338,6 +338,6 @@ class MyPlutusData(PlutusData): # Submit signed transaction to the network print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(address, nft_output) diff --git a/integration-test/test/test_plutus.py b/integration-test/test/test_plutus.py index 036672cf..c5d78a5c 100644 --- a/integration-test/test/test_plutus.py +++ b/integration-test/test/test_plutus.py @@ -37,7 +37,7 @@ def test_plutus_v1(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Fund taker a collateral UTxO --------------- @@ -55,14 +55,14 @@ def test_plutus_v1(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Taker take --------------- redeemer = Redeemer(42) - utxo_to_spend = self.chain_context.utxos(str(script_address))[0] + utxo_to_spend = self.chain_context.utxos(script_address)[0] taker_address = Address(self.extended_payment_vkey.hash(), network=self.NETWORK) @@ -75,7 +75,7 @@ def test_plutus_v1(self): builder.add_output(take_output) non_nft_utxo = None - for utxo in self.chain_context.utxos(str(taker_address)): + for utxo in self.chain_context.utxos(taker_address): # multi_asset should be empty for collateral utxo if not utxo.output.amount.multi_asset: non_nft_utxo = utxo @@ -89,7 +89,7 @@ def test_plutus_v1(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(taker_address, take_output) @@ -121,7 +121,7 @@ def test_plutus_v2_datum_hash(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Taker take --------------- @@ -131,7 +131,7 @@ def test_plutus_v2_datum_hash(self): utxo_to_spend = None # Speed the utxo that doesn't have datum/datum_hash or script attached - for utxo in self.chain_context.utxos(str(script_address)): + for utxo in self.chain_context.utxos(script_address): if not utxo.output.script and ( utxo.output.datum_hash == datum_hash(datum) or utxo.output.datum == datum @@ -150,7 +150,7 @@ def test_plutus_v2_datum_hash(self): builder.add_output(take_output) non_nft_utxo = None - for utxo in self.chain_context.utxos(str(taker_address)): + for utxo in self.chain_context.utxos(taker_address): # multi_asset should be empty for collateral utxo if not utxo.output.amount.multi_asset: non_nft_utxo = utxo @@ -164,7 +164,7 @@ def test_plutus_v2_datum_hash(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(taker_address, take_output) @@ -198,7 +198,7 @@ def test_plutus_v2_inline_script_inline_datum(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Taker take --------------- @@ -208,7 +208,7 @@ def test_plutus_v2_inline_script_inline_datum(self): utxo_to_spend = None # Speed the utxo that has both inline script and inline datum - for utxo in self.chain_context.utxos(str(script_address)): + for utxo in self.chain_context.utxos(script_address): if utxo.output.datum and utxo.output.script: utxo_to_spend = utxo break @@ -225,9 +225,9 @@ def test_plutus_v2_inline_script_inline_datum(self): print("############### Transaction created ###############") print(signed_tx) - print(signed_tx.to_cbor()) + print(signed_tx) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(taker_address, take_output) @@ -259,7 +259,7 @@ def test_plutus_v2_ref_script(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Send ADA to the same script address without datum or script --------------- @@ -276,7 +276,7 @@ def test_plutus_v2_ref_script(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) time.sleep(3) # ----------- Taker take --------------- @@ -286,7 +286,7 @@ def test_plutus_v2_ref_script(self): utxo_to_spend = None # Spend the utxo that doesn't have datum/datum_hash or script attached - for utxo in self.chain_context.utxos(str(script_address)): + for utxo in self.chain_context.utxos(script_address): if not utxo.output.script and ( utxo.output.datum_hash == datum_hash(datum) or datum_hash(utxo.output.datum) == datum_hash(datum) @@ -308,6 +308,6 @@ def test_plutus_v2_ref_script(self): print(signed_tx) print(signed_tx.to_cbor()) print("############### Submitting transaction ###############") - self.chain_context.submit_tx(signed_tx.to_cbor()) + self.chain_context.submit_tx(signed_tx) self.assert_output(taker_address, take_output) diff --git a/pycardano/backend/base.py b/pycardano/backend/base.py index 9ab8b027..b3ce7a56 100644 --- a/pycardano/backend/base.py +++ b/pycardano/backend/base.py @@ -5,9 +5,10 @@ from typeguard import typechecked +from pycardano.address import Address from pycardano.network import Network from pycardano.plutus import ExecutionUnits -from pycardano.transaction import UTxO +from pycardano.transaction import UTxO, Transaction __all__ = [ "GenesisParameters", @@ -136,7 +137,18 @@ def last_block_slot(self) -> int: """Slot number of last block""" raise NotImplementedError() - def utxos(self, address: str) -> List[UTxO]: + def utxos(self, address: Union[str, Address]) -> List[UTxO]: + """Get all UTxOs associated with an address. + + Args: + address (Union[str, Address]): An address, potentially bech32 encoded + + Returns: + List[UTxO]: A list of UTxOs. + """ + return self._utxos(str(address)) + + def _utxos(self, address: str) -> List[UTxO]: """Get all UTxOs associated with an address. Args: @@ -147,7 +159,19 @@ def utxos(self, address: str) -> List[UTxO]: """ raise NotImplementedError() - def submit_tx(self, cbor: Union[bytes, str]): + def submit_tx(self, tx: Transaction): + """Submit a transaction to the blockchain. + + Args: + tx (Transaction): The transaction to be submitted. + + Raises: + :class:`InvalidArgumentException`: When the transaction is invalid. + :class:`TransactionFailedException`: When fails to submit the transaction to blockchain. + """ + return self.submit_tx_cbor(tx.to_cbor("bytes")) + + def submit_tx_cbor(self, cbor: Union[bytes, str]): """Submit a transaction to the blockchain. Args: @@ -159,7 +183,18 @@ def submit_tx(self, cbor: Union[bytes, str]): """ raise NotImplementedError() - def evaluate_tx(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + def evaluate_tx(self, tx: Transaction) -> Dict[str, ExecutionUnits]: + """Evaluate execution units of a transaction. + + Args: + transaction (Transaction): The transaction to be evaluated. + + Returns: + List[ExecutionUnits]: A list of execution units calculated for each of the transaction's redeemers + """ + return self.evaluate_tx_cbor(tx.to_cbor("bytes")) + + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: """Evaluate execution units of a transaction. Args: diff --git a/pycardano/backend/blockfrost.py b/pycardano/backend/blockfrost.py index d77acdde..60abb11e 100644 --- a/pycardano/backend/blockfrost.py +++ b/pycardano/backend/blockfrost.py @@ -160,7 +160,7 @@ def _get_script( )["json"] return NativeScript.from_dict(script_json) - def utxos(self, address: str) -> List[UTxO]: + def _utxos(self, address: str) -> List[UTxO]: results = self.api.address_utxos(address, gather_pages=True) utxos = [] @@ -217,7 +217,7 @@ def utxos(self, address: str) -> List[UTxO]: return utxos - def submit_tx(self, cbor: Union[bytes, str]) -> str: + def submit_tx_cbor(self, cbor: Union[bytes, str]) -> str: """Submit a transaction. Args: @@ -243,7 +243,7 @@ def submit_tx(self, cbor: Union[bytes, str]) -> str: os.remove(f.name) return response - def evaluate_tx(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: """Evaluate execution units of a transaction. Args: diff --git a/pycardano/backend/ogmios.py b/pycardano/backend/ogmios.py index 38067600..0696d40f 100644 --- a/pycardano/backend/ogmios.py +++ b/pycardano/backend/ogmios.py @@ -226,7 +226,7 @@ def last_block_slot(self) -> int: result = self._query_chain_tip() return result["slot"] - def utxos(self, address: str) -> List[UTxO]: + def _utxos(self, address: str) -> List[UTxO]: """Get all UTxOs associated with an address. Args: @@ -438,7 +438,7 @@ def _utxo_from_ogmios_result(self, result) -> UTxO: utxo = UTxO(tx_in, tx_out) return utxo - def submit_tx(self, cbor: Union[bytes, str]): + def submit_tx_cbor(self, cbor: Union[bytes, str]): """Submit a transaction to the blockchain. Args: @@ -456,7 +456,7 @@ def submit_tx(self, cbor: Union[bytes, str]): if "SubmitFail" in result: raise TransactionFailedException(result["SubmitFail"]) - def evaluate_tx(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: """Evaluate execution units of a transaction. Args: diff --git a/pycardano/txbuilder.py b/pycardano/txbuilder.py index 568e39d6..0e8f2088 100644 --- a/pycardano/txbuilder.py +++ b/pycardano/txbuilder.py @@ -240,7 +240,7 @@ def add_script_input( self.reference_inputs.add(utxo) self._reference_scripts.append(utxo.output.script) elif not script: - for i in self.context.utxos(str(utxo.output.address)): + for i in self.context.utxos(utxo.output.address): if i.output.script: self._inputs_to_scripts[utxo] = i.output.script self.reference_inputs.add(i) @@ -989,7 +989,7 @@ def build( additional_utxo_pool = [] additional_amount = Value() for address in self.input_addresses: - for utxo in self.context.utxos(str(address)): + for utxo in self.context.utxos(address): if ( utxo not in selected_utxos and utxo not in self.excluded_inputs @@ -1123,7 +1123,7 @@ def _add_collateral_input(cur_total, candidate_inputs): if tmp_val.coin < collateral_amount: sorted_inputs = sorted( - self.context.utxos(str(collateral_return_address)), + self.context.utxos(collateral_return_address), key=lambda i: (len(i.output.to_cbor()), -i.output.amount.coin), ) _add_collateral_input(tmp_val, sorted_inputs) @@ -1207,7 +1207,7 @@ def _estimate_execution_units( tx_body, witness_set, auxiliary_data=tmp_builder.auxiliary_data ) - return self.context.evaluate_tx(tx.to_cbor()) + return self.context.evaluate_tx(tx) def build_and_sign( self, diff --git a/test/pycardano/util.py b/test/pycardano/util.py index 433a7cc2..c69c268f 100644 --- a/test/pycardano/util.py +++ b/test/pycardano/util.py @@ -93,7 +93,7 @@ def last_block_slot(self) -> int: """Current slot number""" return 2000 - def utxos(self, address: str) -> List[UTxO]: + def _utxos(self, address: str) -> List[UTxO]: """Get all UTxOs associated with an address. Args: @@ -110,7 +110,7 @@ def utxos(self, address: str) -> List[UTxO]: ) return [UTxO(tx_in1, tx_out1), UTxO(tx_in2, tx_out2)] - def submit_tx(self, cbor: Union[bytes, str]): + def submit_tx_cbor(self, cbor: Union[bytes, str]): """Submit a transaction to the blockchain. Args: @@ -122,7 +122,7 @@ def submit_tx(self, cbor: Union[bytes, str]): """ pass - def evaluate_tx(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: + def evaluate_tx_cbor(self, cbor: Union[bytes, str]) -> Dict[str, ExecutionUnits]: return {"spend:0": ExecutionUnits(399882, 175940720)}