def handle_channel_settled(raiden: 'RaidenService', event: Event):
    data = event.event_data
    token_network_identifier = event.originating_contract
    channel_identifier = data['args']['channel_identifier']
    block_number = data['block_number']
    block_hash = data['block_hash']
    transaction_hash = data['transaction_hash']

    chain_state = views.state_from_raiden(raiden)
    channel_state = views.get_channelstate_by_canonical_identifier(
        chain_state=chain_state,
        canonical_identifier=CanonicalIdentifier(
            chain_identifier=chain_state.chain_id,
            token_network_address=token_network_identifier,
            channel_identifier=channel_identifier,
        ),
    )

    # This may happen for two reasons:
    # - This node is not a participant for the given channel (normal operation,
    #   the event should be ignored).
    # - Something went wrong in our code and the channel state was cleared
    #   before settle (a bug, this should raise an exception on development
    #   mode).
    # Because we cannot distinguish the two cases, assume the channel is not of
    # interest and ignore the event.
    if not channel_state:
        return

    """
    This is resolving a corner case where the current node view
    of the channel state does not reflect what the blockchain
    contains.
    The corner case goes as follows in a setup of nodes:
    A -> B:
    - A sends out a LockedTransfer to B
    - B sends a refund to A
    - B goes offline
    - A sends LockExpired to B
      Here:
      (1) the lock is removed from A's state
      (2) B never received the message
    - A closes the channel with B's refund
    - B comes back online and calls updateNonClosingBalanceProof
      with A's LockedTransfer (LockExpired was never processed).
    - When channel is settled, B unlocks it's refund transfer lock
      provided that it gains from doing so.
    - A does NOT try to unlock its lock because its side
      of the channel state is empty (lock expired and was removed).

    The above is resolved by providing the state machine with the
    onchain locksroots for both participants in the channel so that
    the channel state is updated to store these locksroots.
    In `raiden_event_handler:handle_contract_send_channelunlock`,
    those values are used to restore the channel state back to where
    the locksroots values existed and this channel state is used
    to calculate the gain and potentially perform unlocks in case
    there is value to be gained.
    """
    our_locksroot, partner_locksroot = get_onchain_locksroots(
        chain=raiden.chain,
        canonical_identifier=channel_state.canonical_identifier,
        participant1=channel_state.our_state.address,
        participant2=channel_state.partner_state.address,
        block_identifier=block_hash,
    )

    channel_settled = ContractReceiveChannelSettled(
        transaction_hash=transaction_hash,
        canonical_identifier=channel_state.canonical_identifier,
        our_onchain_locksroot=our_locksroot,
        partner_onchain_locksroot=partner_locksroot,
        block_number=block_number,
        block_hash=block_hash,
    )
    raiden.handle_and_track_state_change(channel_settled)