<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def is_balance_proof_usable_onchain( received_balance_proof: BalanceProofSignedState, channel_state: NettingChannelState, sender_state: NettingChannelEndState, ) -> SuccessOrError: """ Checks the balance proof can be used on-chain. For a balance proof to be valid it must be newer than the previous one, i.e. the nonce must increase, the signature must tie the balance proof to the correct channel, and the values must not result in an under/overflow onchain. Important: This predicate does not validate all the message fields. The fields locksroot, transferred_amount, and locked_amount **MUST** be validated elsewhere based on the message type. """

    expected_nonce = get_next_nonce(sender_state)

    is_valid_signature_, signature_msg = is_valid_signature(
        received_balance_proof,
        sender_state.address,
    )

    result: SuccessOrError

    # TODO: Accept unlock messages if the node has not yet sent a transaction
    # with the balance proof to the blockchain, this will save one call to
    # unlock on-chain for the non-closing party.
    if get_status(channel_state) != CHANNEL_STATE_OPENED:
        # The channel must be opened, otherwise if receiver is the closer, the
        # balance proof cannot be used onchain.
        msg = f'The channel is already closed.'
        result = (False, msg)

    elif received_balance_proof.channel_identifier != channel_state.identifier:
        # Informational message, the channel_identifier **validated by the
        # signature** must match for the balance_proof to be valid.
        msg = (
            f"channel_identifier does not match. "
            f"expected: {channel_state.identifier} "
            f"got: {received_balance_proof.channel_identifier}."
        )
        result = (False, msg)

    elif received_balance_proof.token_network_identifier != channel_state.token_network_identifier:
        # Informational message, the token_network_identifier **validated by
        # the signature** must match for the balance_proof to be valid.
        msg = (
            f"token_network_identifier does not match. "
            f"expected: {channel_state.token_network_identifier} "
            f"got: {received_balance_proof.token_network_identifier}."
        )
        result = (False, msg)

    elif received_balance_proof.chain_id != channel_state.chain_id:
        # Informational message, the chain_id **validated by the signature**
        # must match for the balance_proof to be valid.
        msg = (
            f"chain_id does not match channel's "
            f"chain_id. expected: {channel_state.chain_id} "
            f"got: {received_balance_proof.chain_id}."
        )
        result = (False, msg)

    elif not is_balance_proof_safe_for_onchain_operations(received_balance_proof):
        transferred_amount_after_unlock = (
            received_balance_proof.transferred_amount +
            received_balance_proof.locked_amount
        )
        msg = (
            f"Balance proof total transferred amount would overflow onchain. "
            f"max: {UINT256_MAX} result would be: {transferred_amount_after_unlock}"
        )

        result = (False, msg)

    elif received_balance_proof.nonce != expected_nonce:
        # The nonces must increase sequentially, otherwise there is a
        # synchronization problem.
        msg = (
            f'Nonce did not change sequentially, expected: {expected_nonce} '
            f'got: {received_balance_proof.nonce}.'
        )

        result = (False, msg)

    elif not is_valid_signature_:
        # The signature must be valid, otherwise the balance proof cannot be
        # used onchain.
        result = (False, signature_msg)

    else:
        result = (True, None)

    return result