I am trying to use the https://github.com/Python-Cardano/pycardano/blob/main/examples/native_token.py with minor changes, like pointing to mainnet (have tried preview as well). I have updated the address to point to my actual wallet and trying to create an nft. I am getting the below error
File "\Desktop\CDrive\work\Python3.7\lib\site-packages\pycardano\backend\blockfrost.py", line 230, in submit_tx self.api.transaction_submit(f.name) File "\Desktop\CDrive\work\Python3.7\lib\site-packages\blockfrost\utils.py", line 63, in error_wrapper raise ApiError(request_response) blockfrost.utils.ApiError: {'error': 'Bad Request', 'message': '"transaction read error RawCborDecodeError [DecoderErrorDeserialiseFailure \"Byron Tx\" (DeserialiseFailure 1 \"Size mismatch when decoding TxAux.\\nExpected 2, but found 4.\"),DecoderErrorDeserialiseFailure \"Shelley Tx\" (DeserialiseFailure 1 \"Size mismatch when decoding \\nRecord RecD.\\nExpected 4, but found 3.\"),DecoderErrorDeserialiseFailure \"Shelley Tx\" (DeserialiseFailure 1 \"Size mismatch when decoding \\nRecord RecD.\\nExpected 4, but found 3.\"),DecoderErrorDeserialiseFailure \"Shelley Tx\" (DeserialiseFailure 1 \"Size mismatch when decoding \\nRecord RecD.\\nExpected 4, but found 3.\"),DecoderErrorDeserialiseFailure \"Shelley Tx\" (DeserialiseFailure 79 \"expected string\"),DecoderErrorDeserialiseFailure \"Shelley Tx\" (DeserialiseFailure 79 \"expected string\")]"', 'status_code': 400}
I am not sure what is wrong, would be of great help if anyone can guide me to get it working. The same code minor change has given have also faced " File "\Desktop\CDrive\work\Python3.7\lib\tempfile.py", line 481, in func_wrapper return func(*args, **kwargs) TypeError: a bytes-like object is required, not 'Transaction'"
Below is the full python file
""" This is a complete walk through of minting a NFT on Cardano blockchain in pure Python code.
This example is inspired by https://developers.cardano.org/docs/native-tokens/minting-nfts#crafting-the-transaction
import pathlib
from blockfrost import ApiUrls
from pycardano import *
Copy your BlockFrost project ID below. Go to https://blockfrost.io/ for more information.
BLOCK_FROST_PROJECT_ID = "" NETWORK = Network.MAINNET
chain_context = BlockFrostChainContext( project_id=BLOCK_FROST_PROJECT_ID, base_url=ApiUrls.mainnet.value, #ApiUrls.preprod.value, )
"""Preparation"""
Define the root directory where images and keys will be stored.
PROJECT_ROOT = "blockfrost" root = pathlib.Path(PROJECT_ROOT) print(PROJECT_ROOT)
Create the directory if it doesn't exist
root.mkdir(parents=True, exist_ok=True)
"""Generate keys""" key_dir = root / "keys" key_dir.mkdir(exist_ok=True)
Load payment keys or create them if they don't exist
def load_or_create_key_pair(base_dir, base_name): skey_path = base_dir / f"{base_name}.skey" vkey_path = base_dir / f"{base_name}.vkey"
if skey_path.exists():
skey = PaymentSigningKey.load(str(skey_path))
vkey = PaymentVerificationKey.from_signing_key(skey)
else:
key_pair = PaymentKeyPair.generate()
key_pair.signing_key.save(str(skey_path))
key_pair.verification_key.save(str(vkey_path))
skey = key_pair.signing_key
vkey = key_pair.verification_key
return skey, vkey
Payment address. Send some ADA (~5 ADA is enough) to this address, so we can pay the minting fee later.
payment_skey, payment_vkey = load_or_create_key_pair(key_dir, "payment") address = "<myWalletAddress"
address = Address(payment_vkey.hash(), network=NETWORK)
#"addr_test1qqxypmc96e3pska6ch2ucq4uv5d7uz6nhpgcne4ea4hgmemv40lpm3wmc3wqk5arjpgzrccm0m9k72puaqzwsgrj47asmp86u7" #Address(payment_vkey.hash(), network=NETWORK)
print(address)
Generate policy keys, which will be used when minting NFT
policy_skey, policy_vkey = load_or_create_key_pair(key_dir, "policy")
"""Create policy"""
A policy that requires a signature from the policy key we generated above
pub_key_policy = ScriptPubkey(policy_vkey.hash())
A time policy that disallows token minting after 10000 seconds from last block
must_before_slot = InvalidHereAfter(chain_context.last_block_slot + 10000)
Combine two policies using ScriptAll policy
policy = ScriptAll([pub_key_policy, must_before_slot])
Calculate policy ID, which is the hash of the policy
policy_id = policy.hash() print(f"Policy ID: {policy_id}") with open(root / "policy.id", "a+") as f: f.truncate(0) f.write(str(policy_id)) #****************************************************************************************************************************************** """Define NFT"""
Create an asset container
my_asset = Asset()
Create names for our assets
nft1 = AssetName(b"MY_NFT_1") nft2 = AssetName(b"MY_NFT_2")
Put assets into the asset container with a quantity of 1
my_asset[nft1] = 1 my_asset[nft2] = 1
Create a MultiAsset container
my_nft = MultiAsset()
Put assets into MultiAsset container. In this example, we only have one policy.
However, MultiAsset container can hold multiple different policies.
my_nft[policy_id] = my_asset
Create the final native script that will be attached to the transaction
native_scripts = [policy] #****************************************************************************************************************************************** """Define NFT (Alternative)"""
The nft definition above is somewhat verbose.
We can also directly create native assets from python primitives.
my_nft_alternative = MultiAsset.from_primitive( { policy_id.payload: { # Use policy ID created from above. We can't use policy_id here because policy_id's type # is ScriptHash, which is not a primitive type. Instead, we use policy_id.payload (bytes) b"MY_NFT_1": 1, # Name of our NFT1 # Quantity of this NFT b"MY_NFT_2": 1, # Name of our NFT2 # Quantity of this NFT } } )
my_nft and my_nft_alternative are equivalent
assert my_nft == my_nft_alternative #****************************************************************************************************************************************** """Create metadata"""
We need to create a metadata for our NFTs, so they could be displayed correctly by blockchain explorer
metadata = { 721: { # 721 refers to the metadata label registered for NFT standard here: # https://github.com/cardano-foundation/CIPs/blob/master/CIP-0010/registry.json#L14-L17 policy_id.payload.hex(): { "MY_NFT_1": { "description": "This is my first NFT thanks to PyCardano", "name": "PyCardano NFT example token 1", "id": 1, "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", }, "MY_NFT_2": { "description": "This is my second NFT thanks to PyCardano", "name": "PyCardano NFT example token 2", "id": 2, "image": "ipfs://QmRhTTbUrPYEw3mJGGhQqQST9k86v1DPBiTTWJGKDJsVFw", }, } } }
Place metadata in AuxiliaryData, the format acceptable by a transaction.
auxiliary_data = AuxiliaryData(AlonzoMetadata(metadata=Metadata(metadata)))
"""Build transaction"""
Create a transaction builder
builder = TransactionBuilder(chain_context)
Add our own address as the input address
builder.add_input_address(address)
Since an InvalidHereAfter rule is included in the policy, we must specify time to live (ttl) for this transaction
builder.ttl = must_before_slot.after
Set nft we want to mint
builder.mint = my_nft
Set native script
builder.native_scripts = native_scripts
Set transaction metadata
builder.auxiliary_data = auxiliary_data
Calculate the minimum amount of lovelace that need to hold the NFT we are going to mint
min_val = min_lovelace( chain_context, output=TransactionOutput(address, Value(0, my_nft)) )
Send the NFT to our own address
builder.add_output(TransactionOutput(address, Value(min_val, my_nft)))
Create final signed transaction
signed_tx = builder.build_and_sign([payment_skey], change_address=address)
signed_tx = builder.build_and_sign([payment_skey, policy_skey], change_address=address)
print("############### Transaction created ###############") print("------------------------------Signed transaction------------------------------") print(signed_tx) print("-------------------------------------Signed to CBOR------------------------------") print(signed_tx.to_cbor())
Submit signed transaction to the network
print("############### Submitting transaction ###############")
chain_context.submit_tx(signed_tx)