简单直接,使用pycardano开发cardano nft。
准备
- python 3.8.8
- pycardano
- blockfrost api
开始代码
准备blockfrost 账号
import pathlib
from blockfrost import ApiUrls
from pycardano import *
#准备blockfrost 账号
BLOCK_FROST_PROJECT_ID = "......XXXXX"
NETWORK = Network.TESTNET
chain_context = BlockFrostChainContext(
project_id=BLOCK_FROST_PROJECT_ID,
base_url=ApiUrls.preview.value,
)
准备存放私公钥,policy文件
PROJECT_ROOT = "my_nft_stuff"
root = pathlib.Path(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 = 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))
定义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)))
提交到cardano测试网
# 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, policy_skey], change_address=address)
打印输出
print("############### Transaction created ###############")
print(signed_tx)
print(signed_tx.to_cbor())
# Submit signed transaction to the network
print("############### Submitting transaction ###############")
chain_context.submit_tx(signed_tx.to_cbor())
ok,成功。