diff --git a/res/ui/mainwindow.ui b/res/ui/mainwindow.ui
index 9e68d093597d4b9d2bf952aa91058a41914127b2..d92357d930a1c8257d97ae0eaa38dbe2dfe9b4f5 100644
--- a/res/ui/mainwindow.ui
+++ b/res/ui/mainwindow.ui
@@ -50,6 +50,12 @@
       <string>&amp;Open</string>
      </property>
     </widget>
+    <widget class="QMenu" name="menuAdvanced">
+     <property name="title">
+      <string>Advanced</string>
+     </property>
+     <addaction name="action_revoke_identity"/>
+    </widget>
     <addaction name="menu_change_account"/>
     <addaction name="action_configure_parameters"/>
     <addaction name="action_add_account"/>
@@ -59,6 +65,8 @@
     <addaction name="separator"/>
     <addaction name="action_add_a_contact"/>
     <addaction name="menu_contacts_list"/>
+    <addaction name="separator"/>
+    <addaction name="menuAdvanced"/>
    </widget>
    <widget class="QMenu" name="menu_help">
     <property name="title">
@@ -188,6 +196,11 @@
     <string>&amp;Manage local node</string>
    </property>
   </action>
+  <action name="action_revoke_identity">
+   <property name="text">
+    <string>Revoke an identity</string>
+   </property>
+  </action>
  </widget>
  <resources>
   <include location="../icons/icons.qrc"/>
diff --git a/res/ui/revocation.ui b/res/ui/revocation.ui
new file mode 100644
index 0000000000000000000000000000000000000000..d7edc4990e334b82dbe71405c249084bd05ad234
--- /dev/null
+++ b/res/ui/revocation.ui
@@ -0,0 +1,234 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>RevocationDialog</class>
+ <widget class="QDialog" name="RevocationDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>250</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Revoke an identity</string>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QStackedWidget" name="stackedWidget">
+     <property name="styleSheet">
+      <string notr="true">QGroupBox {
+    border: 1px solid gray;
+    border-radius: 9px;
+    margin-top: 0.5em;
+}
+
+QGroupBox::title {
+    subcontrol-origin: margin;
+    left: 10px;
+    padding: 0 3px 0 3px;
+	font-weight: bold;
+}</string>
+     </property>
+     <property name="currentIndex">
+      <number>1</number>
+     </property>
+     <widget class="QWidget" name="page_load_file">
+      <layout class="QVBoxLayout" name="verticalLayout_2">
+       <item>
+        <widget class="QLabel" name="label">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>&lt;h2&gt;Select a revokation document&lt;/h1&gt;</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QPushButton" name="button_load">
+         <property name="text">
+          <string>Load from file</string>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox">
+         <property name="styleSheet">
+          <string notr="true"/>
+         </property>
+         <property name="title">
+          <string>Revocation document</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <widget class="QLabel" name="label_revocation_content">
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+     <widget class="QWidget" name="page_destination">
+      <layout class="QVBoxLayout" name="verticalLayout_4">
+       <item>
+        <widget class="QLabel" name="label_2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="text">
+          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-size:x-large; font-weight:600;&quot;&gt;Select publication destination&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+         </property>
+         <property name="textFormat">
+          <enum>Qt::RichText</enum>
+         </property>
+        </widget>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_2">
+         <item>
+          <widget class="QRadioButton" name="radio_community">
+           <property name="text">
+            <string>To a co&amp;mmunity</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QComboBox" name="combo_community"/>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <layout class="QHBoxLayout" name="horizontalLayout_3">
+         <property name="sizeConstraint">
+          <enum>QLayout::SetDefaultConstraint</enum>
+         </property>
+         <item>
+          <widget class="QRadioButton" name="radio_address">
+           <property name="text">
+            <string>&amp;To an address</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLineEdit" name="edit_address"/>
+         </item>
+         <item>
+          <widget class="QSpinBox" name="spinbox_port">
+           <property name="maximum">
+            <number>65535</number>
+           </property>
+           <property name="value">
+            <number>8201</number>
+           </property>
+          </widget>
+         </item>
+        </layout>
+       </item>
+       <item>
+        <widget class="QGroupBox" name="groupBox_2">
+         <property name="sizePolicy">
+          <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+           <horstretch>0</horstretch>
+           <verstretch>0</verstretch>
+          </sizepolicy>
+         </property>
+         <property name="title">
+          <string>Revocation information</string>
+         </property>
+         <layout class="QVBoxLayout" name="verticalLayout_5">
+          <item>
+           <widget class="QLabel" name="label_revocation_info">
+            <property name="sizePolicy">
+             <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+              <horstretch>0</horstretch>
+              <verstretch>0</verstretch>
+             </sizepolicy>
+            </property>
+            <property name="text">
+             <string/>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <spacer name="verticalSpacer">
+            <property name="orientation">
+             <enum>Qt::Vertical</enum>
+            </property>
+            <property name="sizeHint" stdset="0">
+             <size>
+              <width>20</width>
+              <height>1</height>
+             </size>
+            </property>
+           </spacer>
+          </item>
+         </layout>
+        </widget>
+       </item>
+      </layout>
+     </widget>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="topMargin">
+      <number>6</number>
+     </property>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="button_next">
+       <property name="text">
+        <string>Next</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+ <slots>
+  <slot>open_process_add_community()</slot>
+  <slot>key_changed(int)</slot>
+  <slot>action_remove_community()</slot>
+  <slot>open_process_edit_community(QModelIndex)</slot>
+  <slot>next()</slot>
+  <slot>previous()</slot>
+  <slot>open_import_key()</slot>
+  <slot>open_generate_account_key()</slot>
+  <slot>action_edit_account_key()</slot>
+  <slot>action_edit_account_parameters()</slot>
+  <slot>action_show_pubkey()</slot>
+  <slot>action_delete_account()</slot>
+ </slots>
+</ui>
diff --git a/src/sakia/core/account.py b/src/sakia/core/account.py
index 8765d181cb568d17626cbfd2011b8d15a7fc4939..82b0096486043f93b18f409f4b7d08b6e6636d9f 100644
--- a/src/sakia/core/account.py
+++ b/src/sakia/core/account.py
@@ -4,7 +4,7 @@ Created on 1 févr. 2014
 @author: inso
 """
 
-from duniterpy.documents import Membership, SelfCertification, Certification, Revokation, BlockUID, Block
+from duniterpy.documents import Membership, SelfCertification, Certification, Revocation, BlockUID, Block
 from duniterpy.key import SigningKey
 from duniterpy.api import bma
 from duniterpy.api.bma import PROTOCOL_VERSION
@@ -546,7 +546,7 @@ class Account(QObject):
         """
         revoked = await self._identities_registry.future_find(self.pubkey, community)
 
-        revokation = Revokation(PROTOCOL_VERSION, community.currency, None)
+        revokation = Revocation(PROTOCOL_VERSION, community.currency, None)
         selfcert = await revoked.selfcert(community)
 
         key = SigningKey(self.salt, password)
@@ -578,9 +578,9 @@ class Account(QObject):
         :param sakia.core.Community community: the community
         :param str password: the password
         :return: the revokation document
-        :rtype: duniterpy.documents.certification.Revokation
+        :rtype: duniterpy.documents.certification.Revocation
         """
-        document = Revokation(PROTOCOL_VERSION, community.currency, self.pubkey, "")
+        document = Revocation(PROTOCOL_VERSION, community.currency, self.pubkey, "")
         identity = await self.identity(community)
         selfcert = await identity.selfcert(community)
 
diff --git a/src/sakia/core/transfer.py b/src/sakia/core/transfer.py
index 3234a34a43f88a99b66fb56f1020afb234046b40..b1cd3048ac8d02f013480656ed5c82a2e9285729 100644
--- a/src/sakia/core/transfer.py
+++ b/src/sakia/core/transfer.py
@@ -68,6 +68,9 @@ class Transfer(QObject):
         self._locally_created = locally_created
         self._metadata = metadata
 
+        # Dict containing states of a transfer :
+        # keys are a tuple containg (current_state, transition_parameters)
+        # values are tuples containing (transition_test, transition_success, new_state)
         self._table_states = {
             (TransferState.TO_SEND, (list, Block)):
                 (
diff --git a/src/sakia/gui/mainwindow.py b/src/sakia/gui/mainwindow.py
index c348d56b97550584ddc78249cf126741d2ffe01a..5d66b78e060f2d8ad39799d10ec09d94e7944b9a 100644
--- a/src/sakia/gui/mainwindow.py
+++ b/src/sakia/gui/mainwindow.py
@@ -21,6 +21,7 @@ from .community_view import CommunityWidget
 from .contact import ConfigureContactDialog
 from .import_account import ImportAccountDialog
 from .certification import CertificationDialog
+from .revocation import RevocationDialog
 from .password_asker import PasswordAskerDialog
 from .preferences import PreferencesDialog
 from .process_cfg_community import ProcessConfigureCommunity
@@ -110,6 +111,7 @@ class MainWindow(QObject):
         self.ui.actionCertification.triggered.connect(self.open_certification_dialog)
         self.ui.actionPreferences.triggered.connect(self.open_preferences_dialog)
         self.ui.actionAbout.triggered.connect(self.open_about_popup)
+        self.ui.action_revoke_identity.triggered.connect(self.open_revocation_dialog)
 
         self.ui.actionManage_local_node.triggered.connect(self.open_duniter_ui)
         self.ui.menu_duniter.setDisabled(True)
@@ -263,6 +265,10 @@ class MainWindow(QObject):
                                      self.community_view.community,
                                      self.password_asker)
 
+    def open_revocation_dialog(self):
+        RevocationDialog.open_dialog(self.app,
+                                     self.account)
+
     def open_add_contact_dialog(self):
         dialog = ConfigureContactDialog.new_contact(self.app, self.account, self.widget)
         dialog.exec_()
diff --git a/src/sakia/gui/revocation.py b/src/sakia/gui/revocation.py
new file mode 100644
index 0000000000000000000000000000000000000000..ddcca43af472054f4cfb28a41e738b207531976c
--- /dev/null
+++ b/src/sakia/gui/revocation.py
@@ -0,0 +1,206 @@
+import asyncio
+import aiohttp
+import logging
+from duniterpy.api import errors
+from duniterpy.api import bma
+from duniterpy.documents import MalformedDocumentError
+from duniterpy.documents.certification import Revocation
+from sakia.core.net import Node
+from PyQt5.QtWidgets import QDialog, QFileDialog, QMessageBox
+from PyQt5.QtCore import QObject
+
+from .widgets.dialogs import QAsyncMessageBox
+from ..tools.decorators import asyncify
+from ..gen_resources.revocation_uic import Ui_RevocationDialog
+
+
+class RevocationDialog(QObject):
+    """
+    A dialog to revoke an identity
+    """
+
+    def __init__(self, app, account, widget, ui):
+        """
+        Constructor if a certification dialog
+
+        :param sakia.core.Application app:
+        :param sakia.core.Account account:
+        :param PyQt5.QtWidgets widget: the widget of the dialog
+        :param sakia.gen_resources.revocation_uic.Ui_RevocationDialog ui: the view of the certification dialog
+        :return:
+        """
+        super().__init__()
+        self.widget = widget
+        self.ui = ui
+        self.ui.setupUi(self.widget)
+        self.app = app
+        self.account = account
+        self.revocation_document = None
+        self.revoked_selfcert = None
+        self._steps = (
+            {
+                'page': self.ui.page_load_file,
+                'init': self.init_dialog,
+                'next': self.revocation_selected
+            },
+            {
+                'page': self.ui.page_destination,
+                'init': self.init_publication_page,
+                'next': self.publish
+            }
+        )
+        self._current_step = 0
+        self.handle_next_step(init=True)
+        self.ui.button_next.clicked.connect(lambda checked: self.handle_next_step(False))
+
+    def handle_next_step(self, init=False):
+        if self._current_step < len(self._steps) - 1:
+            if not init:
+                self.ui.button_next.clicked.disconnect(self._steps[self._current_step]['next'])
+                self._current_step += 1
+            self._steps[self._current_step]['init']()
+            self.ui.stackedWidget.setCurrentWidget(self._steps[self._current_step]['page'])
+            self.ui.button_next.clicked.connect(self._steps[self._current_step]['next'])
+
+    def init_dialog(self):
+        self.ui.button_next.setEnabled(False)
+        self.ui.button_load.clicked.connect(self.load_from_file)
+
+        self.ui.radio_address.toggled.connect(lambda c: self.publication_mode_changed("address"))
+        self.ui.radio_community.toggled.connect(lambda c: self.publication_mode_changed("community"))
+        self.ui.edit_address.textChanged.connect(self.refresh)
+        self.ui.spinbox_port.valueChanged.connect(self.refresh)
+        self.ui.combo_community.currentIndexChanged.connect(self.refresh)
+
+    def publication_mode_changed(self, radio):
+        self.ui.edit_address.setEnabled(radio == "address")
+        self.ui.spinbox_port.setEnabled(radio == "address")
+        self.ui.combo_community.setEnabled(radio == "community")
+        self.refresh()
+
+    def load_from_file(self):
+        selected_files = QFileDialog.getOpenFileName(self.widget,
+                                          self.tr("Load a revocation file"),
+                                          "",
+                                          self.tr("All text files (*.txt)"))
+        selected_file = selected_files[0]
+        try:
+            with open(selected_file, 'r') as file:
+                file_content = file.read()
+                self.revocation_document = Revocation.from_signed_raw(file_content)
+                self.revoked_selfcert = Revocation.extract_self_cert(file_content)
+                self.refresh()
+                self.ui.button_next.setEnabled(True)
+        except MalformedDocumentError:
+            QMessageBox.critical(self.widget, self.tr("Error loading document"),
+                                        self.tr("Loaded document is not a revocation document"),
+                                 QMessageBox.Ok)
+            self.ui.button_next.setEnabled(False)
+
+    def revocation_selected(self):
+        pass
+
+    def init_publication_page(self):
+        self.ui.combo_community.clear()
+        if self.account:
+            for community in self.account.communities:
+                self.ui.combo_community.addItem(community.currency)
+            self.ui.radio_community.setChecked(True)
+        else:
+            self.ui.radio_address.setChecked(True)
+            self.ui.radio_community.setEnabled(False)
+
+    def publish(self):
+        self.ui.button_next.setEnabled(False)
+        answer = QMessageBox.warning(self.widget, self.tr("Revocation"),
+                                      self.tr("""<h4>The publication of this document will remove your identity from the network.</h4>
+<li>
+    <li> <b>This identity won't be able to join the targeted community anymore.</b> </li>
+    <li> <b>This identity won't be able to generate Universal Dividends anymore.</b> </li>
+    <li> <b>This identity won't be able to certify individuals anymore.</b> </li>
+</li>
+Please think twice before publishing this document.
+"""), QMessageBox.Ok | QMessageBox.Cancel)
+        if answer == QMessageBox.Ok:
+            self.accept()
+        else:
+            self.ui.button_next.setEnabled(True)
+
+    @asyncify
+    async def accept(self):
+        try:
+            session = aiohttp.ClientSession()
+            if self.ui.radio_community.isChecked():
+                community = self.account.communities[self.ui.combo_community.currentIndex()]
+                await community.bma_access.broadcast(bma.wot.Revoke, {},
+                       {
+                           'revocation': self.revocation_document.signed_raw(self.revoked_selfcert)
+                       })
+            elif self.ui.radio_address.isChecked():
+                    server = self.ui.edit_address.text()
+                    port = self.ui.spinbox_port.value()
+                    node = await Node.from_address(None, server, port, session=session)
+                    conn_handler = node.endpoint.conn_handler()
+                    await bma.wot.Revoke(conn_handler).post(session,
+                                                revocation=self.revocation_document.signed_raw(self.revoked_selfcert))
+        except (MalformedDocumentError, ValueError, errors.DuniterError,
+            aiohttp.errors.ClientError, aiohttp.errors.DisconnectedError,
+                aiohttp.errors.TimeoutError) as e:
+            await QAsyncMessageBox.critical(self.widget, self.tr("Error broadcasting document"),
+                                        str(e))
+        else:
+            await QAsyncMessageBox.information(self.widget, self.tr("Revocation broadcast"),
+                                               self.tr("The document was successfully broadcasted."))
+            self.widget.accept()
+        finally:
+            session.close()
+
+    @classmethod
+    def open_dialog(cls, app, account):
+        """
+        Certify and identity
+        :param sakia.core.Application app: the application
+        :param sakia.core.Account account: the account certifying the identity
+        :return:
+        """
+        dialog = cls(app, account, QDialog(), Ui_RevocationDialog())
+        dialog.refresh()
+        return dialog.exec()
+
+    def refresh(self):
+        if self.revoked_selfcert:
+            text = self.tr("""
+<div>Identity revoked : {uid} (public key : {pubkey}...)</div>
+<div>Identity signed on block : {timestamp}</div>
+    """.format(uid=self.revoked_selfcert.uid,
+               pubkey=self.revoked_selfcert.pubkey[:12],
+               timestamp=self.revoked_selfcert.timestamp))
+
+            self.ui.label_revocation_content.setText(text)
+
+            if self.ui.radio_community.isChecked():
+                target = self.tr("All nodes of community {name}".format(name=self.ui.combo_community.currentText()))
+            elif self.ui.radio_address.isChecked():
+                target = self.tr("Address {address}:{port}".format(address=self.ui.edit_address.text(),
+                                                                   port=self.ui.spinbox_port.value()))
+            else:
+                target = ""
+            self.ui.label_revocation_info.setText("""
+<h4>Revocation document</h4>
+<div>{text}</div>
+<h4>Publication address</h4>
+<div>{target}</div>
+""".format(text=text,
+           target=target))
+        else:
+            self.ui.label_revocation_content.setText("")
+
+    def async_exec(self):
+        future = asyncio.Future()
+        self.widget.finished.connect(lambda r: future.set_result(r))
+        self.widget.open()
+        self.refresh()
+        return future
+
+    def exec(self):
+        self.widget.exec()