Sending transactions
info
This flow is also described in the Construction API Overview article in the official Rosetta documentation.
The steps needed to send payment in MINA token are following:
- Given a key pair, derive the account indentifier using /construction/deriveendpoint
- Call /construction/preprocessand/construction/metadatato construct parameters for/construction/payloadsrequest
- Create an unsigned transaction blob using construction/payloadsendpoint
- Call construction/parse(optional) to check if the unsigned transaction does what you expect
- Use detached signer to sign the transaction
- Call construction/combineto generate signed blob to be sent via/construction/submitendpoint
- Call construction/parseagain (optional) to confirm correctness of the signed transaction
- Get a future transaction hash using /construction/hashenpoint
- Submit the signed transaction blob via /construction/submitendpoint
For ease of readability, this sample implementation skips the sanity checks (steps 4 and 7) and combines steps 2 and 3 in a single tx_payloads function call.
Before running this sample:
- Make sure you followed Offline signer tool article and generated a key pair
- Send some test funds on the account you've generated.
The implementation is as follows:
def withdrawal_flow(vault_keypair, dest_address, value_nano, fee_nano=None):
    """
    Full withdrawal flow example (without sanity check)
    If fee_nano is None - fee will be suggested by Rosetta API response
    """
    vault_pubkey = vault_keypair["public"]
    vault_private_key = vault_keypair["private"]
    
    # derive vault address
    derive_response = derive_account_identifier(vault_pubkey)
    vault_address = derive_response["account_identifier"]["address"]
    
    # get transfer payload to sign
    payloads_response = tx_payloads(
        vault_pubkey, vault_address, dest_address, fee_nano, value_nano)
    
    # sign transfer payload
    signature = sign_transaction(
        SIGNER_PATH, 
        vault_private_key,
        payloads_response["unsigned_transaction"])
    # get signed transaction blob
    combine_response = tx_combine(vault_pubkey, payloads_response, signature)
    signed_transaction_blob = combine_response['signed_transaction']
    # sanity check may be performed here 
    # for that - use tx_parse function output
    # to doublecheck it corresponds what you want to do
    # parsed_tx = tx_parse(signed_transaction_blob, True)
    # get future transaction hash
    tx_hash_response = tx_hash(signed_transaction_blob)
    future_tx_hash = tx_hash_response['transaction_identifier']['hash']
    # submit transaction. this call will fail if tx is not in mempool
    tx_submit(signed_transaction_blob)
    
    # wait for transaction confirmation:
    # for that, track blocks until we meet our transaction in the last one
    latest_block = network_status()["current_block_identifier"]["index"]
    while True:
        # check if our transaction exists in the latest block
        txs = wait_for_block(latest_block)['block']['transactions']
        hashes = [tx['transaction_identifier']['hash'] for tx in txs]
        if future_tx_hash in hashes:
            break
        latest_block += 1
    
    return future_tx_hash