def deregister_stake_addr( cluster_obj: clusterlib.ClusterLib, temp_template: str, txins: List[clusterlib.UTXOData], collaterals: List[clusterlib.UTXOData], pool_user: delegation.PoolUserScript, redeemer_file: Path, ) -> clusterlib.TxRawOutput: """Deregister stake address.""" src_payment_balance = cluster_obj.get_address_balance( pool_user.payment.address) reward_balance = cluster_obj.get_stake_addr_info( pool_user.stake.address).reward_account_balance # create stake address deregistration cert stake_addr_dereg_cert = cluster_obj.gen_stake_addr_deregistration_cert( addr_name=f"{temp_template}_addr0", stake_script_file=pool_user.stake.script_file, ) # withdraw rewards to payment address, deregister stake address withdrawal_script = clusterlib.ScriptWithdrawal( txout=clusterlib.TxOut(address=pool_user.stake.address, amount=-1), script_file=pool_user.stake.script_file, collaterals=[collaterals[0]], redeemer_file=redeemer_file, ) dereg_cert_script = clusterlib.ComplexCert( certificate_file=stake_addr_dereg_cert, script_file=pool_user.stake.script_file, collaterals=[collaterals[1]], redeemer_file=redeemer_file, ) tx_files = clusterlib.TxFiles( signing_key_files=[pool_user.payment.skey_file]) tx_raw_output = cluster_obj.build_tx( src_address=pool_user.payment.address, tx_name=f"{temp_template}_dereg_withdraw", txins=txins, tx_files=tx_files, complex_certs=[dereg_cert_script], fee_buffer=2_000_000, script_withdrawals=[withdrawal_script], witness_override=len(tx_files.signing_key_files), ) # calculate cost of Plutus script plutus_cost = cluster_obj.calculate_plutus_script_cost( src_address=pool_user.payment.address, tx_name=f"{temp_template}_dereg_withdraw", txins=txins, tx_files=tx_files, complex_certs=[dereg_cert_script], fee_buffer=2_000_000, script_withdrawals=[withdrawal_script], witness_override=len(tx_files.signing_key_files), ) tx_signed = cluster_obj.sign_tx( tx_body_file=tx_raw_output.out_file, signing_key_files=tx_files.signing_key_files, tx_name=f"{temp_template}_reg_deleg", ) cluster_obj.submit_tx(tx_file=tx_signed, txins=tx_raw_output.txins) # check that the key deposit was returned and rewards withdrawn assert ( cluster_obj.get_address_balance( pool_user.payment.address) == src_payment_balance - tx_raw_output.fee + reward_balance + cluster_obj.get_address_deposit() ), f"Incorrect balance for source address `{pool_user.payment.address}`" # check that the stake address is no longer delegated stake_addr_info = cluster_obj.get_stake_addr_info(pool_user.stake.address) assert not stake_addr_info.delegation, f"Stake address is still delegated: {stake_addr_info}" tx_db_dereg = dbsync_utils.check_tx(cluster_obj=cluster_obj, tx_raw_output=tx_raw_output) if tx_db_dereg: assert pool_user.stake.address in tx_db_dereg.stake_deregistration # compare cost of Plutus script with data from db-sync dbsync_utils.check_plutus_cost( redeemer_record=tx_db_dereg.redeemers[0], cost_record=plutus_cost[0]) return tx_raw_output
def delegate_stake_addr( cluster_obj: clusterlib.ClusterLib, temp_template: str, txins: List[clusterlib.UTXOData], collaterals: List[clusterlib.UTXOData], pool_user: delegation.PoolUserScript, pool_id: str, redeemer_file: Path, ) -> Tuple[clusterlib.TxRawOutput, List[dict]]: """Submit registration certificate and delegate to pool.""" # create stake address registration cert stake_addr_reg_cert_file = cluster_obj.gen_stake_addr_registration_cert( addr_name=f"{temp_template}_addr0", stake_script_file=pool_user.stake.script_file) # create stake address delegation cert stake_addr_deleg_cert_file = cluster_obj.gen_stake_addr_delegation_cert( addr_name=f"{temp_template}_addr0", stake_script_file=pool_user.stake.script_file, stake_pool_id=pool_id, ) src_init_balance = cluster_obj.get_address_balance( pool_user.payment.address) # register stake address and delegate it to pool reg_cert_script = clusterlib.ComplexCert( certificate_file=stake_addr_reg_cert_file, ) deleg_cert_script = clusterlib.ComplexCert( certificate_file=stake_addr_deleg_cert_file, script_file=pool_user.stake.script_file, collaterals=collaterals, redeemer_file=redeemer_file, ) tx_files = clusterlib.TxFiles( signing_key_files=[pool_user.payment.skey_file]) tx_raw_output = cluster_obj.build_tx( src_address=pool_user.payment.address, tx_name=f"{temp_template}_reg_deleg", txins=txins, tx_files=tx_files, complex_certs=[reg_cert_script, deleg_cert_script], fee_buffer=2_000_000, witness_override=len(tx_files.signing_key_files), ) # calculate cost of Plutus script plutus_cost = cluster_obj.calculate_plutus_script_cost( src_address=pool_user.payment.address, tx_name=f"{temp_template}_reg_deleg", txins=txins, tx_files=tx_files, complex_certs=[reg_cert_script, deleg_cert_script], fee_buffer=2_000_000, witness_override=len(tx_files.signing_key_files), ) tx_signed = cluster_obj.sign_tx( tx_body_file=tx_raw_output.out_file, signing_key_files=tx_files.signing_key_files, tx_name=f"{temp_template}_reg_deleg", ) cluster_obj.submit_tx(tx_file=tx_signed, txins=tx_raw_output.txins) # check that the balance for source address was correctly updated deposit = cluster_obj.get_address_deposit() assert ( cluster_obj.get_address_balance( pool_user.payment.address) == src_init_balance - deposit - tx_raw_output.fee ), f"Incorrect balance for source address `{pool_user.payment.address}`" # check that the stake address was delegated stake_addr_info = cluster_obj.get_stake_addr_info(pool_user.stake.address) assert stake_addr_info.delegation, f"Stake address was not delegated yet: {stake_addr_info}" assert pool_id == stake_addr_info.delegation, "Stake address delegated to wrong pool" return tx_raw_output, plutus_cost
def test_witness_redeemer( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord], key: str, ): """Test minting a token with a Plutus script. Uses `cardano-cli transaction build` command for building the transactions. * fund the token issuer and create a UTxO for collateral * check that the expected amount was transferred to token issuer's address * mint the token using a Plutus script with required signer * check that the token was minted and collateral UTxO was not spent * check expected fees * check expected Plutus cost * (optional) check transactions in db-sync """ # pylint: disable=too-many-locals temp_template = common.get_test_id(cluster) payment_addr = payment_addrs[0] issuer_addr = payment_addrs[1] lovelace_amount = 2_000_000 token_amount = 5 script_fund = 200_000_000 minting_cost = plutus_common.compute_cost( execution_cost=plutus_common.MINTING_WITNESS_REDEEMER_COST, protocol_params=cluster.get_protocol_params(), ) if key == "normal": redeemer_file = plutus_common.DATUM_WITNESS_GOLDEN_NORMAL signing_key_golden = plutus_common.SIGNING_KEY_GOLDEN else: redeemer_file = plutus_common.DATUM_WITNESS_GOLDEN_EXTENDED signing_key_golden = plutus_common.SIGNING_KEY_GOLDEN_EXTENDED issuer_init_balance = cluster.get_address_balance(issuer_addr.address) # Step 1: fund the token issuer mint_utxos, collateral_utxos, tx_output_step1 = _fund_issuer( cluster_obj=cluster, temp_template=temp_template, payment_addr=payment_addr, issuer_addr=issuer_addr, minting_cost=minting_cost, amount=script_fund, ) # Step 2: mint the "qacoin" policyid = cluster.get_policyid(plutus_common.MINTING_PLUTUS_V1) asset_name = f"qacoin{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token = f"{policyid}.{asset_name}" mint_txouts = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token) ] plutus_mint_data = [ clusterlib.Mint( txouts=mint_txouts, script_file=plutus_common.MINTING_PLUTUS_V1, collaterals=collateral_utxos, redeemer_file=redeemer_file, ) ] tx_files_step2 = clusterlib.TxFiles( signing_key_files=[issuer_addr.skey_file, signing_key_golden], ) txouts_step2 = [ clusterlib.TxOut(address=issuer_addr.address, amount=lovelace_amount), *mint_txouts, ] tx_output_step2 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, required_signers=[signing_key_golden], ) plutus_cost = cluster.calculate_plutus_script_cost( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, required_signers=[signing_key_golden], ) # sign incrementally (just to check that it works) tx_signed_step2 = cluster.sign_tx( tx_body_file=tx_output_step2.out_file, signing_key_files=[issuer_addr.skey_file], tx_name=f"{temp_template}_step2_sign0", ) tx_signed_step2_inc = cluster.sign_tx( tx_file=tx_signed_step2, signing_key_files=[signing_key_golden], tx_name=f"{temp_template}_step2_sign1", ) cluster.submit_tx(tx_file=tx_signed_step2_inc, txins=mint_utxos) assert ( cluster.get_address_balance( issuer_addr.address) == issuer_init_balance + minting_cost.collateral + lovelace_amount ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" token_utxo = cluster.get_utxo(address=issuer_addr.address, coins=[token]) assert token_utxo and token_utxo[ 0].amount == token_amount, "The token was not minted" # check expected fees expected_fee_step1 = 167_349 assert helpers.is_in_interval(tx_output_step1.fee, expected_fee_step1, frac=0.15) expected_fee_step2 = 372_438 assert helpers.is_in_interval(tx_output_step2.fee, expected_fee_step2, frac=0.15) plutus_common.check_plutus_cost( plutus_cost=plutus_cost, expected_cost=[plutus_common.MINTING_WITNESS_REDEEMER_COST], ) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step1) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step2)
def test_minting_context_equivalance( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Test context equivalence while minting a token. Uses `cardano-cli transaction build` command for building the transactions. * fund the token issuer and create a UTxO for collateral * check that the expected amount was transferred to token issuer's address * generate a dummy redeemer and a dummy Tx * derive the correct redeemer from the dummy Tx * mint the token using the derived redeemer * check that the token was minted and collateral UTxO was not spent * check expected Plutus cost * (optional) check transactions in db-sync """ # pylint: disable=too-many-locals,too-many-statements temp_template = common.get_test_id(cluster) payment_addr = payment_addrs[0] issuer_addr = payment_addrs[1] lovelace_amount = 2_000_000 token_amount = 5 script_fund = 200_000_000 minting_cost = plutus_common.compute_cost( execution_cost=plutus_common.MINTING_CONTEXT_EQUIVALENCE_COST, protocol_params=cluster.get_protocol_params(), ) issuer_init_balance = cluster.get_address_balance(issuer_addr.address) # Step 1: fund the token issuer mint_utxos, collateral_utxos, tx_output_step1 = _fund_issuer( cluster_obj=cluster, temp_template=temp_template, payment_addr=payment_addr, issuer_addr=issuer_addr, minting_cost=minting_cost, amount=script_fund, ) # Step 2: mint the "qacoin" invalid_hereafter = cluster.get_slot_no() + 1_000 policyid = cluster.get_policyid( plutus_common.MINTING_CONTEXT_EQUIVALENCE_PLUTUS_V1) asset_name = f"qacoin{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token = f"{policyid}.{asset_name}" mint_txouts = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token) ] tx_files_step2 = clusterlib.TxFiles(signing_key_files=[ issuer_addr.skey_file, plutus_common.SIGNING_KEY_GOLDEN ], ) txouts_step2 = [ clusterlib.TxOut(address=issuer_addr.address, amount=lovelace_amount), *mint_txouts, ] # generate a dummy redeemer in order to create a txbody from which # we can generate a tx and then derive the correct redeemer redeemer_file_dummy = Path( f"{temp_template}_dummy_script_context.redeemer") clusterlib_utils.create_script_context( cluster_obj=cluster, redeemer_file=redeemer_file_dummy) plutus_mint_data_dummy = [ clusterlib.Mint( txouts=mint_txouts, script_file=plutus_common. MINTING_CONTEXT_EQUIVALENCE_PLUTUS_V1, collaterals=collateral_utxos, redeemer_file=redeemer_file_dummy, ) ] tx_output_dummy = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_dummy", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data_dummy, required_signers=[plutus_common.SIGNING_KEY_GOLDEN], invalid_before=1, invalid_hereafter=invalid_hereafter, script_valid=False, ) assert tx_output_dummy tx_file_dummy = cluster.sign_tx( tx_body_file=tx_output_dummy.out_file, signing_key_files=tx_files_step2.signing_key_files, tx_name=f"{temp_template}_dummy", ) # generate the "real" redeemer redeemer_file = Path(f"{temp_template}_script_context.redeemer") try: clusterlib_utils.create_script_context(cluster_obj=cluster, redeemer_file=redeemer_file, tx_file=tx_file_dummy) except AssertionError as err: err_msg = str(err) if "DeserialiseFailure" in err_msg: pytest.xfail("DeserialiseFailure: see issue #944") if "TextEnvelopeTypeError" in err_msg and cluster.use_cddl: # noqa: SIM106 pytest.xfail( "TextEnvelopeTypeError: `create-script-context` doesn't work with CDDL format" ) else: raise plutus_mint_data = [ plutus_mint_data_dummy[0]._replace(redeemer_file=redeemer_file) ] tx_output_step2 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, required_signers=[plutus_common.SIGNING_KEY_GOLDEN], invalid_before=1, invalid_hereafter=invalid_hereafter, ) # calculate cost of Plutus script plutus_cost_step2 = cluster.calculate_plutus_script_cost( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, required_signers=[plutus_common.SIGNING_KEY_GOLDEN], invalid_before=1, invalid_hereafter=invalid_hereafter, ) tx_signed_step2 = cluster.sign_tx( tx_body_file=tx_output_step2.out_file, signing_key_files=tx_files_step2.signing_key_files, tx_name=f"{temp_template}_step2", ) cluster.submit_tx(tx_file=tx_signed_step2, txins=mint_utxos) assert ( cluster.get_address_balance( issuer_addr.address) == issuer_init_balance + minting_cost.collateral + lovelace_amount ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" token_utxo = cluster.get_utxo(address=issuer_addr.address, coins=[token]) assert token_utxo and token_utxo[ 0].amount == token_amount, "The token was not minted" plutus_common.check_plutus_cost( plutus_cost=plutus_cost_step2, expected_cost=[plutus_common.MINTING_CONTEXT_EQUIVALENCE_COST], ) # check tx_view tx_view.check_tx_view(cluster_obj=cluster, tx_raw_output=tx_output_step2) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step1) tx_db_record_step2 = dbsync_utils.check_tx( cluster_obj=cluster, tx_raw_output=tx_output_step2) # compare cost of Plutus script with data from db-sync if tx_db_record_step2: dbsync_utils.check_plutus_cost( redeemer_record=tx_db_record_step2.redeemers[0], cost_record=plutus_cost_step2[0])
def test_two_scripts_minting( self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Test minting two tokens with two different Plutus scripts. Uses `cardano-cli transaction build` command for building the transactions. * fund the token issuer and create a UTxO for collaterals * check that the expected amount was transferred to token issuer's address * mint the tokens using two different Plutus scripts * check that the tokens were minted and collateral UTxOs were not spent * check transaction view output * check expected fees * check expected Plutus cost * (optional) check transactions in db-sync """ # pylint: disable=too-many-locals,too-many-statements temp_template = common.get_test_id(cluster) payment_addr = payment_addrs[0] issuer_addr = payment_addrs[1] lovelace_amount = 2_000_000 token_amount = 5 script_fund = 500_000_000 # this is higher than `plutus_common.MINTING*_COST`, because the script context has changed # to include more stuff minting_cost_two = plutus_common.ExecutionCost(per_time=408_545_501, per_space=1_126_016, fixed_cost=94_428) minting_time_range_cost_two = plutus_common.ExecutionCost( per_time=427_707_230, per_space=1_188_952, fixed_cost=99_441) protocol_params = cluster.get_protocol_params() minting_cost1 = plutus_common.compute_cost( execution_cost=minting_cost_two, protocol_params=protocol_params) minting_cost2 = plutus_common.compute_cost( execution_cost=minting_time_range_cost_two, protocol_params=protocol_params) issuer_init_balance = cluster.get_address_balance(issuer_addr.address) # Step 1: fund the token issuer tx_files_step1 = clusterlib.TxFiles( signing_key_files=[payment_addr.skey_file], ) txouts_step1 = [ clusterlib.TxOut(address=issuer_addr.address, amount=script_fund), # for collaterals clusterlib.TxOut(address=issuer_addr.address, amount=minting_cost1.collateral), clusterlib.TxOut(address=issuer_addr.address, amount=minting_cost2.collateral), ] tx_output_step1 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step1", tx_files=tx_files_step1, txouts=txouts_step1, fee_buffer=2_000_000, # don't join 'change' and 'collateral' txouts, we need separate UTxOs join_txouts=False, ) tx_signed_step1 = cluster.sign_tx( tx_body_file=tx_output_step1.out_file, signing_key_files=tx_files_step1.signing_key_files, tx_name=f"{temp_template}_step1", ) cluster.submit_tx(tx_file=tx_signed_step1, txins=tx_output_step1.txins) issuer_step1_balance = cluster.get_address_balance(issuer_addr.address) assert ( issuer_step1_balance == issuer_init_balance + script_fund + minting_cost1.collateral + minting_cost2.collateral ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" # Step 2: mint the "qacoins" txid_step1 = cluster.get_txid(tx_body_file=tx_output_step1.out_file) mint_utxos = cluster.get_utxo(txin=f"{txid_step1}#1") collateral_utxo1 = cluster.get_utxo(txin=f"{txid_step1}#2") collateral_utxo2 = cluster.get_utxo(txin=f"{txid_step1}#3") slot_step2 = cluster.get_slot_no() # "time range" qacoin slots_offset = 200 timestamp_offset_ms = int(slots_offset * cluster.slot_length + 5) * 1_000 protocol_version = cluster.get_protocol_params( )["protocolVersion"]["major"] if protocol_version > 5: # POSIX timestamp + offset redeemer_value_timerange = ( int(datetime.datetime.now().timestamp() * 1_000) + timestamp_offset_ms) else: # BUG: https://github.com/input-output-hk/cardano-node/issues/3090 redeemer_value_timerange = 1_000_000_000_000 policyid_timerange = cluster.get_policyid( plutus_common.MINTING_TIME_RANGE_PLUTUS_V1) asset_name_timerange = f"qacoint{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token_timerange = f"{policyid_timerange}.{asset_name_timerange}" mint_txouts_timerange = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token_timerange) ] # "anyone can mint" qacoin redeemer_cbor_file = plutus_common.REDEEMER_42_CBOR policyid_anyone = cluster.get_policyid(plutus_common.MINTING_PLUTUS_V1) asset_name_anyone = f"qacoina{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token_anyone = f"{policyid_anyone}.{asset_name_anyone}" mint_txouts_anyone = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token_anyone) ] # mint the tokens plutus_mint_data = [ clusterlib.Mint( txouts=mint_txouts_timerange, script_file=plutus_common.MINTING_TIME_RANGE_PLUTUS_V1, collaterals=collateral_utxo1, redeemer_value=str(redeemer_value_timerange), ), clusterlib.Mint( txouts=mint_txouts_anyone, script_file=plutus_common.MINTING_PLUTUS_V1, collaterals=collateral_utxo2, redeemer_cbor_file=redeemer_cbor_file, ), ] tx_files_step2 = clusterlib.TxFiles( signing_key_files=[issuer_addr.skey_file], ) txouts_step2 = [ clusterlib.TxOut(address=issuer_addr.address, amount=lovelace_amount), *mint_txouts_timerange, *mint_txouts_anyone, ] tx_output_step2 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, invalid_before=slot_step2 - slots_offset, invalid_hereafter=slot_step2 + slots_offset, ) plutus_cost = cluster.calculate_plutus_script_cost( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, invalid_before=slot_step2 - slots_offset, invalid_hereafter=slot_step2 + slots_offset, ) tx_signed_step2 = cluster.sign_tx( tx_body_file=tx_output_step2.out_file, signing_key_files=tx_files_step2.signing_key_files, tx_name=f"{temp_template}_step2", ) cluster.submit_tx(tx_file=tx_signed_step2, txins=mint_utxos) assert ( cluster.get_address_balance( issuer_addr.address) == issuer_init_balance + minting_cost1.collateral + minting_cost2.collateral + lovelace_amount ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" token_utxo_timerange = cluster.get_utxo(address=issuer_addr.address, coins=[token_timerange]) assert (token_utxo_timerange and token_utxo_timerange[0].amount == token_amount), "The 'timerange' token was not minted" token_utxo_anyone = cluster.get_utxo(address=issuer_addr.address, coins=[token_anyone]) assert (token_utxo_anyone and token_utxo_anyone[0].amount == token_amount), "The 'anyone' token was not minted" # check expected fees expected_fee_step1 = 168_977 assert helpers.is_in_interval(tx_output_step1.fee, expected_fee_step1, frac=0.15) expected_fee_step2 = 633_269 assert helpers.is_in_interval(tx_output_step2.fee, expected_fee_step2, frac=0.15) plutus_common.check_plutus_cost( plutus_cost=plutus_cost, expected_cost=[minting_cost_two, minting_time_range_cost_two], ) # check tx_view tx_view.check_tx_view(cluster_obj=cluster, tx_raw_output=tx_output_step2) # check transactions in db-sync dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step1) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step2)
def test_time_range_minting(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Test minting a token with a time constraints Plutus script. Uses `cardano-cli transaction build` command for building the transactions. * fund the token issuer and create a UTxO for collateral * check that the expected amount was transferred to token issuer's address * mint the token using a Plutus script * check that the token was minted and collateral UTxO was not spent * check expected fees * check expected Plutus cost * (optional) check transactions in db-sync """ # pylint: disable=too-many-locals temp_template = common.get_test_id(cluster) payment_addr = payment_addrs[0] issuer_addr = payment_addrs[1] lovelace_amount = 2_000_000 token_amount = 5 script_fund = 200_000_000 minting_cost = plutus_common.compute_cost( execution_cost=plutus_common.MINTING_TIME_RANGE_COST, protocol_params=cluster.get_protocol_params(), ) issuer_init_balance = cluster.get_address_balance(issuer_addr.address) # Step 1: fund the token issuer mint_utxos, collateral_utxos, tx_output_step1 = _fund_issuer( cluster_obj=cluster, temp_template=temp_template, payment_addr=payment_addr, issuer_addr=issuer_addr, minting_cost=minting_cost, amount=script_fund, ) # Step 2: mint the "qacoin" slot_step2 = cluster.get_slot_no() slots_offset = 200 timestamp_offset_ms = int(slots_offset * cluster.slot_length + 5) * 1_000 protocol_version = cluster.get_protocol_params( )["protocolVersion"]["major"] if protocol_version > 5: # POSIX timestamp + offset redeemer_value = int(datetime.datetime.now().timestamp() * 1_000) + timestamp_offset_ms else: # BUG: https://github.com/input-output-hk/cardano-node/issues/3090 redeemer_value = 1_000_000_000_000 policyid = cluster.get_policyid( plutus_common.MINTING_TIME_RANGE_PLUTUS_V1) asset_name = f"qacoin{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token = f"{policyid}.{asset_name}" mint_txouts = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token) ] plutus_mint_data = [ clusterlib.Mint( txouts=mint_txouts, script_file=plutus_common.MINTING_TIME_RANGE_PLUTUS_V1, collaterals=collateral_utxos, redeemer_value=str(redeemer_value), ) ] tx_files_step2 = clusterlib.TxFiles( signing_key_files=[issuer_addr.skey_file], ) txouts_step2 = [ clusterlib.TxOut(address=issuer_addr.address, amount=lovelace_amount), *mint_txouts, ] tx_output_step2 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, invalid_before=slot_step2 - slots_offset, invalid_hereafter=slot_step2 + slots_offset, ) plutus_cost = cluster.calculate_plutus_script_cost( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, invalid_before=slot_step2 - slots_offset, invalid_hereafter=slot_step2 + slots_offset, ) tx_signed_step2 = cluster.sign_tx( tx_body_file=tx_output_step2.out_file, signing_key_files=tx_files_step2.signing_key_files, tx_name=f"{temp_template}_step2", ) cluster.submit_tx(tx_file=tx_signed_step2, txins=mint_utxos) assert ( cluster.get_address_balance( issuer_addr.address) == issuer_init_balance + minting_cost.collateral + lovelace_amount ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" token_utxo = cluster.get_utxo(address=issuer_addr.address, coins=[token]) assert token_utxo and token_utxo[ 0].amount == token_amount, "The token was not minted" # check expected fees expected_fee_step1 = 167_349 assert helpers.is_in_interval(tx_output_step1.fee, expected_fee_step1, frac=0.15) expected_fee_step2 = 411_175 assert helpers.is_in_interval(tx_output_step2.fee, expected_fee_step2, frac=0.15) plutus_common.check_plutus_cost( plutus_cost=plutus_cost, expected_cost=[plutus_common.MINTING_TIME_RANGE_COST], ) # check tx_view tx_view.check_tx_view(cluster_obj=cluster, tx_raw_output=tx_output_step2) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step1) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step2)
def test_minting_one_token(self, cluster: clusterlib.ClusterLib, payment_addrs: List[clusterlib.AddressRecord]): """Test minting a token with a Plutus script. Uses `cardano-cli transaction build` command for building the transactions. * fund the token issuer and create a UTxO for collateral * check that the expected amount was transferred to token issuer's address * mint the token using a Plutus script * check that the token was minted and collateral UTxO was not spent * check expected fees * check expected Plutus cost * (optional) check transactions in db-sync """ # pylint: disable=too-many-locals temp_template = common.get_test_id(cluster) payment_addr = payment_addrs[0] issuer_addr = payment_addrs[1] lovelace_amount = 2_000_000 token_amount = 5 script_fund = 200_000_000 minting_cost = plutus_common.compute_cost( execution_cost=plutus_common.MINTING_COST, protocol_params=cluster.get_protocol_params()) issuer_init_balance = cluster.get_address_balance(issuer_addr.address) # Step 1: fund the token issuer and create UTXO for collaterals mint_utxos, collateral_utxos, tx_output_step1 = _fund_issuer( cluster_obj=cluster, temp_template=temp_template, payment_addr=payment_addr, issuer_addr=issuer_addr, minting_cost=minting_cost, amount=script_fund, collateral_utxo_num=2, ) # Step 2: mint the "qacoin" policyid = cluster.get_policyid(plutus_common.MINTING_PLUTUS_V1) asset_name = f"qacoin{clusterlib.get_rand_str(4)}".encode( "utf-8").hex() token = f"{policyid}.{asset_name}" mint_txouts = [ clusterlib.TxOut(address=issuer_addr.address, amount=token_amount, coin=token) ] plutus_mint_data = [ clusterlib.Mint( txouts=mint_txouts, script_file=plutus_common.MINTING_PLUTUS_V1, collaterals=collateral_utxos, redeemer_file=plutus_common.REDEEMER_42, ) ] tx_files_step2 = clusterlib.TxFiles( signing_key_files=[issuer_addr.skey_file], ) txouts_step2 = [ clusterlib.TxOut(address=issuer_addr.address, amount=lovelace_amount), *mint_txouts, ] tx_output_step2 = cluster.build_tx( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, ) plutus_cost = cluster.calculate_plutus_script_cost( src_address=payment_addr.address, tx_name=f"{temp_template}_step2", tx_files=tx_files_step2, txins=mint_utxos, txouts=txouts_step2, mint=plutus_mint_data, ) tx_signed_step2 = cluster.sign_tx( tx_body_file=tx_output_step2.out_file, signing_key_files=tx_files_step2.signing_key_files, tx_name=f"{temp_template}_step2", ) cluster.submit_tx(tx_file=tx_signed_step2, txins=mint_utxos) assert ( cluster.get_address_balance( issuer_addr.address) == issuer_init_balance + minting_cost.collateral + lovelace_amount ), f"Incorrect balance for token issuer address `{issuer_addr.address}`" token_utxo = cluster.get_utxo(address=issuer_addr.address, coins=[token]) assert token_utxo and token_utxo[ 0].amount == token_amount, "The token was not minted" # check expected fees expected_fee_step1 = 168_977 assert helpers.is_in_interval(tx_output_step1.fee, expected_fee_step1, frac=0.15) expected_fee_step2 = 371_111 assert helpers.is_in_interval(tx_output_step2.fee, expected_fee_step2, frac=0.15) plutus_common.check_plutus_cost( plutus_cost=plutus_cost, expected_cost=[plutus_common.MINTING_COST], ) # check tx_view tx_view.check_tx_view(cluster_obj=cluster, tx_raw_output=tx_output_step2) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step1) dbsync_utils.check_tx(cluster_obj=cluster, tx_raw_output=tx_output_step2)