def tx_extract(payload, senders, inputs, outputs, block_id, vtxindex, txid):
    """
    Extract and return a dict of fields from the underlying blockchain transaction data
    that are useful to this operation.

    structure:
    inputs                                | outputs
    ------------------------------------------------------------------------------
    sender scriptsig + scriptPubkey       | OP_RETURN with token transfer payload
    ------------------------------------------------------------------------------
                                          | recipient script (DUST_MINIMUM)
                                          ----------------------------------------
                                          | sender's change address

    The recipient script identifies the recipient address.  This is its own output
    to ensure that the underlying blockchain can and will enforce signatures from
    the recipient on future spend transactions.  Also, it makes it straightforward
    to track blockstack transactions in existing block explorers.

    Any other inputs and outputs are allowed.
    """
  
    sender_script = None
    sender_address = None

    recipient_script = None
    recipient_address = None

    try:
        # first two outputs matter to us
        assert check_tx_output_types(outputs[:2], block_id)

        assert len(senders) > 0
        assert 'script_pubkey' in senders[0].keys()
        assert 'addresses' in senders[0].keys()

        sender_script = str(senders[0]['script_pubkey'])
        sender_address = str(senders[0]['addresses'][0])

        assert sender_script is not None
        assert sender_address is not None

        recipient_script = get_token_transfer_recipient_from_outputs(outputs)
        recipient_address = virtualchain.script_hex_to_address(recipient_script)

        assert recipient_script is not None
        assert recipient_address is not None

    except Exception, e:
        log.exception(e)
        raise Exception("Failed to extract")

    parsed_payload = parse(payload, block_id)
    assert parsed_payload is not None 
   
    ret = {}
    ret.update(parsed_payload)
    ret.update({
        'address': sender_address,
        'sender': sender_script,
        'recipient_address': recipient_address,
        'recipient': recipient_script,
        'op': TOKEN_TRANSFER,
        'block_id': block_id,
        'txid': txid,
        'vtxindex': vtxindex
    })

    return ret
Extract and return a dict of fields from the underlying blockchain transaction data
    that are useful to this operation.

    structure:
    inputs                                | outputs
    ------------------------------------------------------------------------------
    sender scriptsig + scriptPubkey       | OP_RETURN with token transfer payload
    ------------------------------------------------------------------------------
                                          | recipient script (DUST_MINIMUM)
                                          ----------------------------------------
                                          | sender's change address

    The recipient script identifies the recipient address.  This is its own output
    to ensure that the underlying blockchain can and will enforce signatures from
    the recipient on future spend transactions.  Also, it makes it straightforward
    to track blockstack transactions in existing block explorers.

    Any other inputs and outputs are allowed.