From a734b358caae090227c537a52e11477f32ddd602 Mon Sep 17 00:00:00 2001 From: Michiel B <52638249+Godspeed-exe@users.noreply.github.com> Date: Sun, 5 Jan 2025 00:34:40 +0100 Subject: [PATCH] add more examples scripts (#399) * add more examples scripts * exclude tempfiles * delete tempfiles * remove external file and generate local pdf * Fix format --------- Co-authored-by: Michiel Co-authored-by: Jerry --- examples/more_examples/.env-example | 3 + examples/more_examples/.gitignore | 5 + examples/more_examples/01_address.py | 78 +++++++ examples/more_examples/02_query_address.py | 67 ++++++ examples/more_examples/03_distribute.py | 70 +++++++ examples/more_examples/04_consolidate.py | 106 ++++++++++ examples/more_examples/05_mint_asset.py | 131 ++++++++++++ .../more_examples/06_query_receive_address.py | 66 ++++++ examples/more_examples/07_mint_nfts.py | 192 ++++++++++++++++++ examples/more_examples/08_burn_nfts.py | 181 +++++++++++++++++ .../more_examples/09_sign_document_data.py | 117 +++++++++++ examples/more_examples/10_verify_document.py | 101 +++++++++ .../more_examples/11_verify_fake_document.py | 113 +++++++++++ .../more_examples/12_transaction_chaining.py | 166 +++++++++++++++ examples/more_examples/README.md | 21 ++ examples/more_examples/keys/.gitkeep | 0 16 files changed, 1417 insertions(+) create mode 100644 examples/more_examples/.env-example create mode 100644 examples/more_examples/.gitignore create mode 100644 examples/more_examples/01_address.py create mode 100644 examples/more_examples/02_query_address.py create mode 100644 examples/more_examples/03_distribute.py create mode 100644 examples/more_examples/04_consolidate.py create mode 100644 examples/more_examples/05_mint_asset.py create mode 100644 examples/more_examples/06_query_receive_address.py create mode 100644 examples/more_examples/07_mint_nfts.py create mode 100644 examples/more_examples/08_burn_nfts.py create mode 100644 examples/more_examples/09_sign_document_data.py create mode 100644 examples/more_examples/10_verify_document.py create mode 100644 examples/more_examples/11_verify_fake_document.py create mode 100644 examples/more_examples/12_transaction_chaining.py create mode 100644 examples/more_examples/README.md create mode 100644 examples/more_examples/keys/.gitkeep diff --git a/examples/more_examples/.env-example b/examples/more_examples/.env-example new file mode 100644 index 00000000..00e311bb --- /dev/null +++ b/examples/more_examples/.env-example @@ -0,0 +1,3 @@ +network="testnet" +wallet_mnemonic="select calm scorpion mask furnace nerve fade slam bid suggest avoid remove half depend turn little midnight fossil submit cart sick glance inner slide" +blockfrost_api_key="preprod...." \ No newline at end of file diff --git a/examples/more_examples/.gitignore b/examples/more_examples/.gitignore new file mode 100644 index 00000000..e6848975 --- /dev/null +++ b/examples/more_examples/.gitignore @@ -0,0 +1,5 @@ +.env +/keys/* +!keys/.gitkeep +tempfile.pdf +tempfile_copy.pdf \ No newline at end of file diff --git a/examples/more_examples/01_address.py b/examples/more_examples/01_address.py new file mode 100644 index 00000000..f4970e65 --- /dev/null +++ b/examples/more_examples/01_address.py @@ -0,0 +1,78 @@ +import os + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +print("Enterprise address (only payment):") +print("Payment Derivation path: m/1852'/1815'/0'/0/0") + +enterprise_address = Address( + payment_part=payment_skey.to_verification_key().hash(), network=cardano_network +) +print(enterprise_address) + +print(" ") +print("Staking enabled address:") +print("Payment Derivation path: m/1852'/1815'/0'/0/0") +print("Staking Derivation path: m/1852'/1815'/0'/2/0") + +staking_enabled_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) +print(staking_enabled_address) + +print(" ") +next_step = input("Press Enter to continue...") +print(" ") + +for i in range(5): + derivation_path = f"m/1852'/1815'/0'/0/{i}" + + payment_key = new_wallet.derive_from_path(derivation_path) + payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) + + enterprise_address = Address( + payment_part=payment_skey.to_verification_key().hash(), network=cardano_network + ) + print(f"Address {derivation_path}: {enterprise_address}") + +print(" ") +next_step = input("Press Enter to continue...") +print(" ") + +for i in range(5): + derivation_path = f"m/1852'/1815'/0'/0/{i}" + + payment_key = new_wallet.derive_from_path(derivation_path) + payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) + + staking_enabled_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, + ) + print(f"Address {derivation_path}: {staking_enabled_address}") diff --git a/examples/more_examples/02_query_address.py b/examples/more_examples/02_query_address.py new file mode 100644 index 00000000..df82f6d2 --- /dev/null +++ b/examples/more_examples/02_query_address.py @@ -0,0 +1,67 @@ +import os +import sys + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + +print(f"hash \t\t\t\t\t\t\t\t\t amount") +print( + "--------------------------------------------------------------------------------------" +) + +for utxo in utxos: + tokens = "" + for token in utxo.amount: + if token.unit != "lovelace": + tokens += f"{token.quantity} {token.unit} + " + print( + f"{utxo.tx_hash}#{utxo.tx_index} \t {int(utxo.amount[0].quantity)/1000000} ADA [{tokens}]" + ) diff --git a/examples/more_examples/03_distribute.py b/examples/more_examples/03_distribute.py new file mode 100644 index 00000000..f7a4c02c --- /dev/null +++ b/examples/more_examples/03_distribute.py @@ -0,0 +1,70 @@ +import os +import sys + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + +for i in range(20): + output = TransactionOutput(main_address, Value(4000000)) + builder.add_output(output) + +builder.add_input_address(main_address) +signed_tx = builder.build_and_sign([payment_skey], change_address=main_address) +result = cardano.submit_tx(signed_tx.to_cbor()) +print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") +print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") +print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") +print(f"Transaction submitted! ID: {result}") diff --git a/examples/more_examples/04_consolidate.py b/examples/more_examples/04_consolidate.py new file mode 100644 index 00000000..f2e2331e --- /dev/null +++ b/examples/more_examples/04_consolidate.py @@ -0,0 +1,106 @@ +import os +import sys + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + +inputs = [] + +total_ada_used = 0 + +for utxo in utxos: + input = TransactionInput.from_primitive([utxo.tx_hash, utxo.tx_index]) + inputs.append(input) + builder.add_input(input) + total_ada_used += int(utxo.amount[0].quantity) + +output = TransactionOutput(main_address, Value(total_ada_used)) + +tx_body = TransactionBody(inputs=inputs, outputs=[output], fee=100000) + +signature = payment_skey.sign(tx_body.hash()) +vk = PaymentVerificationKey.from_signing_key(payment_skey) +vk_witnesses = [VerificationKeyWitness(vk, signature)] +signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) + +calculated_fee = fee(cardano, len(signed_tx.to_cbor())) + + +total_ada_available = total_ada_used - calculated_fee +output = TransactionOutput(main_address, Value(total_ada_available)) + +tx_body = TransactionBody(inputs=inputs, outputs=[output], fee=calculated_fee) + +signature = payment_skey.sign(tx_body.hash()) +vk = PaymentVerificationKey.from_signing_key(payment_skey) +vk_witnesses = [VerificationKeyWitness(vk, signature)] +signed_tx = Transaction(tx_body, TransactionWitnessSet(vkey_witnesses=vk_witnesses)) + +try: + result = cardano.submit_tx(signed_tx.to_cbor()) + print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") + print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") + print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") + print(f"Transaction submitted! ID: {result}") +except Exception as e: + if "BadInputsUTxO" in str(e): + print("Trying to spend an input that doesn't exist (or no longer exist).") + elif "ValueNotConservedUTxO" in str(e): + print( + "Transaction not correctly balanced. Inputs and outputs (+fee) don't match." + ) + else: + print(e) diff --git a/examples/more_examples/05_mint_asset.py b/examples/more_examples/05_mint_asset.py new file mode 100644 index 00000000..19628a13 --- /dev/null +++ b/examples/more_examples/05_mint_asset.py @@ -0,0 +1,131 @@ +import os +import sys +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +receive_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/1") +reeive_skey = ExtendedSigningKey.from_hdwallet(receive_key) +receive_address = Address( + payment_part=reeive_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +print(" ") +print(f"Derived address: {main_address}") +print(" ") +print(f"Receive address: {receive_address}") +print(" ") + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + +######################################################## +####### Generate Policy keys ####### +####### IF it doesn't exist ####### +######################################################## +if not exists(f"keys/policy.skey") and not exists(f"keys/policy.vkey"): + payment_key_pair = PaymentKeyPair.generate() + payment_signing_key = payment_key_pair.signing_key + payment_verification_key = payment_key_pair.verification_key + payment_signing_key.save(f"keys/policy.skey") + payment_verification_key.save(f"keys/policy.vkey") + + +######################################################## +####### Initiate Policy ####### +######################################################## +policy_signing_key = PaymentSigningKey.load(f"keys/policy.skey") +policy_verification_key = PaymentVerificationKey.load(f"keys/policy.vkey") +pub_key_policy = ScriptPubkey(policy_verification_key.hash()) + + +policy = ScriptAll([pub_key_policy]) + +policy_id = policy.hash() +policy_id_hex = policy_id.payload.hex() +native_scripts = [policy] + +asset_name = "MichielCOIN" +asset_name_bytes = asset_name.encode("utf-8") + +token = AssetName(asset_name_bytes) + +new_asset = Asset() +multiasset = MultiAsset() + +new_asset[token] = 100 + +multiasset[policy_id] = new_asset + + +builder.native_scripts = native_scripts +builder.mint = multiasset + +min_val = min_lovelace( + cardano, output=TransactionOutput(receive_address, Value(0, multiasset)) +) + +builder.add_output(TransactionOutput(receive_address, Value(min_val, multiasset))) + + +builder.add_input_address(main_address) +signed_tx = builder.build_and_sign( + [payment_skey, policy_signing_key], change_address=main_address +) +result = cardano.submit_tx(signed_tx.to_cbor()) + +print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") +print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") +print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") +print(f"Transaction submitted! ID: {result}") diff --git a/examples/more_examples/06_query_receive_address.py b/examples/more_examples/06_query_receive_address.py new file mode 100644 index 00000000..0a0a3aa6 --- /dev/null +++ b/examples/more_examples/06_query_receive_address.py @@ -0,0 +1,66 @@ +import os +import sys + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/1") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + +print(f"hash \t\t\t\t\t\t\t\t\t amount") +print( + "--------------------------------------------------------------------------------------" +) +for utxo in utxos: + tokens = "" + for token in utxo.amount: + if token.unit != "lovelace": + tokens += f"{token.quantity} {token.unit} + " + print( + f"{utxo.tx_hash}#{utxo.tx_index} \t {int(utxo.amount[0].quantity)/1000000} ADA [{tokens}]" + ) diff --git a/examples/more_examples/07_mint_nfts.py b/examples/more_examples/07_mint_nfts.py new file mode 100644 index 00000000..3f728257 --- /dev/null +++ b/examples/more_examples/07_mint_nfts.py @@ -0,0 +1,192 @@ +import os +import random +import sys +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +types = ["lion", "elephant", "panda", "sloth", "tiger", "wolf"] + +assets = [ + { + "name": "CHARACTER0001", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0002", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0003", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0004", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0005", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, +] + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +receive_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/1") +reeive_skey = ExtendedSigningKey.from_hdwallet(receive_key) +receive_address = Address( + payment_part=reeive_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +print(" ") +print(f"Derived address: {main_address}") +print(" ") +print(f"Receive address: {receive_address}") +print(" ") + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + +######################################################## +####### Generate Policy keys ####### +####### IF it doesn't exist ####### +######################################################## +if not exists(f"keys/policy.skey") and not exists(f"keys/policy.vkey"): + payment_key_pair = PaymentKeyPair.generate() + payment_signing_key = payment_key_pair.signing_key + payment_verification_key = payment_key_pair.verification_key + payment_signing_key.save(f"keys/policy.skey") + payment_verification_key.save(f"keys/policy.vkey") + + +######################################################## +####### Initiate Policy ####### +######################################################## +policy_signing_key = PaymentSigningKey.load(f"keys/policy.skey") +policy_verification_key = PaymentVerificationKey.load(f"keys/policy.vkey") +pub_key_policy = ScriptPubkey(policy_verification_key.hash()) + + +policy = ScriptAll([pub_key_policy]) + +policy_id = policy.hash() +policy_id_hex = policy_id.payload.hex() +native_scripts = [policy] + +my_asset = Asset() +my_nft = MultiAsset() + +metadata = {721: {policy_id_hex: {}}} + +asset_minted = [] + +for asset in assets: + asset_name = asset["name"] + asset_name_bytes = asset_name.encode("utf-8") + metadata[721][policy_id_hex][asset_name] = { + "name": asset_name, + "type": asset["type"], + "attack": asset["attack"], + "speed": asset["speed"], + "defense": asset["defense"], + "health": asset["health"], + } + nft1 = AssetName(asset_name_bytes) + my_asset[nft1] = 1 + + +my_nft[policy_id] = my_asset +builder.native_scripts = native_scripts + +auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) +builder.auxiliary_data = auxiliary_data + +builder.mint = my_nft + +min_val = min_lovelace( + cardano, output=TransactionOutput(receive_address, Value(0, my_nft)) +) + +builder.add_output(TransactionOutput(receive_address, Value(min_val, my_nft))) + + +builder.add_input_address(main_address) +signed_tx = builder.build_and_sign( + [payment_skey, policy_signing_key], change_address=main_address +) +result = cardano.submit_tx(signed_tx.to_cbor()) + +print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") +print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") +print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") +print(f"Transaction submitted! ID: {result}") diff --git a/examples/more_examples/08_burn_nfts.py b/examples/more_examples/08_burn_nfts.py new file mode 100644 index 00000000..aa057ce6 --- /dev/null +++ b/examples/more_examples/08_burn_nfts.py @@ -0,0 +1,181 @@ +import os +import random +import sys +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +types = ["lion", "elephant", "panda", "sloth", "tiger", "wolf"] + +assets = [ + { + "name": "CHARACTER0001", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0002", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0003", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0004", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, + { + "name": "CHARACTER0005", + "attack": str(random.randint(1, 70)), + "speed": str(random.randint(1, 70)), + "defense": str(random.randint(1, 70)), + "health": str(random.randint(1, 70)), + "type": random.choice(types), + }, +] + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +receive_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/1") +receive_skey = ExtendedSigningKey.from_hdwallet(receive_key) +receive_address = Address( + payment_part=receive_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +print(" ") +print(f"Derived address: {main_address}") +print(" ") +print(f"Receive address: {receive_address}") +print(" ") + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + +######################################################## +####### Generate Policy keys ####### +####### IF it doesn't exist ####### +######################################################## +if not exists(f"keys/policy.skey") and not exists(f"keys/policy.vkey"): + payment_key_pair = PaymentKeyPair.generate() + payment_signing_key = payment_key_pair.signing_key + payment_verification_key = payment_key_pair.verification_key + payment_signing_key.save(f"keys/policy.skey") + payment_verification_key.save(f"keys/policy.vkey") + + +######################################################## +####### Initiate Policy ####### +######################################################## +policy_signing_key = PaymentSigningKey.load(f"keys/policy.skey") +policy_verification_key = PaymentVerificationKey.load(f"keys/policy.vkey") +pub_key_policy = ScriptPubkey(policy_verification_key.hash()) + + +policy = ScriptAll([pub_key_policy]) + +policy_id = policy.hash() +policy_id_hex = policy_id.payload.hex() +native_scripts = [policy] + +my_asset = Asset() +my_nft = MultiAsset() + +metadata = {721: {policy_id_hex: {}}} + +asset_minted = [] + +for asset in assets: + asset_name = asset["name"] + asset_name_bytes = asset_name.encode("utf-8") + metadata[721][policy_id_hex][asset_name] = { + "name": asset_name, + "type": asset["type"], + "attack": asset["attack"], + "speed": asset["speed"], + "defense": asset["defense"], + "health": asset["health"], + } + nft1 = AssetName(asset_name_bytes) + my_asset[nft1] = -1 + +my_nft[policy_id] = my_asset +builder.native_scripts = native_scripts +builder.mint = my_nft + + +builder.add_input_address(receive_address) +signed_tx = builder.build_and_sign( + [receive_skey, policy_signing_key], change_address=receive_address +) +result = cardano.submit_tx(signed_tx.to_cbor()) + +print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") +print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") +print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") +print(f"Transaction submitted! ID: {result}") diff --git a/examples/more_examples/09_sign_document_data.py b/examples/more_examples/09_sign_document_data.py new file mode 100644 index 00000000..772a939a --- /dev/null +++ b/examples/more_examples/09_sign_document_data.py @@ -0,0 +1,117 @@ +import json +import os +import random +import sys +import urllib.request +from hashlib import sha256 +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv +from reportlab.pdfgen import canvas + +from pycardano import * + + +def split_into_64chars(string): + return [string[i : i + 64] for i in range(0, len(string), 64)] + + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +filename = "tempfile.pdf" +pdf = canvas.Canvas(filename) +pdf.drawString(100, 750, "Hello, this is an example PDF!") + +pdf.save() + + +h256 = sha256() +h256.update(open(filename, "rb").read()) +document_hash = h256.hexdigest() + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +payload = {"document_hash": document_hash} + +payload = str(payload) + +result = cip8.sign( + message=payload, + signing_key=payment_skey, + network=cardano_network, + attach_cose_key=True, +) + + +metadata = { + 1787: { + document_hash: { + "signature": split_into_64chars(result["signature"]), + } + } +} + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + +try: + utxos = api.address_utxos(main_address) +except Exception as e: + if e.status_code == 404: + print("Address does not have any UTXOs. ") + if network == "testnet": + print( + "Request tADA from the faucet: https://docs.cardano.org/cardano-testnets/tools/faucet/" + ) + else: + print(e.message) + sys.exit(1) + + +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +builder = TransactionBuilder(cardano) + + +auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata))) +builder.auxiliary_data = auxiliary_data + + +builder.add_input_address(main_address) +signed_tx = builder.build_and_sign([payment_skey], change_address=main_address) +result = cardano.submit_tx(signed_tx.to_cbor()) + +print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") +print(f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}") +print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") +print(f"Transaction submitted! ID: {result}") diff --git a/examples/more_examples/10_verify_document.py b/examples/more_examples/10_verify_document.py new file mode 100644 index 00000000..f3b19b3e --- /dev/null +++ b/examples/more_examples/10_verify_document.py @@ -0,0 +1,101 @@ +import json +import os +import random +import sys +import urllib.request +from hashlib import sha256 +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + + +def split_into_64chars(string): + return [string[i : i + 64] for i in range(0, len(string), 64)] + + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +prefix = "a401010327200621" +jsonkey = json.loads(payment_skey.to_verification_key().to_non_extended().to_json()) + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +# get commandline arguments + +transaction_id = sys.argv[1] +document_hash = sys.argv[2] + + +onchain_metadata = api.transaction_metadata(transaction_id) + +if onchain_metadata is None: + print("No metadata onchain.") + sys.exit(1) + + +if "1787" in onchain_metadata[0].label: + print("This transaction has a 1787 metadata label onchain.") + + result = onchain_metadata[0].json_metadata + + if document_hash in str(result): + print("Document hash found onchain.") + + if getattr(result, document_hash).signature: + print("Signature found onchain.") + signature = getattr(result, document_hash).signature + + public_key = f"{prefix}{jsonkey['cborHex']}" + + signed_message = { + "signature": "".join(signature), + "key": public_key, + } + + result = cip8.verify(signed_message=signed_message, attach_cose_key=True) + + if result["verified"]: + print( + "This signature is verified correctly, this document was signed by this wallet/identity." + ) + print("Original payload:") + print(result["message"]) + else: + print("This signature is NOT correct!") + else: + print("This transaction does not have a signatuer attribute") + else: + print(f"Document hash ({document_hash}) was not found in this transaction.") +else: + print("This transaction DOES NOT have a 1787 metadata label.") diff --git a/examples/more_examples/11_verify_fake_document.py b/examples/more_examples/11_verify_fake_document.py new file mode 100644 index 00000000..b199cc86 --- /dev/null +++ b/examples/more_examples/11_verify_fake_document.py @@ -0,0 +1,113 @@ +import json +import os +import random +import sys +import urllib.request +from hashlib import sha256 +from os.path import exists + +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv +from reportlab.pdfgen import canvas + +from pycardano import * + + +def split_into_64chars(string): + return [string[i : i + 64] for i in range(0, len(string), 64)] + + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +filename = "tempfile_copy.pdf" +pdf = canvas.Canvas(filename) +pdf.drawString(100, 750, "Hello, this is a copy of the example PDF!") + +pdf.save() + +h256 = sha256() +h256.update(open(filename, "rb").read()) +document_hash = h256.hexdigest() + +print(f"Trying to verify document with hash: {document_hash}") + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + + +prefix = "a401010327200621" +jsonkey = json.loads(payment_skey.to_verification_key().to_non_extended().to_json()) + + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +# get commandline arguments + +transaction_id = sys.argv[1] + + +onchain_metadata = api.transaction_metadata(transaction_id) + +if onchain_metadata is None: + print("No metadata onchain.") + sys.exit(1) + + +if "1787" in onchain_metadata[0].label: + print("This transaction has a 1787 metadata label onchain.") + + result = onchain_metadata[0].json_metadata + + if document_hash in str(result): + print("Document hash found onchain.") + + if getattr(result, document_hash).signature: + print("Signature found onchain.") + signature = getattr(result, document_hash).signature + + public_key = f"{prefix}{jsonkey['cborHex']}" + + signed_message = { + "signature": "".join(signature), + "key": public_key, + } + + result = cip8.verify(signed_message=signed_message, attach_cose_key=True) + + if result["verified"]: + print("This signature is verified correctly!") + if result["message"] == document_hash: + print("TargetHash matches as well! ") + else: + print("This signature is NOT correct!") + else: + print("This transaction does not have a signatuer attribute") + else: + print( + f"Document hash ({document_hash}) was not found in this transaction. Possible corruption." + ) +else: + print("This transaction DOES NOT have a 1787 metadata label.") diff --git a/examples/more_examples/12_transaction_chaining.py b/examples/more_examples/12_transaction_chaining.py new file mode 100644 index 00000000..3f0e53bd --- /dev/null +++ b/examples/more_examples/12_transaction_chaining.py @@ -0,0 +1,166 @@ +import os +import sys +import time + +import requests +from blockfrost import ApiError, ApiUrls, BlockFrostApi, BlockFrostIPFS +from dotenv import load_dotenv + +from pycardano import * + +load_dotenv() +network = os.getenv("network") +wallet_mnemonic = os.getenv("wallet_mnemonic") +blockfrost_api_key = os.getenv("blockfrost_api_key") + +utxos = [] + + +def reload_utxos(main_address): + global utxos + + print("Reloading utxos from Blockfrost") + + api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) + + local_utxos = api.address_utxos(main_address) + + utxos = [] + + for utxo in local_utxos: + if len(utxo.amount) == 1: + new_utxo = { + "tx_hash": utxo.tx_hash, + "tx_index": utxo.tx_index, + "amount": utxo.amount[0].quantity, + } + + utxos.append(new_utxo) + + +if network == "testnet": + base_url = ApiUrls.preprod.value + cardano_network = Network.TESTNET +else: + base_url = ApiUrls.mainnet.value + cardano_network = Network.MAINNET + + +new_wallet = crypto.bip32.HDWallet.from_mnemonic(wallet_mnemonic) +payment_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/0/0") +staking_key = new_wallet.derive_from_path(f"m/1852'/1815'/0'/2/0") +payment_skey = ExtendedSigningKey.from_hdwallet(payment_key) +staking_skey = ExtendedSigningKey.from_hdwallet(staking_key) + + +main_address = Address( + payment_part=payment_skey.to_verification_key().hash(), + staking_part=staking_skey.to_verification_key().hash(), + network=cardano_network, +) + +print(" ") +print(f"Derived address: {main_address}") +print(" ") + +api = BlockFrostApi(project_id=blockfrost_api_key, base_url=base_url) +cardano = BlockFrostChainContext(project_id=blockfrost_api_key, base_url=base_url) + +while True: + + if len(utxos) == 0: + reload_utxos(main_address) + + inputs = [] + outputs = [] + + if len(utxos) == 0: + print("No utxos available. Waiting 10 seconds...") + time.sleep(10) + continue + else: + + total_ada_used = 0 + for utxo in utxos: + + input = TransactionInput.from_primitive([utxo["tx_hash"], utxo["tx_index"]]) + + inputs.append(input) + total_ada_used += int(utxo["amount"]) + + for i in range(10): + output = TransactionOutput(main_address, Value(10000000)) + outputs.append(output) + + ada_leftovers = total_ada_used - (10 * 10000000) + + output = TransactionOutput(main_address, Value(ada_leftovers)) + outputs.append(output) + + tx_body_estimate = TransactionBody( + inputs=inputs, outputs=outputs, fee=1000000, ttl=72303971 + ) + vk_witnesses = [] + signature = payment_skey.sign(tx_body_estimate.hash()) + vk_witnesses.append( + VerificationKeyWitness(payment_skey.to_verification_key(), signature) + ) + + signed_tx = Transaction( + tx_body_estimate, TransactionWitnessSet(vkey_witnesses=vk_witnesses) + ) + + estimated_fee = fee(cardano, len(signed_tx.to_cbor())) + + ada_leftovers = total_ada_used - (10 * 10000000) - estimated_fee + + outputs = [] + for i in range(10): + output = TransactionOutput(main_address, Value(10000000)) + outputs.append(output) + + output = TransactionOutput(main_address, Value(ada_leftovers)) + outputs.append(output) + + tx_body_estimate = TransactionBody( + inputs=inputs, outputs=outputs, fee=estimated_fee, ttl=72303971 + ) + vk_witnesses = [] + signature = payment_skey.sign(tx_body_estimate.hash()) + vk_witnesses.append( + VerificationKeyWitness(payment_skey.to_verification_key(), signature) + ) + + signed_tx = Transaction( + tx_body_estimate, TransactionWitnessSet(vkey_witnesses=vk_witnesses) + ) + + try: + + result = cardano.submit_tx(signed_tx) + + if len(result) > 64: + print(signed_tx.to_cbor_hex()) + else: + + print(f"Number of inputs: \t {len(signed_tx.transaction_body.inputs)}") + print( + f"Number of outputs: \t {len(signed_tx.transaction_body.outputs)}" + ) + print(f"Fee: \t\t\t {signed_tx.transaction_body.fee/1000000} ADA") + print(f"Transaction submitted! ID: {result}") + + utxos = [] + + for i, output in enumerate(outputs): + new_utxo = { + "tx_hash": result, + "tx_index": i, + "amount": output.amount.coin, + } + + utxos.append(new_utxo) + + except Exception as e: + print(e) + reload_utxos(main_address) diff --git a/examples/more_examples/README.md b/examples/more_examples/README.md new file mode 100644 index 00000000..d94e7fa1 --- /dev/null +++ b/examples/more_examples/README.md @@ -0,0 +1,21 @@ +## Introduction into Cardano using PyCardano + +- [x] Derive addresses +- [x] Query address balance +- [x] Create transaction with multiple outputs +- [x] Consolidate all inputs back into 1 utxo +- [x] Mint a fungible asset within a policy and send it to an external address +- [x] Query the receiver address +- [x] Minting 5 NFT's with metadata (player characters in this example) +- [x] Burning NFT's +- [x] Downloading a document from a URL and signing it with CIP8 +- [x] Verify a valid CIP8 signature +- [x] Verify an invalid CIP8 signature +- [x] Example of transaction chaining with manually building and signing a transaction (instead of TransactionBuilder) + + +## How to use +- Clone repo +- rename .env-example to .env +- update values in .env +- play around! \ No newline at end of file diff --git a/examples/more_examples/keys/.gitkeep b/examples/more_examples/keys/.gitkeep new file mode 100644 index 00000000..e69de29b