pycardano: Blockfrost ApiError 5 ADA redeeming transaction fortytwo.py example
Describe the bug Sending 10ADA to the fortytwo plutus script on TESTNET works fine. However, when I attempt to redeem 5ADA from the plutus script I get a blockfrost ApiError.
To Reproduce fortytwo_test.py script under Additional context
Logs Traceback (most recent call last): File “fortytwo_test.py”, line 120, in <module> submit_tx(signed_tx) File “fortytwo_test.py”, line 42, in submit_tx chain_context.submit_tx(tx.to_cbor()) File “/home/zlac116/anaconda3/envs/cardanopy/lib/python3.8/site-packages/pycardano/backend/blockfrost.py”, line 205, in submit_tx self.api.transaction_submit(f.name) File “/home/zlac116/anaconda3/envs/cardanopy/lib/python3.8/site-packages/blockfrost/utils.py”, line 63, in error_wrapper raise ApiError(request_response) blockfrost.utils.ApiError: {‘error’: ‘Bad Request’, ‘message’: ‘“transaction submit error ShelleyTxValidationError ShelleyBasedEraBabbage (ApplyTxError [UtxowFailure (FromAlonzoUtxowFail (PPViewHashesDontMatch (SJust (SafeHash \“0067cdab1a1ae15069bf96bd33cbc059ec3a8677ab198b56081e6716016b0410\”)) (SJust (SafeHash \“2b25c2e22a3a08ca6d9fa0bcf299dff8ab2d5cbe06d5c2c5e255af46bb16cafd\”))))])”’, ‘status_code’: 400}
Expected behavior 5ADA is sent to the taker address
Environment and software version (please complete the following information):
- OS: Ubuntu 20.04.3 LTS
- PyCardano Version 0.6.0
- Python Version 3.8.12
Additional context python script: fortytwo_test.py
'''
Off-chain code of taker and giver in fortytwo
'''
import os
import cbor2
from retry import retry
from dotenv import load_dotenv
import pycardano as pc
load_dotenv()
NETWORK = pc.Network.TESTNET
def get_env_val(key):
val = os.getenv(key)
if not val:
raise Exception(f"Environment variable {key} is not set!")
return val
payment_skey = pc.PaymentSigningKey.load(get_env_val("PAYMENT_KEY_PATH"))
payment_vkey = pc.PaymentVerificationKey.from_signing_key(payment_skey)
stake_skey = pc.StakeSigningKey.load(get_env_val('STAKE_KEY_PATH'))
stake_vkey = pc.StakeVerificationKey.from_signing_key(stake_skey)
chain_context = pc.BlockFrostChainContext(
project_id=get_env_val("BLOCKFROST_ID"), network=NETWORK
)
@retry(delay=20)
def wait_for_tx(tx_id):
chain_context.api.transaction(tx_id)
print(f"Transaction {tx_id} has been successfully included in the blockchain.")
def submit_tx(tx):
print("############### Transaction created ###############")
print(tx)
print(tx.to_cbor())
print("############### Submitting transaction ###############")
chain_context.submit_tx(tx.to_cbor())
wait_for_tx(str(tx.id))
def utxos(address):
amount = sum([i.output.amount.coin for i in chain_context.utxos(str(address)) if not i.output.amount.multi_asset is None]) / 1e6
print(f'UTXO value: {amount} ADA')
def find_collateral(target_address):
for utxo in chain_context.utxos(str(target_address)):
# A collateral should contain no multi asset
if not utxo.output.amount.multi_asset:
return utxo
return None
def create_collateral(target_address, skey):
collateral_builder = pc.TransactionBuilder(chain_context)
collateral_builder.add_input_address(target_address)
collateral_builder.add_output(pc.TransactionOutput(target_address, 5000000))
submit_tx(collateral_builder.build_and_sign([skey], target_address))
# ----------- Giver sends 10 ADA to a script address ---------------
with open("fortytwo.plutus", "r") as f:
script_hex = f.read()
forty_two_script = cbor2.loads(bytes.fromhex(script_hex))
script_hash = pc.plutus_script_hash(forty_two_script)
script_address = pc.Address(script_hash, network=NETWORK)
giver_address = pc.Address(payment_vkey.hash(), stake_vkey.hash(), network=NETWORK)
builder = pc.TransactionBuilder(chain_context)
builder.add_input_address(giver_address)
datum = pc.PlutusData() # A Unit type "()" in Haskell
builder.add_output(
pc.TransactionOutput(script_address, 10000000, datum_hash=pc.datum_hash(datum))
)
utxos(giver_address)
signed_tx = builder.build_and_sign([payment_skey], giver_address)
submit_tx(signed_tx)
# ----------- Taker takes 10 ADA from the script address ---------------
# taker_address could be any address. In this example, we will use the same address as giver.
taker_address = giver_address
# Notice that transaction builder will automatically estimate execution units (num steps & memory) for a redeemer if
# no execution units are provided in the constructor of Redeemer.
# Put integer 42 (the secret that unlocks the fund) in the redeemer.
redeemer = pc.Redeemer(pc.RedeemerTag.SPEND, 42)
utxo_to_spend = chain_context.utxos(str(script_address))[1]
builder = pc.TransactionBuilder(chain_context)
builder.add_script_input(utxo_to_spend, forty_two_script, datum, redeemer)
# Send 5 ADA to taker address. The remaining ADA (~4.7) will be sent as change.
take_output = pc.TransactionOutput(taker_address, 5000000)
builder.add_output(take_output)
non_nft_utxo = find_collateral(taker_address)
if non_nft_utxo is None:
create_collateral(taker_address, payment_skey)
non_nft_utxo = find_collateral(taker_address)
builder.collaterals.append(non_nft_utxo)
signed_tx = builder.build_and_sign([payment_skey], taker_address)
submit_tx(signed_tx)
utxos(giver_address)
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 16
Thanks @cffls for your help! 😃