环境/api
- Python 3.8.8
- blockfrost
安装pycardano
pip install pycardano
cardano的设计模式是etuxo,所以他的销毁token/asset方式算是比较简单的,这里用 pycardano做的example;官方没有实际的例子,但是也可以做,需要修改一处源码;很简单的,就是注释掉几行代码就可以。
完整的代码最后给出,这里说明下几个要注意的点
销毁token的数量
my_asset = Asset()
# Create names for our assets
token = AssetName(b"..输入你要删除的token/asset名字")
my_asset[token] = -1
你要销毁几个那么my_asset[token]就等于几。这里我们就销毁一个,输入-1。当然NFT,如果你的钱包里只有一个,那么你不能输入-2。销毁数量不能大于你所拥有的量。
下面是定义output,注意这里我们优定义了一个my_asset_[token] ,赋值0,因为我有一个,销毁一个,那么output就是0了。同样的如果你有5个销毁3个,那么这里就要设置2。千万别搞错了,否则就不会成功。 (如果对于output和input有不了解建议要仔细看看他的eutxo,这个是cardano的核心设计。后面看有什么关联的知识点的时候,我再详细说明。)
my_asset_ = Asset()
my_asset_[token] = 0
my_nft_ = MultiAsset()
my_nft_[policy_id] = my_asset_
# Send the NFT to our own address
builder.add_output(TransactionOutput(address, Value(min_val, my_nft_)))
修改pycardano源码
版本
pycardano 0.7.2
my_asset[token] = -1 其实会报错,pycardano这里有个非负数检查。他源码中没有考虑到销毁的场景。
修改pycardano/transaction.py", line 396。 按照下面的样子修改,注释掉负数的检查。
def validate_burn(self):
if isinstance(self.amount, int) and self.amount < 0:
raise InvalidDataException(
f"Transaction output cannot have negative amount of ADA or "
f"native asset: \n {self.amount}"
)
# if isinstance(self.amount, Value) and (
# self.amount.coin < 0
# or self.amount.multi_asset.count(lambda p, n, v: v < 0) > 0
# ):
# raise InvalidDataException(
# f"Transaction output cannot have negative amount of ADA or "
# f"native asset: \n {self.amount}"
# )
ok,其他的没有啥需要注意的和坑了。全部代码如下。
import pathlib
from blockfrost import ApiUrls
from pycardano import *
import step1_2 as s12
import step_3 as s3
import step4 as s4
BLOCK_FROST_PROJECT_ID = "输入blockfrost API"
NETWORK = Network.TESTNET
chain_context = BlockFrostChainContext(
project_id=BLOCK_FROST_PROJECT_ID,
# base_url=ApiUrls.preprod.value,
base_url=ApiUrls.preview.value,
)
"""Preparation"""
# Define the root directory where images and keys will be stored.
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(10753386)
# 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()
my_asset = Asset()
# Create names for our assets
token = AssetName(b"")
my_asset[token] = -1
my_nft = MultiAsset()
my_nft[policy_id] = my_asset
native_scripts = [policy]
# 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
# 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))
)
my_asset_ = Asset()
my_asset_[token] = 0
my_nft_ = MultiAsset()
my_nft_[policy_id] = my_asset_
# 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())
import time
def init():
policy_id = policy.hash()
print(f"Policy ID: {policy_id}")
if __name__ == "__main__":
print("process ...")
init()