ARC69 Minter and Modifier Part 2
Video Tutorial
Contract - User Mints and Claims Pokemon
Compile the contract using:
algokit compile arc69NFTmodifier.py
Python Code
from algopy import ARC4Contract, itxn, Global, GlobalState, UInt64, gtxn, Bytes, subroutine, String, BoxRef, Txn, op, LocalState, Account
from algopy.arc4 import abimethod, Struct, Address, Bool
from algopy.arc4 import UInt64 as arc4UInt64
from algopy.arc4 import String as arc4String
class availablePokemon(Struct):
pokemon_name: arc4String
pokemon_type: arc4String
pokemon_description: arc4String
pokemon_ipfs_hash: arc4String
class userPokemonInfo(Struct):
uid: arc4UInt64
owner: Address
asset_id: arc4UInt64
pokemon_id: arc4UInt64
level: arc4UInt64
exp: arc4UInt64
training: Bool
training_start_time: arc4UInt64
class arc69NFTmodifier(ARC4Contract):
def __init__(self) -> None:
self.pokemonUnitCounter = GlobalState(arc4UInt64(0))
self.pokemonCreated = GlobalState(arc4UInt64(0))
@subroutine
def itoa(self, i: UInt64) -> Bytes:
digits = Bytes(b"0123456789")
radix = digits.length
if i < radix:
return digits[i]
return self.itoa(i // radix) + digits[i % radix]
@abimethod
def registerNewPokemonData(
self,
pokemon_name: arc4String,
pokemon_type: arc4String,
pokemon_description: arc4String,
pokemon_ipfs_hash: arc4String,
payment_txn: gtxn.PaymentTransaction,
) -> arc4String:
assert payment_txn.receiver == Global.current_application_address
self.pokemonUnitCounter.value = arc4UInt64(self.pokemonUnitCounter.value.native + 1)
box_ref = BoxRef(key=self.pokemonUnitCounter.value.bytes)
value, exists = box_ref.maybe()
assert not exists
new_pokemon_info = availablePokemon(
pokemon_name=pokemon_name,
pokemon_type=pokemon_type,
pokemon_description=pokemon_description,
pokemon_ipfs_hash=pokemon_ipfs_hash
)
box_ref.create(size=new_pokemon_info.bytes.length)
box_ref.put(new_pokemon_info.bytes)
return arc4String('Pokemon Registered to Contract: ') + pokemon_name
Confirming User Mint
from algosdk.v2client.algod import AlgodClient
from algokit_utils import ApplicationClient
from algosdk.atomic_transaction_composer import AtomicTransactionComposer, AccountTransactionSigner, TransactionWithSigner
from algosdk.transaction import PaymentTxn
from algosdk.account import address_from_private_key
from pathlib import Path
from algosdk.abi import ABIType
from algosdk.encoding import decode_address
from dotenv import load_dotenv
from base64 import b64decode
import os
load_dotenv()
node_token = os.getenv('algod_token')
node_server = os.getenv('algod_server')
private_key = os.getenv('private_key')
algod_client = AlgodClient(node_token, node_server)
app_spec = Path(__file__).parent / './arc69NFTmodifier.arc32.json'
app_id = int(os.getenv('app_id'))
signer = AccountTransactionSigner(private_key=private_key)
address = address_from_private_key(private_key=private_key)
params = algod_client.suggested_params()
application_client = ApplicationClient(
algod_client=algod_client,
app_spec=app_spec,
app_id=app_id,
signer=signer,
sender=address,
suggested_params=params
)
atc = AtomicTransactionComposer()
decoded_address = decode_address(address)
pokemon_selected_box_name = decoded_address
uint64_coder = ABIType.from_string('(uint64)')
user_pokemon_selected = algod_client.application_box_by_name(app_id, pokemon_selected_box_name)['value']
b64_decoded_value = b64decode(user_pokemon_selected)
global_states = algod_client.application_info(app_id)['params']['global-state']
for key in global_states:
if b64decode(key['key']) == b'pokemonCreated':
current_uid = b64decode(key['value']['bytes'])
total_bytes = (7 * 8) + (32 * 2) + 1
box_cost = (total_bytes * 400) + 2500 + 102_000
mbr_fee_payment_tx_1 = PaymentTxn(
sender=address,
sp=params,
receiver=application_client.app_address,
amt=box_cost,
note='#1'
)
wrapped_payment_tx_1 = TransactionWithSigner(mbr_fee_payment_tx_1, signer)
box_ref_1 = b64_decoded_value # The pokemon selected #1 , #2, or #3
box_ref_2 = decoded_address # The users address decoded
box_ref_3 = current_uid + decoded_address # The next unique ID counter + the users address
application_client.compose_call(
atc,
call_abi_method='mintUserPokemon',
payment_txn=wrapped_payment_tx_1,
transaction_parameters={
'boxes':[[app_id, box_ref_1], [app_id, box_ref_2], [app_id, box_ref_3]]
}
)
results = atc.execute(algod_client, 2)
tx_ids = [results.tx_ids[i] for i in range(len(results.tx_ids))]
abi_results = [results.abi_results[i].return_value for i in range(len(results.abi_results))]
print(tx_ids)
print(abi_results)
Confirming User Claim
from algosdk.v2client.algod import AlgodClient
from algokit_utils import ApplicationClient
from algosdk.atomic_transaction_composer import AtomicTransactionComposer, AccountTransactionSigner, TransactionWithSigner
from algosdk.transaction import PaymentTxn, AssetTransferTxn
from algosdk.account import address_from_private_key
from pathlib import Path
from algosdk.abi import ABIType
from algosdk.encoding import decode_address
from dotenv import load_dotenv
from base64 import b64decode
import os
load_dotenv()
node_token = os.getenv('algod_token')
node_server = os.getenv('algod_server')
private_key = os.getenv('private_key')
algod_client = AlgodClient(node_token, node_server)
app_spec = Path(__file__).parent / './arc69NFTmodifier.arc32.json'
app_id = int(os.getenv('app_id'))
signer = AccountTransactionSigner(private_key=private_key)
address = address_from_private_key(private_key=private_key)
params = algod_client.suggested_params()
application_client = ApplicationClient(
algod_client=algod_client,
app_spec=app_spec,
app_id=app_id,
signer=signer,
sender=address,
suggested_params=params
)
atc = AtomicTransactionComposer()
decoded_address = decode_address(address)
mbr_fee_payment_tx_1 = PaymentTxn(
sender=address,
sp=params,
receiver=application_client.app_address,
amt=2000,
note='#1'
)
wrapped_payment_tx_1 = TransactionWithSigner(mbr_fee_payment_tx_1, signer)
atc.add_transaction(wrapped_payment_tx_1)
users_pokemon = 728462064
user_optin_tx = AssetTransferTxn(
sender=address,
receiver=address,
sp=params,
amt=0,
index=users_pokemon
)
wrapped_user_optin_tx = TransactionWithSigner(user_optin_tx, signer)
current_uid = (0).to_bytes(8, 'big')
box_ref_1 = current_uid + decoded_address
application_client.compose_call(
atc,
call_abi_method='claimPokemon',
opt_in_txn=wrapped_user_optin_tx,
uid=0,
transaction_parameters={
'boxes':[[app_id, box_ref_1]],
'foreign_assets': [users_pokemon]
}
)
results = atc.execute(algod_client, 2)
tx_ids = [results.tx_ids[i] for i in range(len(results.tx_ids))]
abi_results = [results.abi_results[i].return_value for i in range(len(results.abi_results))]
print(tx_ids)
print(abi_results)