diff --git a/dist/android/sources b/dist/android/sources
index 65fae394ca791b990578f5dde1e49f5e97fd34fa..17788c85b43b1fa75287a80454349948068cc457 160000
--- a/dist/android/sources
+++ b/dist/android/sources
@@ -1 +1 @@
-Subproject commit 65fae394ca791b990578f5dde1e49f5e97fd34fa
+Subproject commit 17788c85b43b1fa75287a80454349948068cc457
diff --git a/doc/build_ios.md b/doc/build_ios.md
index 155d549d0168a642babaf63b31be58e1793ca6a8..6856698c6f156d2fd1adb89ca23cb1de3d4b5c70 100644
--- a/doc/build_ios.md
+++ b/doc/build_ios.md
@@ -82,7 +82,7 @@ npm install -g nw-gyp node-pre-gyp
 
 2. Install global dependencies (see [Development Guide](./development_guide.md) for versions to used) :
 ```
-npm install -g yarn gulp@3.9.1 cordova @ionic/cli@6.6.0
+npm install -g yarn gulp cordova @ionic/cli@6.20.9
 ```
 
 3. Install project dependencies :
diff --git a/package.json b/package.json
index 6b12f65dbef7534e16845d226a96e3455215444d..356ca61bfff6d5820c2ba9d03a3264fc1c35b8f4 100644
--- a/package.json
+++ b/package.json
@@ -103,7 +103,7 @@
     "cordova-plugin-customurlscheme": "^5.0.2",
     "cordova-plugin-device": "^2.1.0",
     "cordova-plugin-dialogs": "^2.0.2",
-    "cordova-plugin-file": "^6.0.2",
+    "cordova-plugin-file": "^8.0.0",
     "cordova-plugin-ionic-keyboard": "^2.2.0",
     "cordova-plugin-ionic-webview": "^5.0.0",
     "cordova-plugin-network-information": "~3.0.0",
@@ -156,7 +156,7 @@
     "map-stream": "0.0.7",
     "merge2": "^1.3.0",
     "mv": "^2.1.1",
-    "node-sass": "^8.0.0",
+    "node-sass": "^9.0.0",
     "phonegap-plugin-barcodescanner": "^8.1.0",
     "playup": "^1.1.0",
     "vinyl-fs": "^3.0.3",
diff --git a/platforms/android b/platforms/android
deleted file mode 160000
index 583a19c5d1733a606e68f72ecbb124ce2d1316cc..0000000000000000000000000000000000000000
--- a/platforms/android
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 583a19c5d1733a606e68f72ecbb124ce2d1316cc
diff --git a/resources/android/build/app/libs/libsodium-jni-release.aar b/resources/android/build/app/libs/libsodium-jni-release.aar
deleted file mode 100644
index a88fe7e2303dfc4648ee16dd53c0a9f43b747dac..0000000000000000000000000000000000000000
Binary files a/resources/android/build/app/libs/libsodium-jni-release.aar and /dev/null differ
diff --git a/scss/ionic.app.scss b/scss/ionic.app.scss
index 39bd50f55e2e8dfc6a8ee2250c9f0a61717a32be..fba9deb1811e3566aa054eb53a91ac5bdead6aa5 100644
--- a/scss/ionic.app.scss
+++ b/scss/ionic.app.scss
@@ -1282,10 +1282,11 @@ html, body {
   }
 }
 
-.stable-100-bg {
-  background-color: $stable-100-bg !important;
+.popover-wallet-tx-actions {
+  height: 120px;
 }
 
+
 /******
 * TX view (wallet or identity)
 *******/
@@ -1394,6 +1395,7 @@ html, body {
   filter: alpha(opacity=80);
 }
 
+
 .card.stable-900-bg,
 .card .stable-900-bg,
 .item.stable-900-bg,
@@ -2570,6 +2572,11 @@ div[drop-zone]:hover {
 /**********
   Wot identity
 **********/
+
+.stable-100-bg {
+  background-color: $stable-100-bg !important;
+}
+
 .hero.dark-100-bg {
   background-color: $dark-100-bg;
 }
diff --git a/www/i18n/locale-ca.json b/www/i18n/locale-ca.json
index a93f3cb02ca8e783fcaaf5f70daab7a3dbdbfe37..8c1613b1188c35daab8398d8128db5b3d1157aab 100644
--- a/www/i18n/locale-ca.json
+++ b/www/i18n/locale-ca.json
@@ -51,6 +51,7 @@
     "LOADING": "Esperi si us plau...",
     "LOADING_WAIT": "Esperi si us plau...<br/><small>(Cesium està interrogant el node Duniter)</small>",
     "SEARCHING": "Cerca en procés...",
+    "DOWNLOADING_DOTS": "Descarregant...",
     "FROM": "De",
     "TO": "A",
     "COPY": "Còpia",
@@ -694,7 +695,7 @@
       "NO_WALLET": "Sin monedero secundario",
       "BTN_DELETE": "Eliminar un monedero secundario…",
       "BTN_RENAME": "Renombrar el monedero",
-      "EXPORT_FILENAME": "monederos-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-monederos-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total : ",
       "EDIT_POPOVER": {
         "TITLE": "Renombrar el monedero",
@@ -728,7 +729,7 @@
       "RECOVER_ID_SELECT_FILE": "Elija el <b>archivo para salvaguardar sus credenciales</b> a utilizar :",
       "GENERATE_KEYFILE": "Generar mi archivo de llaves…",
       "GENERATE_KEYFILE_HELP": "Genera un archivo que le permitirá atenticarse sin tener que introducir las credenciales.<br/><b>Cuidado:</b> este archivo contendrá su llave secreta; ¡Es muy importante conservarlo en un lugar seguro!",
-      "KEYFILE_FILENAME": "llavero-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-llavero-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Registrarse como miembro…",
       "MEMBERSHIP_IN_HELP": "Le permite <b>transformar</b> una cuenta de monedero simple <b>en una cuenta miembro</b>, enviando una petición de membresía. Solo si todavía no tiene una cuenta miembro.",
       "SEND_IDENTITY": "Publicar identidad…",
@@ -760,16 +761,17 @@
       "REVOCATION_WITH_FILE": "Revocar una identidad a partir de un fichero",
       "REVOCATION_WITH_FILE_DESCRIPTION": "Si ha perdido de forma permanente las credenciales de su cuenta miembro (o la seguridad de la cuenta se ve comprometida), puede usar <b>el archivo de revocación de la cuenta</b> para forzar la salida de la Red de Confianza.",
       "REVOCATION_WITH_FILE_HELP": "Para <b>revocar permanentemente</b> una cuenta miembro, arrastre el archivo de revocación en el cuadro siguiente o haga clic en el cuadro para seleccionar un archivo.",
-      "REVOCATION_FILENAME": "revocacion-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocacion-{{uid}}-{{pubkey}}.txt",
       "REVOCATION_WALLET": "Revocar esta identidad",
       "SAVE_ID": "Guardar mis credenciales",
       "STRONG_LEVEL": "Alto <span class=\"hidden-xs \">(6 preguntas min.)</span>",
       "TITLE": "Cuenta y seguridad",
       "RECOVER_ID_HELP": "Si dispone de un <b>archivo de recuperación de sus credenciales</b>, las puede reobtener respondiendo correctamente a las preguntas personales elegidas en su momento.",
       "REVOCATION_WALLET_HELP": "Pedir la revocación de vuestra identidad comporta la <b>salida de la red de confianza</b> (definitiva para el seudónimo y la llave pública asociada). La cuenta no producirá ya más el Dividendo Universal.<br/>Podrá seguir usándola como monedero simple.",
-      "SAVE_ID_HELP": "Creación de un archivo de recuperación, para <b>reobtener su contraseña</b> (y frase secreta) en caso de olvido. El archivo se <b>cifra</b> con ayuda de las preguntas personales elegidas."
+      "SAVE_ID_HELP": "Creación de un archivo de recuperación, para <b>reobtener su contraseña</b> (y frase secreta) en caso de olvido. El archivo se <b>cifra</b> con ayuda de las preguntas personales elegidas.",
+      "SAVE_ID_FILENAME": "{{currency}}-credencials-{{pubkey}}.txt"
     },
-    "FILE_NAME": "{{currency}}_HistorialDeCuenta_{{pubkey|formatPubkey}}_{{currentTime|formatDateForFile}}.csv",
+    "FILE_NAME": "{{currency}}-HistorialDeCuenta-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Fecha",
       "AMOUNT": "Cantidad",
@@ -890,6 +892,7 @@
     "GET_BLOCK_FAILED": "Error en la recuperación del bloque",
     "INVALID_BLOCK_HASH": "Bloque no encontrado (hash diferente)",
     "DOWNLOAD_REVOCATION_FAILED": "Debe seleccionar un fichero de texto",
+    "DOWNLOAD_SAVE_ID_FAILED": "Error en baixar l'arxiu de còpia de seguretat de les credencials.",
     "REVOCATION_FAILED": "Error en la revocación.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Frase secreta o contraseña incorrectos",
     "RECOVER_ID_FAILED": "Error en la recuperación de las credenciales",
@@ -904,7 +907,8 @@
     "INVALID_FILE_FORMAT": "Formato de archivo inválido.",
     "SAME_TX_RECIPIENT": "El destinatario debe ser diferente del emisor.",
     "SELF_CERTIFICATION": "No pots certificar la teva pròpia identitat.",
-    "TX_SANDBOX_FULL": "El node Duniter utilitzat per Cesium ja no pot rebre transferències noves, perquè la cua està plena.<br/><br/>Torneu-ho a provar o canvieu els nodes (a través del menú <b>Configuració</b>)."
+    "TX_SANDBOX_FULL": "El node Duniter utilitzat per Cesium ja no pot rebre transferències noves, perquè la cua està plena.<br/><br/>Torneu-ho a provar o canvieu els nodes (a través del menú <b>Configuració</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Error en descarregar l'extracte de compte"
   },
   "INFO": {
     "POPUP_TITLE": "Información",
@@ -921,7 +925,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "La <b>revocación de esta identidad</b> fue solicitada y está en espera de ser procesada.",
     "FEATURES_NOT_IMPLEMENTED": "Esta funcionalidad todavía está en proceso de desarrollo.<br/><br/>¿Por qué no <b>contribuir a Cesium</b>, para obtenerla más rápido? ;)",
     "EMPTY_TX_HISTORY": "Ninguna operación a exportar",
-    "LOADING_PENDING_TX": "Esperi si us plau...<br/><small>(Recuperant operacions pendents)</small>"
+    "LOADING_PENDING_TX": "Esperi si us plau...<br/><small>(Recuperant operacions pendents)</small>",
+    "FILE_DOWNLOADED": "Fitxer descarregat"
   },
   "CONFIRM": {
     "EXIT_APP": "¿ Cerrar la aplicación ?",
diff --git a/www/i18n/locale-de-DE.json b/www/i18n/locale-de-DE.json
index dca7b56446bc030f9ac742735aa2d7676cc7fff4..162cbc7c9a861efda715eaea3c1857c6bb3e7460 100644
--- a/www/i18n/locale-de-DE.json
+++ b/www/i18n/locale-de-DE.json
@@ -51,6 +51,7 @@
     "LOADING": "Lade...",
     "LOADING_WAIT": "Lade...<br/><small>(Cesium fragt den Duniter-Knoten ab)</small>",
     "SEARCHING": "Suche...",
+    "DOWNLOADING_DOTS": "Herunterladen...",
     "FROM": "Von",
     "TO": "An",
     "COPY": "Kopieren",
@@ -615,7 +616,7 @@
       "NO_WALLET": "Keine sekundäre Brieftasche",
       "BTN_DELETE": "Eine sekundäre Brieftasche entfernen...",
       "BTN_RENAME": "Brieftasche umbenennen",
-      "EXPORT_FILENAME": "my_wallets-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-my_wallets-{{pubkey}}.csv",
       "TOTAL_DOTS": "Gesamt: ",
       "EDIT_POPOVER": {
         "TITLE": "Brieftasche umbenennen",
@@ -637,7 +638,7 @@
       "DOWNLOAD_REVOKE_HELP" : "Eine Sperrdatei ist wichtig, zum Beispiel bei Verlust von Zugangsdaten. Sie ermöglicht dir, <b>dieses Konto aus dem Netz des Vertrauens herauszuholen</b> und es zu einer einfachen Brieftasche zu machen.",
       "GENERATE_KEYFILE": "Meine Schlüsselbund-Datei generieren ...",
       "GENERATE_KEYFILE_HELP": "Generiere eine Datei, mit der du dich authentifizieren kannst, ohne deine Zugangsdaten einzugeben.<br/><b>Warnung:</b> Diese Datei enthält Ihren geheimen Schlüssel. Es ist daher sehr wichtig, sie an einem sicheren Ort aufzubewahren!",
-      "KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-keychain-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Als Mitglied registrieren...",
       "MEMBERSHIP_IN_HELP": "Ermöglicht es dir, ein einfaches Brieftaschen-Konto <b>in ein Mitgliedskonto umzuwandeln</b>, indem du eine Mitgliedschaftsanfrage sendest. Nur erlaubt, wenn du noch kein anderes Mitgliedskonto hast.",
       "SEND_IDENTITY": "Pseudonym veröffentlichen...",
@@ -673,9 +674,10 @@
       "REVOCATION_WITH_FILE_HELP": "Um ein Mitgliedskonto <b>dauerhaft zu widerrufen</b>, ziehe bitte die Widerrufsdatei in das Feld unten oder klicke in das Feld, um nach einer Datei zu suchen.",
       "REVOCATION_WALLET": "Dieses Konto sofort widerrufen",
       "REVOCATION_WALLET_HELP": "Die Anforderung des Widerrufs Ihrer Identität führt dazu, dass <b>Ihre Mitgliedschaft widerrufen wird</b> (auf jeden Fall für das zugehörige Pseudonym und den öffentlichen Schlüssel). Das Konto ist dann nicht mehr in der Lage, eine Universaldividende zu produzieren.<br/>Sie können es jedoch weiterhin als einfache Brieftasche verwenden.",
-      "REVOCATION_FILENAME": "revocation-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocation-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Meine Zugangsdaten speichern...",
       "SAVE_ID_HELP": "Erstellen einer Sicherungsdatei, um <b>dein Passwort</b> (und den geheimen Benutzernamen) <b>wiederzuerlangen, falls du es vergisst</b>. Die Datei ist mit personenbezogenen Fragen <b>gesichert</b> (verschlüsselt).",
+      "SAVE_ID_FILENAME": "{{currency}}-anmeldeinformationen-{{pubkey}}.txt",
       "STRONG_LEVEL": "Hoch <span class=\"hidden-xs \">(6 Fragen Minimum)</span>",
       "TITLE": "Konto and Sicherheit",
       "KEYFILE": {
@@ -696,7 +698,7 @@
         }
       }
     },
-    "FILE_NAME": "{{currency}} - Kontozusammenfassung {{pubkey|formatPubkey}} {{currentTime|formatDateForFile}}.csv",
+    "FILE_NAME": "{{currency}}-Kontozusammenfassung-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Datum",
       "AMOUNT": "Betrag",
@@ -809,6 +811,7 @@
     "GET_BLOCK_FAILED": "Fehler beim Holen eines Blocks",
     "INVALID_BLOCK_HASH": "Block nicht gefunden (falscher Hashwert)",
     "DOWNLOAD_REVOCATION_FAILED": "Fehler beim Herunterladen der Widerrufsdatei.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Fehler beim Herunterladen der Sicherungsdatei für die Anmeldeinformationen.",
     "REVOCATION_FAILED": "Fehler bei dem Versuch, die Identität zu widerrufen.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Falscher geheimer Benutzername oder Passwort",
     "RECOVER_ID_FAILED": "Konnte Passwort nicht wiederherstellen",
@@ -833,7 +836,8 @@
     "INVALID_FILE_FORMAT": "Ungültiges Dateiformat.",
     "SAME_TX_RECIPIENT": "Der Empfänger muss sich vom Auftraggeber unterscheiden.",
     "SELF_CERTIFICATION": "Sie können Ihre eigene Identität nicht zertifizieren.",
-    "TX_SANDBOX_FULL": "Der von Cesium verwendete Duniter-Knoten kann keine neuen Überweisungen mehr bearbeiten, da die Warteschlange voll ist.<br/><br/>Versuche es später erneut oder wähle einen anderen Duniter-Knoten (in den <b>Einstellungen</b>)."
+    "TX_SANDBOX_FULL": "Der von Cesium verwendete Duniter-Knoten kann keine neuen Überweisungen mehr bearbeiten, da die Warteschlange voll ist.<br/><br/>Versuche es später erneut oder wähle einen anderen Duniter-Knoten (in den <b>Einstellungen</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Fehler beim Herunterladen des Kontoauszugs"
   },
   "INFO": {
     "POPUP_TITLE": "Hinweis",
@@ -851,7 +855,8 @@
     "FEATURE_NOT_AVAILABLE_ON_DEMO": "Diese Funktion ist auf der Demo-Version nicht verfügbar.<br/>Aus <b>Sicherheitsgründen</b> empfehlen wir dir, eine Kopie der Software zu <b>installieren</b>.<br/>Besuche die Webseite <a href='https://cesium.app'>www.cesium.app</a> für Hilfe und weitere Informationen.",
     "FEATURES_NOT_IMPLEMENTED": "Diese Funktion ist noch nicht implementiert.<br/><br/>Warum nicht mitwirken, um sie schneller zu erhalten? ;)",
     "EMPTY_TX_HISTORY": "Keine Tansaktionen für den Export vorhanden.",
-    "LOADING_PENDING_TX": "Lade...<br/><small>(Abrufen von ausstehenden Operationen)</small>"
+    "LOADING_PENDING_TX": "Lade...<br/><small>(Abrufen von ausstehenden Operationen)</small>",
+    "FILE_DOWNLOADED": "Datei heruntergeladen"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Bist du sicher</b>, dass du fortfahren möchtest?",
diff --git a/www/i18n/locale-en-GB.json b/www/i18n/locale-en-GB.json
index 97ae039e5f7f530d3d17393dda71acba509c5a5f..70a4df1cd558fc0301f469260250dde697064ddf 100644
--- a/www/i18n/locale-en-GB.json
+++ b/www/i18n/locale-en-GB.json
@@ -51,6 +51,7 @@
     "LOADING": "Loading...",
     "LOADING_WAIT": "Loading...<br/><small>(Cesium is querying the Duniter peer)</small>",
     "SEARCHING": "Searching...",
+    "DOWNLOADING_DOTS": "Downloading...",
     "FROM": "From",
     "TO": "To",
     "COPY": "Copy",
@@ -601,7 +602,7 @@
       "NO_WALLET": "No secondary wallet",
       "BTN_DELETE": "Remove a secondary wallet...",
       "BTN_RENAME": "Rename the wallet",
-      "EXPORT_FILENAME": "my_wallets-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-my_wallets-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total: ",
       "EDIT_POPOVER": {
         "TITLE": "Rename the wallet",
@@ -623,7 +624,7 @@
       "DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
       "GENERATE_KEYFILE": "Generate my keychain file ...",
       "GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
-      "KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-keychain-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Register as member...",
       "MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
       "SEND_IDENTITY": "Publish identity...",
@@ -659,7 +660,7 @@
       "REVOCATION_WITH_FILE_HELP": "To <b>permanently revoke</ b> a member account, please drag the revocation file in the box below, or click in the box to search for a file.",
       "REVOCATION_WALLET": "Revoke this account immediately",
       "REVOCATION_WALLET_HELP": "Requesting revocation of your identity causes <b>will revoke your membership</ b> (definitely for the associated pseudonym and public key). The account will no longer be able to produce a Universal Dividend.<br/>However, you can still use it as a simple wallet.",
-      "REVOCATION_FILENAME": "revocation-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocation-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Save my credentials...",
       "SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
       "STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
@@ -795,6 +796,7 @@
     "GET_BLOCK_FAILED": "Error while getting block",
     "INVALID_BLOCK_HASH": "Block not found (incorrect hash)",
     "DOWNLOAD_REVOCATION_FAILED": "Error while downloading revocation file.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Failed to download the credentials backup file.",
     "REVOCATION_FAILED": "Error while trying to revoke the identity.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Wrong secret identifier or password ",
     "RECOVER_ID_FAILED": "Could not recover password",
@@ -819,7 +821,8 @@
     "INVALID_FILE_FORMAT": "Invalid file format.",
     "SAME_TX_RECIPIENT": "The recipient must be different from the issuer.",
     "SELF_CERTIFICATION": "You cannot certify your own identity.",
-    "TX_SANDBOX_FULL": "The Duniter peer used by Cesium can no longer process new transfers, as its queue is full.<br/><br/>Please try again later or change the peer (in the <b>Settings</b>)."
+    "TX_SANDBOX_FULL": "The Duniter peer used by Cesium can no longer process new transfers, as its queue is full.<br/><br/>Please try again later or change the peer (in the <b>Settings</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Error downloading the account statement"
   },
   "INFO": {
     "POPUP_TITLE": "Information",
@@ -836,7 +839,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "Revocation <b>has been sent successfully</b>. It is awaiting processing.",
     "FEATURES_NOT_IMPLEMENTED": "This features is not implemented yet.<br/><br/>Why not to contribute to get it faster? ;)",
     "EMPTY_TX_HISTORY": "No operations to export",
-    "LOADING_PENDING_TX": "Please wait...<br/><small>(Retrieving pending operations)</small>"
+    "LOADING_PENDING_TX": "Please wait...<br/><small>(Retrieving pending operations)</small>",
+    "FILE_DOWNLOADED": "File downloaded"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Are you sure</b> you want to continue?",
diff --git a/www/i18n/locale-en.json b/www/i18n/locale-en.json
index a23d15730163dab1e1bd53a918f2421b07531f8b..3ad8f8db22291afe0449d38569ee0b12cd5aed8c 100644
--- a/www/i18n/locale-en.json
+++ b/www/i18n/locale-en.json
@@ -51,6 +51,7 @@
     "LOADING": "Loading...",
     "LOADING_WAIT": "Loading...<br/><small>(Cesium is querying the Duniter peer)</small>",
     "SEARCHING": "Searching...",
+    "DOWNLOADING_DOTS": "Downloading...",
     "FROM": "From",
     "TO": "To",
     "COPY": "Copy",
@@ -601,7 +602,7 @@
       "NO_WALLET": "No secondary wallet",
       "BTN_DELETE": "Remove a secondary wallet...",
       "BTN_RENAME": "Rename the wallet",
-      "EXPORT_FILENAME": "my_wallets-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-my_wallets-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total: ",
       "EDIT_POPOVER": {
         "TITLE": "Rename the wallet",
@@ -623,7 +624,7 @@
       "DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
       "GENERATE_KEYFILE": "Generate my keychain file ...",
       "GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
-      "KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-keychain-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Register as member...",
       "MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
       "SEND_IDENTITY": "Publish identity...",
@@ -659,9 +660,10 @@
       "REVOCATION_WITH_FILE_HELP": "To <b>permanently revoke</ b> a member account, please drag the revocation file in the box below, or click in the box to search for a file.",
       "REVOCATION_WALLET": "Revoke this account immediately",
       "REVOCATION_WALLET_HELP": "Requesting revocation of your identity causes <b>will revoke your membership</ b> (definitely for the associated pseudonym and public key). The account will no longer be able to produce a Universal Dividend.<br/>However, you can still use it as a simple wallet.",
-      "REVOCATION_FILENAME": "revocation-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocation-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Save my credentials...",
-      "SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
+      "SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b>in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
+      "SAVE_ID_FILENAME": "{{currency}}-credentials-{{pubkey}}.txt",
       "STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
       "TITLE": "Account and security",
       "KEYFILE": {
@@ -682,7 +684,7 @@
         }
       }
     },
-    "FILE_NAME": "{{currency}} - Account statement {{pubkey|formatPubkey}} to {{currentTime|formatDateForFile}}.csv",
+    "FILE_NAME": "{{currency}}-Account_statement-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Date",
       "AMOUNT": "Amount",
@@ -795,6 +797,7 @@
     "GET_BLOCK_FAILED": "Error while getting block",
     "INVALID_BLOCK_HASH": "Block not found (incorrect hash)",
     "DOWNLOAD_REVOCATION_FAILED": "Error while downloading revocation file.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Failed to download the credentials backup file.",
     "REVOCATION_FAILED": "Error while trying to revoke the identity.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Wrong secret identifier or password ",
     "RECOVER_ID_FAILED": "Could not recover password",
@@ -819,7 +822,8 @@
     "INVALID_FILE_FORMAT": "Invalid file format.",
     "SAME_TX_RECIPIENT": "The recipient must be different from the issuer.",
     "SELF_CERTIFICATION": "You cannot certify your own identity.",
-    "TX_SANDBOX_FULL": "The Duniter peer used by Cesium can no longer process new transfers, as its queue is full.<br/><br/>Please try again later or change the peer (in the <b>Settings</b>)."
+    "TX_SANDBOX_FULL": "The Duniter peer used by Cesium can no longer process new transfers, as its queue is full.<br/><br/>Please try again later or change the peer (in the <b>Settings</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Error downloading the account statement"
   },
   "INFO": {
     "POPUP_TITLE": "Information",
@@ -836,7 +840,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "Revocation <b>has been sent successfully</b>. It is awaiting processing.",
     "FEATURES_NOT_IMPLEMENTED": "This features is not implemented yet.<br/><br/>Why not to contribute to get it faster? ;)",
     "EMPTY_TX_HISTORY": "No operations to export",
-    "LOADING_PENDING_TX": "Please wait...<br/><small>(Retrieving pending operations)</small>"
+    "LOADING_PENDING_TX": "Please wait...<br/><small>(Retrieving pending operations)</small>",
+    "FILE_DOWNLOADED": "File downloaded"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Are you sure</b> you want to continue?",
diff --git a/www/i18n/locale-eo-EO.json b/www/i18n/locale-eo-EO.json
index b355afdff59712f41e5b807be21524ea3232470e..5a5dda2647454ebb81c778a7288837dbb322b394 100644
--- a/www/i18n/locale-eo-EO.json
+++ b/www/i18n/locale-eo-EO.json
@@ -51,6 +51,7 @@
     "LOADING": "Bonvolu pacienci...",
     "LOADING_WAIT": "Bonvolu pacienci...<br/><small>(Cesium demandas la Duniter-nodon)</small>",
     "SEARCHING": "Serĉanta...",
+    "DOWNLOADING_DOTS": "Elŝutanta...",
     "FROM": "De",
     "TO": "Al",
     "COPY": "Kopii",
@@ -600,7 +601,7 @@
       "NO_WALLET": "Neniu kroma monujo",
       "BTN_DELETE": "Forigi kroman monujon...",
       "BTN_RENAME": "Renomi la monujon",
-      "EXPORT_FILENAME": "miaj_monujoj-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-miaj_monujoj-{{pubkey}}.csv",
       "TOTAL_DOTS": "Sumo: ",
       "EDIT_POPOVER": {
         "TITLE": "Renomi la monujon",
@@ -622,7 +623,7 @@
       "DOWNLOAD_REVOKE_HELP": "Disponi dosieron pri nuligo estas grave, ekzemple kaze de perdo de viaj identigiloj. Ĝi ebligas al vi <b>elirigi tiun konton el la reto de fido</b>, tiel ke ĝi refariĝu simpla monujo.",
       "GENERATE_KEYFILE": "Krei mian dosieron pri ŝlosilaro...",
       "GENERATE_KEYFILE_HELP": "Kreas dosieron, kiu ebligas al vi aŭtentiĝi sen tajpi viajn identigilojn.<br/><b>Atenton:</b> tiu dosiero entenos vian konto-ŝlosilaron (publikan kaj sekretan ŝlosilojn); do tre gravas meti ĝin en sekuran lokon!",
-      "KEYFILE_FILENAME": "ŝlosilaro-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-ŝlosilaro-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Transformi en membro-konton...",
       "MEMBERSHIP_IN_HELP": "Ebligas <b>transformi</b> simplan monujo-konton <b>en membro-konton</b>, sendante aliĝo-peton. Utilas nur se vi ne havas jam alian membro-konton.",
       "SEND_IDENTITY": "Publikigi sian identecon...",
@@ -658,9 +659,10 @@
       "REVOCATION_WITH_FILE_HELP": "Por <b>definitive nuligi</b> membro-konton, bonvolu glitigi en la ĉi-suban zonon vian dosieron pri nuligo, aŭ alklaki la zonon por serĉadi dosieron.",
       "REVOCATION_WALLET": "Nuligi tiun ĉi konton tuj",
       "REVOCATION_WALLET_HELP": "Peti la nuligon de via identeco estigas la <b>eliradon el la reto de fido</b> (definitivan por la pseŭdonimo kaj la publika ŝlosilo kunligitaj). La konto ne plu povos produkti Universalan Dividendon.<br/>Vi tamen daŭre povos konektiĝi al ĝi, kiel al simpla monujo.",
-      "REVOCATION_FILENAME": "nuligo-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-nuligo-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Konservi miajn identigilojn...",
       "SAVE_ID_HELP": "Kreado de konserv-dosiero, por <b>retrovi vian pasvorton</b> (kaj la sekretan identigilon) <b>kaze de forgeso</b>. La dosiero estas <b>sekurigita</b> (ĉifrita) dank'al personaj demandoj.",
+      "SAVE_ID_FILENAME": "{{currency}}-ensalutigiloj-{{pubkey}}.txt",
       "STRONG_LEVEL": "Forta <span class=\"hidden-xs \">(6 demandoj minimume)</span>",
       "TITLE": "Konto kaj sekureco",
       "KEYFILE": {
@@ -794,6 +796,7 @@
     "GET_BLOCK_FAILED": "Malsukceso por ricevi la blokon.",
     "INVALID_BLOCK_HASH": "Bloko ne trovita (haketo malsama)",
     "DOWNLOAD_REVOCATION_FAILED": "Malsukceso por elŝuti la dosieron pri nuligo.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Malsukcesis elŝuti la dosieron por konservi la ensalutigilojn.",
     "REVOCATION_FAILED": "Malsukceso pri nuligo.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Sekreta identigilo aŭ pasvorto malĝusta.",
     "RECOVER_ID_FAILED": "Malsukceso por ricevi la identigilojn",
@@ -818,7 +821,8 @@
     "INVALID_FILE_FORMAT": "Strukturo de dosiero nevalida.",
     "SAME_TX_RECIPIENT": "La adresito devas malsami ol la sendanto.",
     "SELF_CERTIFICATION": "Vi ne povas certigi vian propran identecon.",
-    "TX_SANDBOX_FULL": "La nodo Duniter uzata de Cesium ne plu povas prilabori novajn elspezojn, ĉar ĝia atendovico estas plena.<br/><br/>Bonvolu provi denove poste aŭ ŝanĝi la nodon (en la <b>Agordoj</b>)."
+    "TX_SANDBOX_FULL": "La nodo Duniter uzata de Cesium ne plu povas prilabori novajn elspezojn, ĉar ĝia atendovico estas plena.<br/><br/>Bonvolu provi denove poste aŭ ŝanĝi la nodon (en la <b>Agordoj</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Eraro dum la elŝuto de la konta raporto"
   },
   "INFO": {
     "POPUP_TITLE": "Informo",
@@ -835,7 +839,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "La <b>nuligo de tiu ĉi identeco</b> estis petita kaj atendas traktadon.",
     "FEATURES_NOT_IMPLEMENTED": "Tiu ĉi funkciaro ankoraŭ estas programiĝanta.<br/>Kial ne <b>kontribui al Cesium</b>, por ekhavi ĝin pli rapide? ;)",
     "EMPTY_TX_HISTORY": "Neniu spezo elportota",
-    "LOADING_PENDING_TX": "Bonvolu pacienci...<br/><small>(Prenado de pendaj operacioj)</small>"
+    "LOADING_PENDING_TX": "Bonvolu pacienci...<br/><small>(Prenado de pendaj operacioj)</small>",
+    "FILE_DOWNLOADED": "Dosiero elŝutita"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Ĉu vi certas</b>, ke vi volas daŭrigi?",
diff --git a/www/i18n/locale-es-ES.json b/www/i18n/locale-es-ES.json
index f60c11f2e2b09e3b60b3734eef6de8ee1ead4004..99e6f21849882a7b7904d6f93b8dde0ef810c008 100644
--- a/www/i18n/locale-es-ES.json
+++ b/www/i18n/locale-es-ES.json
@@ -51,6 +51,7 @@
     "LOADING": "Espere por favor...",
     "LOADING_WAIT": "Espere por favor...<br/><small>(Cesium está consultando al nodo Duniter)</small>",
     "SEARCHING": "Búsqueda en proceso…",
+    "DOWNLOADING_DOTS": "Descargando...",
     "FROM": "De",
     "TO": "A",
     "COPY": "Copiar",
@@ -693,7 +694,7 @@
       "NO_WALLET": "Sin monedero secundario",
       "BTN_DELETE": "Eliminar un monedero secundario…",
       "BTN_RENAME": "Renombrar el monedero",
-      "EXPORT_FILENAME": "monederos-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-monederos-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total : ",
       "EDIT_POPOVER": {
         "TITLE": "Renombrar el monedero",
@@ -727,7 +728,7 @@
       "RECOVER_ID_SELECT_FILE": "Elija el <b>archivo para salvaguardar sus credenciales</b> a utilizar :",
       "GENERATE_KEYFILE": "Generar mi archivo de llaves…",
       "GENERATE_KEYFILE_HELP": "Genera un archivo que le permitirá atenticarse sin tener que introducir las credenciales.<br/><b>Cuidado:</b> este archivo contendrá su llave secreta; ¡Es muy importante conservarlo en un lugar seguro!",
-      "KEYFILE_FILENAME": "llavero-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-llavero-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Registrarse como miembro…",
       "MEMBERSHIP_IN_HELP": "Le permite <b>transformar</b> una cuenta de monedero simple <b>en una cuenta miembro</b>, enviando una petición de membresía. Solo si todavía no tiene una cuenta miembro.",
       "SEND_IDENTITY": "Publicar seudónimo/identidad…",
@@ -759,16 +760,17 @@
       "REVOCATION_WITH_FILE": "Revocar una identidad a partir de un fichero",
       "REVOCATION_WITH_FILE_DESCRIPTION": "Si ha perdido de forma permanente las credenciales de su cuenta miembro (o la seguridad de la cuenta se ve comprometida), puede usar <b>el archivo de revocación de la cuenta</b> para forzar la salida de la Red de Confianza.",
       "REVOCATION_WITH_FILE_HELP": "Para <b>revocar permanentemente</b> una cuenta miembro, arrastre el archivo de revocación en el cuadro siguiente o haga clic en el cuadro para seleccionar un archivo.",
-      "REVOCATION_FILENAME": "revocacion-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocacion-{{uid}}-{{pubkey}}.txt",
       "REVOCATION_WALLET": "Revocar esta identidad",
       "SAVE_ID": "Guardar mis credenciales",
       "STRONG_LEVEL": "Alto <span class=\"hidden-xs \">(6 preguntas min.)</span>",
       "TITLE": "Cuenta y seguridad",
       "RECOVER_ID_HELP": "Si dispone de un <b>archivo de recuperación de sus credenciales</b>, las puede reobtener respondiendo correctamente a las preguntas personales elegidas en su momento.",
       "REVOCATION_WALLET_HELP": "Pedir la revocación de vuestra identidad comporta la <b>salida de la red de confianza</b> (definitiva para el seudónimo y la llave pública asociada). La cuenta no producirá ya más el Dividendo Universal.<br/>Podrá seguir usándola como monedero simple.",
-      "SAVE_ID_HELP": "Creación de un archivo de recuperación, para <b>reobtener su contraseña</b> (y frase secreta) en caso de olvido. El archivo se <b>cifra</b> con ayuda de las preguntas personales elegidas."
+      "SAVE_ID_HELP": "Creación de un archivo de recuperación, para <b>reobtener su contraseña</b> (y frase secreta) en caso de olvido. El archivo se <b>cifra</b> con ayuda de las preguntas personales elegidas.",
+      "SAVE_ID_FILENAME": "{{currency}}-credenciales-{{pubkey}}.txt"
     },
-    "FILE_NAME": "{{currency}}_HistorialDeCuenta_{{pubkey|formatPubkey}}_{{currentTime|formatDateForFile}}.csv",
+    "FILE_NAME": "{{currency}}-HistorialDeCuenta-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Fecha",
       "AMOUNT": "Cantidad",
@@ -889,6 +891,7 @@
     "GET_BLOCK_FAILED": "Error en la recuperación del bloque",
     "INVALID_BLOCK_HASH": "Bloque no encontrado (hash diferente)",
     "DOWNLOAD_REVOCATION_FAILED": "Debe seleccionar un fichero de texto",
+    "DOWNLOAD_SAVE_ID_FAILED": "Error al descargar el archivo de copia de seguridad de las credenciales.",
     "REVOCATION_FAILED": "Error en la revocación.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Frase secreta o contraseña incorrectos",
     "RECOVER_ID_FAILED": "Error en la recuperación de las credenciales",
@@ -903,7 +906,8 @@
     "INVALID_FILE_FORMAT": "Formato de archivo inválido.",
     "SAME_TX_RECIPIENT": "El destinatario debe ser diferente del emisor.",
     "SELF_CERTIFICATION": "No puedes certificar tu propia identidad.",
-    "TX_SANDBOX_FULL": "El nodo Duniter utilizado por Cesium ya no puede procesar nuevas transferencias, ya que su cola está llena.<br/><br/>Por favor, inténtelo de nuevo más tarde o cambie de nodo (en las <b>Configuraciones</b>)."
+    "TX_SANDBOX_FULL": "El nodo Duniter utilizado por Cesium ya no puede procesar nuevas transferencias, ya que su cola está llena.<br/><br/>Por favor, inténtelo de nuevo más tarde o cambie de nodo (en las <b>Configuraciones</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Error al descargar el estado de cuenta"
   },
   "INFO": {
     "POPUP_TITLE": "Información",
@@ -920,7 +924,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "La <b>revocación de esta identidad</b> fue solicitada y está en espera de ser procesada.",
     "FEATURES_NOT_IMPLEMENTED": "Esta funcionalidad todavía está en proceso de desarrollo.<br/><br/>¿Por qué no <b>contribuir a Cesium</b>, para obtenerla más rápido? ;)",
     "EMPTY_TX_HISTORY": "Ninguna operación a exportar",
-    "LOADING_PENDING_TX": "Espere por favor...<br/><small>(Recuperando operaciones pendientes)</small>"
+    "LOADING_PENDING_TX": "Espere por favor...<br/><small>(Recuperando operaciones pendientes)</small>",
+    "FILE_DOWNLOADED": "Archivo descargado"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "¿Desea continuar?",
diff --git a/www/i18n/locale-fr-FR.json b/www/i18n/locale-fr-FR.json
index 121321c68376a0ba38717ed03e27e82cd2bd2195..71016cc67c57c226ea302f516b9fc2d43b891843 100644
--- a/www/i18n/locale-fr-FR.json
+++ b/www/i18n/locale-fr-FR.json
@@ -51,6 +51,7 @@
     "LOADING": "Veuillez patienter...",
     "LOADING_WAIT": "Veuillez patienter...<br/><small>(Cesium interroge le nœud Duniter)</small>",
     "SEARCHING": "Recherche en cours...",
+    "DOWNLOADING_DOTS": "Téléchargement...",
     "FROM": "De",
     "TO": "À",
     "COPY": "Copier",
@@ -603,7 +604,7 @@
       "NO_WALLET": "Aucun portefeuille secondaire",
       "BTN_DELETE": "Retirer un portefeuille secondaire...",
       "BTN_RENAME": "Renommer le portefeuille",
-      "EXPORT_FILENAME": "mes_portefeuilles-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-mes_portefeuilles-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total : ",
       "EDIT_POPOVER": {
         "TITLE": "Renommer le portefeuille",
@@ -625,7 +626,7 @@
       "DOWNLOAD_REVOKE_HELP": "Disposer d'un fichier de révocation est important, par exemple en cas de perte de vos identifiants. Il vous permet de <b>sortir ce compte de la toile de confiance</b>, en redevenant ainsi un simple portefeuille. Ne fonctionne pas sur smartphone.",
       "GENERATE_KEYFILE": "Générer mon fichier de trousseau...",
       "GENERATE_KEYFILE_HELP": "Génère un fichier permettant de vous authentifier sans saisir vos identifiants.<br/><b>Attention :</b> ce fichier contiendra votre trousseau de compte (clefs publique et secrète) ; il est donc très important de le mettre en lieu sûr !",
-      "KEYFILE_FILENAME": "trousseau-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-trousseau-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Transformer en compte membre...",
       "MEMBERSHIP_IN_HELP": "Permet de <b>transformer</b> un compte simple portefeuille <b>en compte membre</b>, en envoyant une demande d'adhésion. Utile uniquement si vous n'avez pas déjà un autre compte membre.",
       "SEND_IDENTITY": "Publier son identité...",
@@ -661,9 +662,10 @@
       "REVOCATION_WITH_FILE_HELP": "Pour <b>révoquer définitivement</b> un compte membre, veuillez glisser dans la zone ci-dessous votre fichier de révocation, ou bien cliquer dans la zone pour rechercher un fichier.",
       "REVOCATION_WALLET": "Révoquer immédiatement ce compte",
       "REVOCATION_WALLET_HELP": "Demander la révocation de votre identité entraîne la <b>sortie de la toile de confiance</b> (définitive pour le pseudonyme et la clé publique associés). Le compte ne pourra plus produire de Dividende Universel.<br/>Vous pourrez toutefois encore vous y connecter, comme à un simple portefeuille.",
-      "REVOCATION_FILENAME": "revocation-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocation-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Sauvegarder mes identifiants...",
       "SAVE_ID_HELP": "Création d'un fichier de sauvegarde, pour <b>retrouver votre mot de passe</b> (et l'identifiant secret) <b>en cas de d'oubli</b>. Le fichier est <b>sécurisé</b> (chiffré) à l'aide de questions personnelles.",
+      "SAVE_ID_FILENAME": "{{currency}}-identifiants-{{pubkey}}.txt",
       "STRONG_LEVEL": "Fort <span class=\"hidden-xs \">(6 questions minimum)</span>",
       "TITLE": "Compte et sécurité",
       "KEYFILE": {
@@ -684,7 +686,7 @@
         }
       }
     },
-    "FILE_NAME": "{{currency}} - Relevé du compte {{pubkey|formatPubkey}} au {{currentTime|formatDateForFile}}.csv",
+    "FILE_NAME": "{{currency}}-historique-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Date",
       "AMOUNT": "Montant",
@@ -797,12 +799,13 @@
     "GET_BLOCK_FAILED": "Échec de la récupération du bloc.",
     "INVALID_BLOCK_HASH": "Bloc non trouvé (hash différent).",
     "DOWNLOAD_REVOCATION_FAILED": "Échec du téléchargement du fichier de révocation.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Échec du téléchargement du fichier de sauvegarde des identifiants.",
     "REVOCATION_FAILED": "Échec de la révocation.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Identifiant secret ou mot de passe incorrect.",
     "RECOVER_ID_FAILED": "Échec de la récupération des identifiants",
     "LOAD_FILE_FAILED" : "Échec du chargement du fichier",
     "NOT_VALID_REVOCATION_FILE": "Fichier de révocation non valide (mauvais format de fichier)",
-    "NOT_VALID_SAVE_ID_FILE": "Fichier de récupération non valide (mauvais format de fichier)",
+    "NOT_VALID_SAVE_ID_FILE": "Fichier de sauvegarde non valide (mauvais format de fichier)",
     "NOT_VALID_KEY_FILE": "Fichier de trousseau non valide (format non reconnu)",
     "EXISTING_ACCOUNT": "Vos identifiants correspondent à un compte déjà existant, dont la <a ng-click=\"showHelpModal('pubkey')\">clef publique</a> est :",
     "EXISTING_ACCOUNT_REQUEST": "Veuillez modifier vos identifiants afin qu'ils correspondent à un compte non utilisé.",
@@ -821,7 +824,8 @@
     "INVALID_FILE_FORMAT": "Format de fichier invalide.",
     "SAME_TX_RECIPIENT": "Le destinataire doit être différent de l'émetteur.",
     "SELF_CERTIFICATION": "Vous ne pouvez pas certifier votre propre identité.",
-    "TX_SANDBOX_FULL": "Le nœud Duniter utilisé par Cesium ne peut plus traité de nouveaux virements, car sa file d'attente est pleine.<br/><br/>Veuillez réessayer ultérieurement ou changer de nœud (dans les <b>Paramètres</b>)."
+    "TX_SANDBOX_FULL": "Le nœud Duniter utilisé par Cesium ne peut plus traité de nouveaux virements, car sa file d'attente est pleine.<br/><br/>Veuillez réessayer ultérieurement ou changer de nœud (dans les <b>Paramètres</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Erreur lors du téléchargement du relevé de compte"
   },
   "INFO": {
     "POPUP_TITLE": "Information",
@@ -838,7 +842,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "La <b>révocation de cette identité</b> a été demandée et est en attente de traitement.",
     "FEATURES_NOT_IMPLEMENTED": "Cette fonctionnalité est encore en cours de développement.<br/>Pourquoi ne pas <b>contribuer à Cesium</b>, pour l'obtenir plus rapidement ? ;)",
     "EMPTY_TX_HISTORY": "Aucune opération à exporter",
-    "LOADING_PENDING_TX": "Veuillez patienter...<br/><small>(Récupération des opérations en attente)</small>"
+    "LOADING_PENDING_TX": "Veuillez patienter...<br/><small>(Récupération des opérations en attente)</small>",
+    "FILE_DOWNLOADED": "Fichier téléchargé avec succès"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Êtes-vous sûr</b> de vouloir continuer ?",
diff --git a/www/i18n/locale-it-IT.json b/www/i18n/locale-it-IT.json
index b21269c1f87a5c18e511be6a7d4b35a009387a88..3b4edb919d381c24f1f61b1a6e870742738dcff4 100644
--- a/www/i18n/locale-it-IT.json
+++ b/www/i18n/locale-it-IT.json
@@ -51,6 +51,7 @@
     "LOADING": "Caricando...",
     "LOADING_WAIT": "Caricando...<br/><small>(Cesium interroga il nodo nodo Duniter)</small>",
     "SEARCHING": "Cercando...",
+    "DOWNLOADING_DOTS": "Scaricamento...",
     "FROM": "Da",
     "TO": "A",
     "COPY": "Copiare",
@@ -601,7 +602,7 @@
       "NO_WALLET": "Nessun portafoglio secondario",
       "BTN_DELETE": "Rimuovi un portafoglio secondario ...",
       "BTN_RENAME": "Rinominare il portafoglio",
-      "EXPORT_FILENAME": "my_wallets-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-my_wallets-{{pubkey}}.csv",
       "TOTAL_DOTS": "Totale: ",
       "EDIT_POPOVER": {
         "TITLE": "Rinominare il portafoglio",
@@ -623,7 +624,7 @@
       "DOWNLOAD_REVOKE_HELP" : "Avere une file di revoca è necessario in caso di smarrimento delle tue credenziali. Ti permette <b> di rimuovere tuo conto dalla Rete di Fiducia</b>, per farlo tornare ad essere un semplice portafoglio.",
       "GENERATE_KEYFILE": "Genera il mio file portachiavi ...",
       "GENERATE_KEYFILE_HELP": "Genera un file che ti permette di autenticarti senza digitare le tue credenziali.<br/><b>Attenzione:</b> questo file contiene la tua chiave segreta: è perciò oltremodo importante salvarlo in un posto sicuro!",
-      "KEYFILE_FILENAME": "portachiavi-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-portachiavi-{{pubkey}}-{{format}}.dunikey",
       "MEMBERSHIP_IN": "Iscriviti come membro...",
       "MEMBERSHIP_IN_HELP": "Ti permette <b>convertire </b> un conto semplice <b>in un conto membro</b>, inviando una richiesta di adesione alla RdF. Utile solo se non sei già in possesso di un conto membro.",
       "SEND_IDENTITY": "Pubblica identità...",
@@ -659,9 +660,10 @@
       "REVOCATION_WITH_FILE_HELP": "Se hai <b>definitivamente perso le tue credenziali (o se la sicurezza del tuo conto è compromessa), puoi usare <b>il file di revoca</b> del conto <b>per uscire dalla Rete di Fiducia</b>.",
       "REVOCATION_WALLET": "Revocare immediatamente questo conto",
       "REVOCATION_WALLET_HELP": "Richiedere la cancellazione dell'identità <b>revocherà la tua adesione alla Rete di Fiducia</ b> (definitivamente per lo pseudonimo e per la chiave pubblica associata). Il conto non potrà più produrre il Dividendo Universale.<br/>Nonostante ciò, puoi ancora usare il conto come semplice portafoglio.",
-      "REVOCATION_FILENAME": "revocation-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revocation-{{uid}}-{{pubkey}}.txt",
       "SAVE_ID": "Salvare le mie credenziali...",
       "SAVE_ID_HELP": "Creare un file di backup, per <b>recuperare la tua password</b> (e l'identificativo segreto) <b> in caso di smarrimento</b>. Il file è <b>sicuro</ b> (cifrato) utilizzando le domande personalizzate.",
+      "SAVE_ID_FILENAME": "{{currency}}-credenziali-{{pubkey}}.txt",
       "STRONG_LEVEL": "Alto <span class=\"hidden-xs \">(minimo di 6 domande)</span>",
       "TITLE": "Conto e sicurezza",
         "KEYFILE": {
@@ -795,6 +797,7 @@
     "GET_BLOCK_FAILED": "Impossibile caricare il blocco",
     "INVALID_BLOCK_HASH": "Blocco non trovato (hash errato)",
     "DOWNLOAD_REVOCATION_FAILED": "Errore avvenuto nel download del file di cancellazione d'identità.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Scaricamento del file di backup delle credenziali non riuscito.",
     "REVOCATION_FAILED": "Errore avvenuto durante la richiesta di cancellazione dell'identità.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Identificativo segreto o password sbagliati",
     "RECOVER_ID_FAILED": "Impossibile recuperare la password",
@@ -819,7 +822,8 @@
     "INVALID_FILE_FORMAT": "Formato file invalido.",
     "SAME_TX_RECIPIENT": "Il destinatario deve essere diverso dall'emittente.",
     "SELF_CERTIFICATION": "Non puoi certificare la tua stessa identità.",
-    "TX_SANDBOX_FULL": "Il nodo Duniter utilizzato dal Cesium non può più elaborare nuovi trasferimenti, perché la lista d'attesa è piena.<br/><br/>Riprova più tardi o scegli un'altro nodo Duniter (nelle <b>Impostazioni</b>)."
+    "TX_SANDBOX_FULL": "Il nodo Duniter utilizzato dal Cesium non può più elaborare nuovi trasferimenti, perché la lista d'attesa è piena.<br/><br/>Riprova più tardi o scegli un'altro nodo Duniter (nelle <b>Impostazioni</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Errore nel scaricare l'estratto conto"
   },
   "INFO": {
     "POPUP_TITLE": "Informazioni",
@@ -836,7 +840,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "Cancellazione dell'identità <b>inviata con successo</b>. In attesa di validazione.",
     "FEATURES_NOT_IMPLEMENTED": "Questa funzionalità non è ancora disponibile.<br/><br/>Vuoi contribuire per velocizzarne la disponibilità? ;)",
     "EMPTY_TX_HISTORY": "Nessuna operazione da esportare",
-    "LOADING_PENDING_TX": "Caricando...<br/><small>(Recupero delle operazioni in sospeso)</small>"
+    "LOADING_PENDING_TX": "Caricando...<br/><small>(Recupero delle operazioni in sospeso)</small>",
+    "FILE_DOWNLOADED": "File scaricato"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Sei sicuro/a</b> di voler procedere?",
diff --git a/www/i18n/locale-nl-NL.json b/www/i18n/locale-nl-NL.json
index f04ac3aabe4c4e4b2f7ba906afdb27cecc17e58d..ab88116f227fe1c754170bae34e222a3ca089e6c 100644
--- a/www/i18n/locale-nl-NL.json
+++ b/www/i18n/locale-nl-NL.json
@@ -51,6 +51,7 @@
     "LOADING": "Even geduld...",
     "LOADING_WAIT": "Even geduld...<br/><small>(Cesium vraagt de Duniter-node op)</small>",
     "SEARCHING": "Zoeken...",
+    "DOWNLOADING_DOTS": "Downloaden...",
     "FROM": "Van",
     "TO": "Aan",
     "COPY": "Kopieren",
@@ -526,7 +527,10 @@
       "REMINDER_TITLE": "Herinnering",
       "SHORT_LICENSE_REMINDER": "Je kunt de persoon eraan herinneren verschillende certificeringsparameters te certificeren:<br/><br/><ul><li> - Elk lid kan maximaal 100 andere identiteiten certificeren.</li><li> - De certificeringen worden met een interval van 5 dagen opgeslagen.</li><li> - Een nieuwe identiteit moet in minder dan 2 maanden minstens 5 certificeringen verzamelen.</li><li> - Een lid moet minstens eenmaal per jaar zijn lidmaatschap vernieuwen.</li><li> - Certificeringen hebben een levensduur van twee jaar.</li></ul>"
     },
-    "FILE_NAME": "{{currency}} - Rekeningafschrift {{pubkey|formatPubkey}} {{currentTime|formatDateForFile}}.csv",
+    "SECURITY": {
+      "SAVE_ID_FILENAME": "{{currency}}-inloggegevens-{{pubkey}}.txt"
+    },
+    "FILE_NAME": "{{currency}}-rekeningafschrift-{{pubkey}}-{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
       "TIME": "Datum",
       "AMOUNT": "Bedrag",
@@ -579,6 +583,7 @@
     "GET_CURRENCY_PARAMETER": "Could not get currency parameters.",
     "GET_CURRENCY_FAILED": "Could not load currency.",
     "SEND_TX_FAILED": "Could not send transaction.",
+    "DOWNLOAD_SAVE_ID_FAILED": "Downloaden van het back-upbestand voor inloggegevens mislukt.",
     "ALL_SOURCES_USED": "Please wait the next block computation (All transaction sources has been used).",
     "NOT_ENOUGH_SOURCES": "Not enough changes to send this amount in one time.<br/>Maximum amount: {{amount}} {{unit}}<sub>{{subUnit}}</sub>.",
     "ACCOUNT_CREATION_FAILED": "Error while creating your member account.",
@@ -615,7 +620,8 @@
     "EXISTING_ACCOUNT": "Je gegevens komen overeen met een bestaande rekening, met de <a ng-click=\"showHelpModal('pubkey')\">publieke sleutel</a>:",
     "EXISTING_ACCOUNT_REQUEST": "Gelieve je gegevens te wijzigen zodat ze met een niet gebruikte rekening overeenkomen.",
     "SELF_CERTIFICATION": "U kunt uw eigen identiteit niet certificeren.",
-    "TX_SANDBOX_FULL": "De Duniter-peer die door Cesium wordt gebruikt, kan geen nieuwe overschrijvingen meer verwerken, omdat de wachtrij vol is.<br/><br/>Probeer het later opnieuw of wijzig de peer (in de <b>Instellingen</b>)."
+    "TX_SANDBOX_FULL": "De Duniter-peer die door Cesium wordt gebruikt, kan geen nieuwe overschrijvingen meer verwerken, omdat de wachtrij vol is.<br/><br/>Probeer het later opnieuw of wijzig de peer (in de <b>Instellingen</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Fout bij het downloaden van het rekeningoverzicht"
   },
   "INFO": {
     "POPUP_TITLE": "Informatie",
@@ -630,7 +636,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "Intrekking <b>is succesvol verzonden</b>. Het wacht op verwerking.",
     "FEATURE_NOT_AVAILABLE_ON_DEMO": "Functionaliteit niet beschikbaar op deze demonstratiesite.<br/>Om <b>veiligheidsredenen</b> raden we u aan uw kopie van de software te <b>installeren</b>.<br/>Bezoek de website <a href='https://cesium.app'>www.cesium.app</a> voor hulp.",
     "EMPTY_TX_HISTORY": "Aucune operatie à exporteur",
-    "LOADING_PENDING_TX": "Even geduld...<br/><small>(Ophalen van hangende operaties)</small>"
+    "LOADING_PENDING_TX": "Even geduld...<br/><small>(Ophalen van hangende operaties)</small>",
+    "FILE_DOWNLOADED": "Bestand gedownload"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Weet je zeker</b> dat je door wil gaan?",
diff --git a/www/i18n/locale-pt-PT.json b/www/i18n/locale-pt-PT.json
index b7fc19e1230402dda1720a18f5d0fe751bdf50ba..c3c716576b27ecfd570973212f0b77164c6f35b8 100644
--- a/www/i18n/locale-pt-PT.json
+++ b/www/i18n/locale-pt-PT.json
@@ -51,6 +51,7 @@
     "LOADING": "Aguarde por favor...",
     "LOADING_WAIT": "Aguarde por favor...<br/><small>(Cesium está a questionar o nó Duniter)</small>",
     "SEARCHING": "Procurando…",
+    "DOWNLOADING_DOTS": "Baixando...",
     "FROM": "De",
     "TO": "Para",
     "COPY": "Copiar",
@@ -693,7 +694,7 @@
       "NO_WALLET": "Sem carteira secundaria",
       "BTN_DELETE": "Eliminar una carteira secundaria…",
       "BTN_RENAME": "Renomear a carteira",
-      "EXPORT_FILENAME": "carteiras-{{pubkey|formatPubkey}}-{{currency}}.csv",
+      "EXPORT_FILENAME": "{{currency}}-carteiras-{{pubkey}}.csv",
       "TOTAL_DOTS": "Total : ",
       "EDIT_POPOVER": {
         "TITLE": "Renomear a carteira",
@@ -727,7 +728,7 @@
       "RECOVER_ID_SELECT_FILE": "Escolha o <b>arquivo para salvaguardar as suas credenciais</b> a utilizar :",
       "GENERATE_KEYFILE": "Gerar o meu arquivo de chaves…",
       "GENERATE_KEYFILE_HELP": "Gera um arquivo que permitirá autenticar se sem ter que introduzir as credenciais.<br/><b>Cuidado:</b> este arquivo conterá a sua chave secreta; É muito importante conservá-lo em lugar seguro!",
-      "KEYFILE_FILENAME": "llavero-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
+      "KEYFILE_FILENAME": "{{currency}}-llavero-{{pubkey}}{{format}}.dunikey",
       "MEMBERSHIP_IN": "Registar como membro…",
       "MEMBERSHIP_IN_HELP": "Permite <b>transformar</b> uma conta de carteira simples <b>numa conta membro</b>, enviando um pedido de membro. Apenas se ainda não possui uma conta membro.",
       "SEND_IDENTITY": "Publicar identidade…",
@@ -759,14 +760,15 @@
       "REVOCATION_WITH_FILE": "Revogar uma identidade a partir de um ficheiro",
       "REVOCATION_WITH_FILE_DESCRIPTION": "Se perdeu de forma permanente as credenciais da sua conta de membro (ou a segurança da conta foi comprometida), pode usar <b>o arquivo de revogação da conta</b> para forçar a saída da Rede de Confiança.",
       "REVOCATION_WITH_FILE_HELP": "Para <b>revogar permanentemente</b> uma conta de membro, arraste o arquivo de revogação no quadro seguinte ou faça clique no quadro para selecionar um arquivo.",
-      "REVOCATION_FILENAME": "revogação-{{uid}}-{{pubkey|formatPubkey}}-{{currency}}.txt",
+      "REVOCATION_FILENAME": "{{currency}}-revogação-{{uid}}-{{pubkey}}.txt",
       "REVOCATION_WALLET": "Revogar esta identidade",
       "SAVE_ID": "Guardar as minhas credenciais",
       "STRONG_LEVEL": "Alto <span class=\"hidden-xs \">(6 perguntas min.)</span>",
       "TITLE": "Conta e segurança",
       "RECOVER_ID_HELP": "Se possui um <b>arquivo de recuperação das suas credenciais</b>, pode recuperá-las respondendo corretamente às perguntas pessoais escolhidas por si.",
       "REVOCATION_WALLET_HELP": "Pedir a revogação da sua identidade acarreta a <b>saída da rede de confiança</b> (definitiva para o seu pseudónimo e a chave pública associada). A conta não produzirá mais o Dividendo Universal.<br/>Poderá continuar a usar carteira simples.",
-      "SAVE_ID_HELP": "Criação de um arquivo de recuperação, para <b>recuperar a sua contra senha</b> (e frase secreta) em caso de esquecimento. O arquivo <b>cifra-se</b> com a ajuda das perguntas pessoais escolhidas."
+      "SAVE_ID_HELP": "Criação de um arquivo de recuperação, para <b>recuperar a sua contra senha</b> (e frase secreta) em caso de esquecimento. O arquivo <b>cifra-se</b> com a ajuda das perguntas pessoais escolhidas.",
+      "SAVE_ID_FILENAME": "{{currency}}-credenciais-{{pubkey}}.txt"
     },
     "FILE_NAME": "{{currency}}_HistoricoDaConta_{{pubkey|formatPubkey}}_{{currentTime|formatDateForFile}}.csv",
     "HEADERS": {
@@ -889,6 +891,7 @@
     "GET_BLOCK_FAILED": "Falha na recuperação do bloco",
     "INVALID_BLOCK_HASH": "Bloco não encontrado (hash diferente)",
     "DOWNLOAD_REVOCATION_FAILED": "Deve selecionar um ficheiro de texto",
+    "DOWNLOAD_SAVE_ID_FAILED": "Falha no download do arquivo de backup das credenciais.",
     "REVOCATION_FAILED": "Falha na revogação.",
     "SALT_OR_PASSWORD_NOT_CONFIRMED": "Frase secreta o contra senha incorretos",
     "RECOVER_ID_FAILED": "Falha na recuperação das credenciais",
@@ -903,7 +906,8 @@
     "INVALID_FILE_FORMAT": "Formato de arquivo inválido.",
     "SAME_TX_RECIPIENT": "O destinatário deve ser diferente do emissor.",
     "SELF_CERTIFICATION": "Não pode certificar a sua própria identidade.",
-    "TX_SANDBOX_FULL": "O nó Duniter utilizado por Cesium já não pode receber mais novas transferências, porque a fila de espera está cheia.<br/><br/>Por favor, tente mais tarde ou mude de nó (nas <b>Definições</b>)."
+    "TX_SANDBOX_FULL": "O nó Duniter utilizado por Cesium já não pode receber mais novas transferências, porque a fila de espera está cheia.<br/><br/>Por favor, tente mais tarde ou mude de nó (nas <b>Definições</b>).",
+    "DOWNLOAD_TX_HISTORY_FAILED": "Erro ao baixar o extrato da conta"
   },
   "INFO": {
     "POPUP_TITLE": "Informação",
@@ -920,7 +924,8 @@
     "REVOCATION_SENT_WAITING_PROCESS": "A <b>revogação desta identidade</b> foi solicitada e aguarda ser processada.",
     "FEATURES_NOT_IMPLEMENTED": "Esta funcionalidade encontra-se em desenvolvimento.<br/><br/>Porque não <b>contribuir com Cesium</b>, para obtê-la mais rápido? ;)",
     "EMPTY_TX_HISTORY": "Nenhuma operação a exportar",
-    "LOADING_PENDING_TX": "Aguarde por favor...<br/><small>(A recuperar operações pendentes)</small>"
+    "LOADING_PENDING_TX": "Aguarde por favor...<br/><small>(A recuperar operações pendentes)</small>",
+    "FILE_DOWNLOADED": "Arquivo baixado"
   },
   "CONFIRM": {
     "CAN_CONTINUE": "<b>Deseja</b> continuar?",
diff --git a/www/js/controllers/wallet-controllers.js b/www/js/controllers/wallet-controllers.js
index fd5f693ca669a0995b8f82be678a784c56a263a2..d5652d211c89059925c69cdb886b2b7dbebadac1 100644
--- a/www/js/controllers/wallet-controllers.js
+++ b/www/js/controllers/wallet-controllers.js
@@ -794,7 +794,19 @@ function WalletTxController($scope, $ionicPopover, $state, $timeout, $location,
     options = options || {};
     options.fromTime = options.fromTime || -1; // default: full history
     var pubkey = $scope.formData.pubkey;
-    csTx.downloadHistoryFile(pubkey, options);
+
+    $scope.hideActionsPopover();
+
+    UIUtils.toast.show('COMMON.DOWNLOADING_DOTS');
+    return csTx.downloadHistoryFile(pubkey, options)
+      .then(UIUtils.toast.hide)
+      .then(function() {
+        UIUtils.toast.show('INFO.FILE_DOWNLOADED', 1000);
+      })
+      .catch(function(err){
+        if (err && err === 'CANCELLED') return;
+        UIUtils.onError('ERROR.DOWNLOAD_TX_HISTORY_FAILED')(err);
+      });
   };
 
   // Updating wallet data
@@ -979,6 +991,24 @@ function WalletTxController($scope, $ionicPopover, $state, $timeout, $location,
 
   /* -- popover -- */
 
+  $scope.showActionsPopover = function(event) {
+    UIUtils.popover.show(event, {
+      templateUrl: 'templates/wallet/popover_tx_actions.html',
+      scope: $scope,
+      autoremove: true,
+      afterShow: function(popover) {
+        $scope.actionsPopover = popover;
+      }
+    });
+  };
+
+  $scope.hideActionsPopover = function() {
+    if ($scope.actionsPopover) {
+      $scope.actionsPopover.hide();
+      $scope.actionsPopover = null;
+    }
+  };
+
   var paddingIndent = 10;
 
   $scope.toUnlockUIArray = function(unlockTreeItem, leftPadding, operator) {
@@ -1410,9 +1440,18 @@ function WalletSecurityModalController($scope, UIUtils, csConfig, csWallet, $tra
 
         return wallet.getCryptedId(record)
           .then(function(record){
-            wallet.downloadSaveId(record);
             $scope.closeModal();
-          });
+
+            return wallet.downloadSaveId(record)
+              .then(function() {
+                UIUtils.toast.show('INFO.FILE_DOWNLOADED', 1000);
+              })
+              .catch(function(err){
+                if (err && err === 'CANCELLED') return;
+                UIUtils.onError('ERROR.DOWNLOAD_SAVE_ID_FAILED')(err);
+              });
+          })
+          ;
       })
       ;
   };
@@ -1445,15 +1484,15 @@ function WalletSecurityModalController($scope, UIUtils, csConfig, csWallet, $tra
         return wallet.downloadRevocation();
       })
 
+      .then(UIUtils.loading.hide)
       .then(function() {
-        UIUtils.loading.hide();
+        UIUtils.toast.show('INFO.FILE_DOWNLOADED', 1000);
       })
 
       .catch(function(err){
         if (err && err === 'CANCELLED') return;
         UIUtils.onError('ERROR.DOWNLOAD_REVOCATION_FAILED')(err);
-      })
-      ;
+      });
 
   };
 
diff --git a/www/js/controllers/wot-controllers.js b/www/js/controllers/wot-controllers.js
index 5647e89ea42bfe68db45538cda5caa5e3786bead..efd55acc542700807c3e76bf26e52bf42e9c9980 100644
--- a/www/js/controllers/wot-controllers.js
+++ b/www/js/controllers/wot-controllers.js
@@ -1280,7 +1280,19 @@ function WotIdentityTxViewController($scope, $timeout, $q, BMA, csSettings, csWo
   $scope.downloadHistoryFile = function(options) {
     options = options || {};
     options.fromTime = options.fromTime || -1; // default: full history
-    csTx.downloadHistoryFile($scope.pubkey, options);
+
+    UIUtils.loading.show();
+
+    UIUtils.toast.show('INFO.DOWNLOADING_DOTS');
+    return csTx.downloadHistoryFile($scope.pubkey, options)
+      .then(UIUtils.toast.hide)
+      .then(function() {
+        UIUtils.toast.show('INFO.FILE_DOWNLOADED', 1000);
+      })
+      .catch(function(err){
+        if (err && err === 'CANCELLED') return;
+        UIUtils.onError('ERROR.DOWNLOAD_TX_HISTORY_FAILED')(err);
+      });
   };
 
   $scope.showMoreTx = function(fromTime) {
@@ -1309,6 +1321,25 @@ function WotIdentityTxViewController($scope, $timeout, $q, BMA, csSettings, csWo
       });
   };
 
+  /* -- popover -- */
+
+  $scope.showActionsPopover = function(event) {
+    UIUtils.popover.show(event, {
+      templateUrl: 'templates/wot/popover_tx_actions.html',
+      scope: $scope,
+      autoremove: true,
+      afterShow: function(popover) {
+        $scope.actionsPopover = popover;
+      }
+    });
+  };
+
+  $scope.hideActionsPopover = function() {
+    if ($scope.actionsPopover) {
+      $scope.actionsPopover.hide();
+      $scope.actionsPopover = null;
+    }
+  };
 }
 
 
diff --git a/www/js/services/bma-services.js b/www/js/services/bma-services.js
index 88e981c7b3824fba4355ff4df44c529fd9bfd19d..5ec007678dfd86ee279e65f20c849d7f2cea742a 100644
--- a/www/js/services/bma-services.js
+++ b/www/js/services/bma-services.js
@@ -233,12 +233,10 @@ angular.module('cesium.bma.services', ['ngApi', 'cesium.http.services', 'cesium.
             }
             throw err;
           });
-      }
+      };
       return wrappedRequest;
     }
 
-
-
     function incrementGetUsageCount(path, limitRequestCount) {
       limitRequestCount = limitRequestCount || constants.LIMIT_REQUEST_COUNT;
       // Wait if too many requests on this path
diff --git a/www/js/services/device-services.js b/www/js/services/device-services.js
index cf88f8f8937c055f314f7db513583a0fab47d8d1..9be7c7821907bcb22341919b014bf280c421b0b1 100644
--- a/www/js/services/device-services.js
+++ b/www/js/services/device-services.js
@@ -2,241 +2,382 @@ var App;
 
 angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.settings.services'])
 
-  .factory('Device', function($rootScope, $translate, $ionicPopup, $q, Api, csConfig,
-      // removeIf(no-device)
-      $cordovaClipboard, $cordovaBarcodeScanner, $cordovaCamera, $cordovaNetwork,
-      // endRemoveIf(no-device)
-      ionicReady) {
-      'ngInject';
-
-      var
-        CONST = {
-          MAX_HEIGHT: 400,
-          MAX_WIDTH: 400
-        },
-        api = new Api(this, "Device"),
-        exports = {
-          // workaround to quickly no is device or not (even before the ready() event)
-          enable: true
-        },
-        cache = {},
-        started = false,
-        startPromise,
-        listeners = {
-          online: undefined,
-          offline: undefined
-        }
-      ;
+  .factory('Device', function ($rootScope, $translate, $timeout, $ionicPopup, $q, Api, csConfig,
+                               // removeIf(no-device)
+                               $cordovaClipboard, $cordovaBarcodeScanner, $cordovaCamera, $cordovaNetwork,
+                               // endRemoveIf(no-device)
+                               ionicReady, UIUtils, Blob, FileSaver) {
+    'ngInject';
+
+    var
+      CONST = {
+        MAX_HEIGHT: 400,
+        MAX_WIDTH: 400,
+        UTF8_BOM_CHAR: new Uint8Array([0xEF, 0xBB, 0xBF]) // UTF-8 BOM
+      },
+      api = new Api(this, "Device"),
+      exports = {
+        // workaround to quickly no is device or not (even before the ready() event)
+        enable: true
+      },
+      cache = {},
+      started = false,
+      startPromise,
+      listeners = {
+        online: undefined,
+        offline: undefined
+      }
+    ;
 
-      // removeIf(device)
-      // workaround to quickly no is device or not (even before the ready() event)
-      exports.enable = false;
-      // endRemoveIf(device)
+    // removeIf(device)
+    // workaround to quickly no is device or not (even before the ready() event)
+    exports.enable = false;
 
-      function getPicture(options) {
-        if (!exports.camera.enable) {
-          return $q.reject("Camera not enable. Please call 'ionicReady()' once before use (e.g in app.js).");
-        }
+    // endRemoveIf(device)
 
-        // Options is the sourceType by default
-        if (options && (typeof options === "string")) {
-          options = {
-            sourceType: options
-          };
-        }
-        options = options || {};
-
-        // Make sure a source type has been given (if not, ask user)
-        if (angular.isUndefined(options.sourceType)) {
-          return $translate(['SYSTEM.PICTURE_CHOOSE_TYPE', 'SYSTEM.BTN_PICTURE_GALLERY', 'SYSTEM.BTN_PICTURE_CAMERA'])
-            .then(function(translations){
-              return $ionicPopup.show({
-                title: translations['SYSTEM.PICTURE_CHOOSE_TYPE'],
-                buttons: [
-                  {
-                    text: translations['SYSTEM.BTN_PICTURE_GALLERY'],
-                    type: 'button',
-                    onTap: function(e) {
-                      return navigator.camera.PictureSourceType.PHOTOLIBRARY;
-                    }
-                  },
-                  {
-                    text: translations['SYSTEM.BTN_PICTURE_CAMERA'],
-                    type: 'button button-positive',
-                    onTap: function(e) {
-                      return navigator.camera.PictureSourceType.CAMERA;
-                    }
+    function getPicture(options) {
+      if (!exports.camera.enable) {
+        return $q.reject("Camera not enable. Please call 'ionicReady()' once before use (e.g in app.js).");
+      }
+
+      // Options is the sourceType by default
+      if (options && (typeof options === "string")) {
+        options = {
+          sourceType: options
+        };
+      }
+      options = options || {};
+
+      // Make sure a source type has been given (if not, ask user)
+      if (angular.isUndefined(options.sourceType)) {
+        return $translate(['SYSTEM.PICTURE_CHOOSE_TYPE', 'SYSTEM.BTN_PICTURE_GALLERY', 'SYSTEM.BTN_PICTURE_CAMERA'])
+          .then(function (translations) {
+            return $ionicPopup.show({
+              title: translations['SYSTEM.PICTURE_CHOOSE_TYPE'],
+              buttons: [
+                {
+                  text: translations['SYSTEM.BTN_PICTURE_GALLERY'],
+                  type: 'button',
+                  onTap: function (e) {
+                    return navigator.camera.PictureSourceType.PHOTOLIBRARY;
+                  }
+                },
+                {
+                  text: translations['SYSTEM.BTN_PICTURE_CAMERA'],
+                  type: 'button button-positive',
+                  onTap: function (e) {
+                    return navigator.camera.PictureSourceType.CAMERA;
                   }
-                ]
-              })
-              .then(function(sourceType){
+                }
+              ]
+            })
+              .then(function (sourceType) {
                 console.info('[camera] User select sourceType:' + sourceType);
                 options.sourceType = sourceType;
                 return exports.camera.getPicture(options);
               });
-            });
-        }
+          });
+      }
 
-        options.quality = options.quality || 50;
-        options.destinationType = options.destinationType || navigator.camera.DestinationType.DATA_URL;
-        options.encodingType = options.encodingType || navigator.camera.EncodingType.PNG;
-        options.targetWidth = options.targetWidth || CONST.MAX_WIDTH;
-        options.targetHeight = options.targetHeight || CONST.MAX_HEIGHT;
-        return $cordovaCamera.getPicture(options);
+      options.quality = options.quality || 50;
+      options.destinationType = options.destinationType || navigator.camera.DestinationType.DATA_URL;
+      options.encodingType = options.encodingType || navigator.camera.EncodingType.PNG;
+      options.targetWidth = options.targetWidth || CONST.MAX_WIDTH;
+      options.targetHeight = options.targetHeight || CONST.MAX_HEIGHT;
+      return $cordovaCamera.getPicture(options);
+    }
+
+    function scan(n) {
+      if (!exports.enable) {
+        return $q.reject("Barcode scanner not enable. Please call 'ionicReady()' once before use (e.g in app.js).");
       }
+      var deferred = $q.defer();
+      cordova.plugins.barcodeScanner.scan(
+        function (result) {
+          if (!result.cancelled) {
+            console.debug('[device] barcode scanner scan: ' + result.text);
+            deferred.resolve(result.text); // make sure to convert into String
+          } else {
+            console.debug('[device] barcode scanner scan: CANCELLED');
+            deferred.resolve();
+          }
+        },
+        function (err) {
+          console.error('[device] Error while using barcode scanner: ' + err);
+          deferred.reject(err);
+        },
+        n);
+      return deferred.promise;
+    }
 
-      function scan(n) {
-        if (!exports.enable) {
-          return $q.reject("Barcode scanner not enable. Please call 'ionicReady()' once before use (e.g in app.js).");
-        }
-        var deferred = $q.defer();
-        cordova.plugins.barcodeScanner.scan(
-          function(result) {
-            if (!result.cancelled) {
-              console.debug('[device] barcode scanner scan: ' + result.text);
-              deferred.resolve(result.text); // make sure to convert into String
-            }
-            else {
-              console.debug('[device] barcode scanner scan: CANCELLED');
-              deferred.resolve();
-            }
-          },
-          function(err) {
-            console.error('[device] Error while using barcode scanner: ' + err);
-            deferred.reject(err);
-          },
-          n);
-        return deferred.promise;
+    function copy(text, callback) {
+      if (!exports.enable) {
+        return $q.reject('Device disabled');
+      }
+      var deferred = $q.defer();
+      $cordovaClipboard
+        .copy(text)
+        .then(function () {
+          // success
+          if (callback) {
+            callback();
+          }
+          deferred.resolve();
+        }, function () {
+          // error
+          deferred.reject({message: 'ERROR.COPY_CLIPBOARD'});
+        });
+      return deferred.promise;
+    }
+
+    exports.clipboard = {copy: copy};
+    exports.camera = {
+      getPicture: getPicture,
+      scan: function (n) {
+        console.warn('Deprecated use of Device.camera.scan(). Use Device.barcode.scan() instead');
+        return scan(n);
       }
+    };
+    exports.barcode = {
+      enable: false,
+      scan: scan
+    };
+    exports.keyboard = {
+      enable: false,
+      close: function () {
+        if (!exports.keyboard.enable) return;
+        cordova.plugins.Keyboard.close();
+      }
+    };
+    exports.network = {
+      connectionType: function () {
+        if (!exports.network.enable) return 'unknown';
+        try {
+          return navigator.connection.type || 'unknown';
+        } catch (err) {
+          console.error('[device] Cannot get connection type: ' + (err && err.message || err), err);
+          return 'unknown';
+        }
+      },
+      isOnline: function () {
+        try {
+          return navigator.connection.type !== Connection.NONE;
+        } catch (err) {
+          console.error('[device] Cannot check if online: ' + (err && err.message || err), err);
+          return true;
+        }
+      },
+      isOffline: function () {
+        try {
+          return navigator.connection.type === Connection.NONE;
+        } catch (err) {
+          console.error('[device] Cannot check if offline: ' + (err && err.message || err), err);
+          return true;
+        }
+        return false;
+      },
+      timeout: function (defaultTimeout) {
+        defaultTimeout = defaultTimeout || csConfig.timeout;
+        var timeout;
+        try {
+          var connectionType = exports.network.connectionType();
+
+          // If desktop: use ethernet as default connection type
+          if (connectionType === 'unknown' && exports.isDesktop()) {
+            connectionType = 'ethernet';
+          }
 
-      function copy(text, callback) {
-        if (!exports.enable) {
-          return $q.reject('Device disabled');
+          switch (connectionType) {
+            case 'ethernet':
+              timeout = 1000; // 1 s
+              break;
+            case 'wifi':
+              timeout = 2000;
+              break;
+            case 'cell': // (e.g. iOS)
+            case 'cell_5g':
+              timeout = 3000;
+              break;
+            case 'cell_4g':
+              timeout = 5000;
+              break;
+            case 'cell_3g':
+              timeout = 10000; // 10s
+              break;
+            case 'cell_2g':
+              timeout = 40000; // 40s
+              break;
+            case 'none':
+              timeout = 0;
+              break;
+            case 'unknown':
+            default:
+              timeout = defaultTimeout;
+              break;
+          }
+          console.debug('[device] Using timeout: {1}ms (connection type: \'{0}\')'.format(connectionType, timeout));
+
+          return timeout;
+        } catch (err) {
+          console.error('[device] Error while trying to get connection type: ' + (err && err.message || err));
+          return defaultTimeout;
         }
-        var deferred = $q.defer();
-        $cordovaClipboard
-          .copy(text)
-          .then(function () {
-            // success
-            if (callback) {
-              callback();
-            }
-            deferred.resolve();
-          }, function () {
-            // error
-            deferred.reject({message: 'ERROR.COPY_CLIPBOARD'});
+      }
+    };
+
+    exports.downloader = {
+      enable: false,
+      download: function(request) {
+        return $q(function(resolve, reject) {
+          if (!exports.downloader.enable) return reject("Cordova Downloaded plugin is not enable!");
+          if (!request) return reject("Missing request argument");
+
+          console.debug('[device] Downloading file from request: ' + JSON.stringify(request));
+
+          cordova.plugins.Downloader.download(request, function(location) {
+            console.info("[device] Successfully download file at '{0}'".format(location));
+            resolve(location);
+          }, function(err) {
+            console.error('[device] Cannot download, from given request', request);
+            reject(err);
           });
-        return deferred.promise;
+        });
       }
+    };
+    exports.file = {
+      enable: false,
+      started: false,
+      ready: function() {
+        if (exports.file.started) return $q.when();
+        return $q(function(resolve) {
+          window.addEventListener('filePluginIsReady', function() {
+
+            console.debug('[device] [file] Plugin is ready');
+
+            // DEBUG: dump available directory
+            Object.keys(cordova.file).forEach(function(key) {
+              console.debug('[device] [file] - cordova.file.{0}: '.format(key) + cordova.file[key]);
+            });
 
-      exports.clipboard = {copy: copy};
-      exports.camera = {
-          getPicture : getPicture,
-          scan: function(n){
-            console.warn('Deprecated use of Device.camera.scan(). Use Device.barcode.scan() instead');
-            return scan(n);
-          }
-        };
-      exports.barcode = {
-        enable : false,
-        scan: scan
-      };
-      exports.keyboard = {
-        enable: false,
-        close: function() {
-          if (!exports.keyboard.enable) return;
-          cordova.plugins.Keyboard.close();
+            exports.file.started = true;
+            resolve();
+          }, false);
+        });
+      },
+      save: function(content, options) {
+
+        var filename = options && options.filename || 'export.txt';
+        var charset = (options && options.encoding || 'utf-8').toLowerCase();
+        var type = options && options.type || 'text/plain';
+        var withBOM = charset === 'utf-8' && (!options || options.withBOM !== false);
+        var showToast = options && options.showToast || false;
+
+        // Use Cordova file plugin
+        if (exports.file.enable) {
+
+          var directory = options && options.directory || (exports.isAndroid() ?
+            cordova.file.externalRootDirectory + 'Download' :
+            cordova.file.documentsDirectory);
+          var fullPath = (directory.endsWith('/') ? directory : (directory + '/')) + filename;
+          console.debug("[device] [file] Saving file '{0}' (using Cordova)...".format(fullPath));
+
+          return $q(function (resolve, reject) {
+
+            var onError = function (err) {
+              console.error("[device] [file] Error while creating file '{0}': {1}".format(fullPath, err ? JSON.stringify(err): 'Unknown error'));
+              reject(err || 'Cannot create file ' + filename);
+            };
+
+            window.resolveLocalFileSystemURL(directory, function (directoryEntry) {
+              directoryEntry.getFile(filename, {create: true}, function (fileEntry) {
+
+                fileEntry.createWriter(function (fileWriter) {
+                  fileWriter.onwriteend = function () {
+                    console.debug("[device] [file] Successfully save file '{0}'".format(fullPath));
+                    resolve(fullPath);
+                  };
+                  fileWriter.onerror = function (e) {
+                    onError();
+                  };
+                  var blob = new Blob(
+                    // Add UTF-8 BOM character (if enable)
+                    withBOM ? [CONST.UTF8_BOM_CHAR, content] : [content],
+                    {type: "{0};charset={1};".format(type, charset)});
+                  fileWriter.write(blob);
+                }, onError);
+              }, onError);
+            }, onError);
+          })
+            .then(function (uri) {
+              if (showToast) {
+                UIUtils.toast.show('INFO.FILE_DOWNLOADED', 1000);
+              }
+              return uri;
+            });
         }
-      };
-      exports.network = {
-        connectionType: function() {
-          if (!exports.network.enable) return  'unknown';
-          try {
-            return navigator.connection.type || 'unknown';
-          }
-          catch(err) {
-            console.error('[device] Cannot get connection type: ' + (err && err.message || err), err);
-            return 'unknown';
-          }
-        },
-        isOnline: function() {
-          try {
-            return navigator.connection.type !== Connection.NONE;
-          }
-          catch(err) {
-            console.error('[device] Cannot check if online: ' + (err && err.message || err), err);
-            return true;
-          }
-        },
-        isOffline: function() {
-          try {
-            return navigator.connection.type === Connection.NONE;
+
+        // Fallback to browser download
+        else {
+          console.debug("[device] [file] Saving file '{0}'...".format(filename));
+
+          var blob = new Blob(
+            // Add UTF-8 BOM character (if enable)
+            withBOM ? [CONST.UTF8_BOM_CHAR, content] : [content],
+            {type: "{0};charset={1};".format(type, charset)});
+
+          return FileSaver.saveAs(blob, filename, true /*disable auto BOM*/);
+        }
+      },
+
+      uri: {
+        getFilename: function (uri) {
+          if (!uri) return uri;
+          var filename = uri.trim();
+
+          // Get last part (or all string, if no '/')
+          var lastSlashIndex = filename.lastIndexOf('/');
+          if (lastSlashIndex !== -1 && lastSlashIndex !== uri.length - 1) {
+            filename = filename.substring(lastSlashIndex + 1);
           }
-          catch(err) {
-            console.error('[device] Cannot check if offline: ' + (err && err.message || err), err);
-            return true;
+
+          // Remove query params
+          var queryParamIndex = filename.indexOf('?');
+          if (queryParamIndex !== -1) {
+            filename = filename.substring(0, queryParamIndex);
           }
-          return false;
+
+          return filename;
         },
-        timeout: function(defaultTimeout) {
-          defaultTimeout = defaultTimeout || csConfig.timeout;
-          var timeout;
-          try {
-            var connectionType = exports.network.connectionType();
-
-            // If desktop: use ethernet as default connection type
-            if (connectionType === 'unknown' && exports.isDesktop()) {
-              connectionType = 'ethernet';
-            }
 
-            switch (connectionType) {
-              case 'ethernet':
-                timeout = 1000; // 1 s
-                break;
-              case 'wifi':
-                timeout = 2000;
-                break;
-              case 'cell': // (e.g. iOS)
-              case 'cell_5g':
-                timeout = 3000;
-                break;
-              case 'cell_4g':
-                timeout = 5000;
-                break;
-              case 'cell_3g':
-                timeout = 10000; // 10s
-                break;
-              case 'cell_2g':
-                timeout = 40000; // 40s
-                break;
-              case 'none':
-                timeout = 0;
-                break;
-              case 'unknown':
-              default:
-                timeout = defaultTimeout;
-                break;
-            }
-            console.debug('[device] Using timeout: {1}ms (connection type: \'{0}\')'.format(connectionType, timeout));
+        getDirectory: function (uri) {
+          if (!uri) return uri;
+          var directory = uri.trim();
 
-            return timeout;
-          } catch(err) {
-            console.error('[device] Error while trying to get connection type: ' + (err && err.message || err));
-            return defaultTimeout;
+          // Already a folder
+          if (directory.endsWith('/')) return directory;
+
+          // Get part before the last slash
+          var lastSlashIndex = directory.lastIndexOf('/');
+          if (lastSlashIndex !== -1 && lastSlashIndex !== directory.length - 1) {
+            return directory.substring(0, lastSlashIndex+1);
           }
+
+          return directory;
         }
-      };
-
-      function getLastIntent() {
-        var deferred = $q.defer();
-        window.plugins.launchmyapp.getLastIntent(
-          deferred.resolve,
-          deferred.reject);
-        return deferred.promise;
       }
 
+    };
+
+    function getLastIntent() {
+      var deferred = $q.defer();
+      window.plugins.launchmyapp.getLastIntent(
+        deferred.resolve,
+        deferred.reject);
+      return deferred.promise;
+    }
+
     // WARN: Need by cordova-plugin-customurlscheme
-    window.handleOpenURL = function(intent) {
+    window.handleOpenURL = function (intent) {
       if (intent) {
         console.info('[device] Received new intent: ', intent);
         cache.lastIntent = intent; // Remember, for last()
@@ -245,178 +386,189 @@ angular.module('cesium.device.services', ['cesium.utils.services', 'cesium.setti
     };
 
     exports.intent = {
-        enable: false,
-        last: function() {
-          return $q.when(cache.lastIntent);
-        },
-        clear: function() {
-          cache.lastIntent = undefined;
-        }
-      };
-
-      // Numerical keyboard - fix #30
-      exports.keyboard.digit = {
-        settings: {
-          bindModel: function(modelScope, modelPath, settings) {
-            settings = settings || {};
-            modelScope = modelScope || $rootScope;
-            var getModelValue = function() {
-              return (modelPath||'').split('.').reduce(function(res, path) {
-                return res ? res[path] : undefined;
-              }, modelScope);
-            };
-            var setModelValue = function(value) {
-              var paths = (modelPath||'').split('.');
-              var property = paths.length && paths[paths.length-1];
-              paths.reduce(function(res, path) {
-                if (path == property) {
-                  res[property] = value;
-                  return;
-                }
-                return res[path];
-              }, modelScope);
-            };
+      enable: false,
+      last: function () {
+        return $q.when(cache.lastIntent);
+      },
+      clear: function () {
+        cache.lastIntent = undefined;
+      }
+    };
 
-            settings.animation = settings.animation || 'pop';
-            settings.action = settings.action || function(number) {
-                setModelValue((getModelValue() ||'') + number);
-              };
-            if (settings.decimal) {
-              settings.decimalSeparator = settings.decimalSeparator || '.';
-              settings.leftButton = {
-                html: '<span>.</span>',
-                action: function () {
-                  var text = getModelValue() || '';
-                  // only one '.' allowed
-                  if (text.indexOf(settings.decimalSeparator) >= 0) return;
-                  // Auto add zero when started with '.'
-                  if (!text.trim().length) {
-                    text = '0';
-                  }
-                  setModelValue(text + settings.decimalSeparator);
-                }
-              };
-            }
-            settings.rightButton = settings.rightButton || {
-                html: '<i class="icon ion-backspace-outline"></i>',
-                action: function() {
-                  var text = getModelValue();
-                  if (text && text.length) {
-                    text = text.slice(0, -1);
-                    setModelValue(text);
-                  }
+    // Numerical keyboard - fix #30
+    exports.keyboard.digit = {
+      settings: {
+        bindModel: function (modelScope, modelPath, settings) {
+          settings = settings || {};
+          modelScope = modelScope || $rootScope;
+          var getModelValue = function () {
+            return (modelPath || '').split('.').reduce(function (res, path) {
+              return res ? res[path] : undefined;
+            }, modelScope);
+          };
+          var setModelValue = function (value) {
+            var paths = (modelPath || '').split('.');
+            var property = paths.length && paths[paths.length - 1];
+            paths.reduce(function (res, path) {
+              if (path == property) {
+                res[property] = value;
+                return;
+              }
+              return res[path];
+            }, modelScope);
+          };
+
+          settings.animation = settings.animation || 'pop';
+          settings.action = settings.action || function (number) {
+            setModelValue((getModelValue() || '') + number);
+          };
+          if (settings.decimal) {
+            settings.decimalSeparator = settings.decimalSeparator || '.';
+            settings.leftButton = {
+              html: '<span>.</span>',
+              action: function () {
+                var text = getModelValue() || '';
+                // only one '.' allowed
+                if (text.indexOf(settings.decimalSeparator) >= 0) return;
+                // Auto add zero when started with '.'
+                if (!text.trim().length) {
+                  text = '0';
                 }
-              };
-            return settings;
-          }
-        }
-      };
-
-      exports.isOSX = function() {
-        return !!navigator.userAgent.match(/Macintosh/i) || ionic.Platform.is("osx");
-      };
-
-      exports.isIOS = function() {
-        return !!navigator.userAgent.match(/iPhone | iPad | iPod/i) || (!!navigator.userAgent.match(/Mobile/i) && !!navigator.userAgent.match(/Macintosh/i)) || ionic.Platform.isIOS();
-      };
-
-      exports.isWindows = function() {
-        return !!navigator.userAgent.match(/Windows/i) || ionic.Platform.is("windows");
-      };
-
-      exports.isUbuntu = function() {
-        return !!navigator.userAgent.match(/Ubuntu|Linux x86_64/i) || ionic.Platform.is("ubuntu");
-      };
-
-      exports.isDesktop = function() {
-        if (!angular.isDefined(cache.isDesktop)) {
-          try {
-
-            cache.isDesktop = !exports.enable && (
-              exports.isUbuntu() ||
-              exports.isWindows() ||
-              exports.isOSX() ||
-              // Should have NodeJs and NW
-              (!!process && !!nw && !!nw.App)
-            );
-          } catch (err) {
-            // If error (e.g. 'process not defined')
-            cache.isDesktop = false;
+                setModelValue(text + settings.decimalSeparator);
+              }
+            };
           }
+          settings.rightButton = settings.rightButton || {
+            html: '<i class="icon ion-backspace-outline"></i>',
+            action: function () {
+              var text = getModelValue();
+              if (text && text.length) {
+                text = text.slice(0, -1);
+                setModelValue(text);
+              }
+            }
+          };
+          return settings;
         }
-        return cache.isDesktop;
-      };
+      }
+    };
 
-      exports.isWeb = function() {
-        return !exports.enable && !exports.isDesktop();
-      };
+    exports.isAndroid = function () {
+      return !!navigator.userAgent.match(/Android/i) || ionic.Platform.is("android");
+    };
 
-      exports.ready = function() {
-        if (started) return $q.when();
-        return startPromise || exports.start();
-      };
+    exports.isOSX = function () {
+      return !!navigator.userAgent.match(/Macintosh/i) || ionic.Platform.is("osx");
+    };
 
-      exports.start = function() {
+    exports.isIOS = function () {
+      return !!navigator.userAgent.match(/iPhone | iPad | iPod/i) || (!!navigator.userAgent.match(/Mobile/i) && !!navigator.userAgent.match(/Macintosh/i)) || ionic.Platform.isIOS();
+    };
 
-        startPromise = ionicReady()
-          .then(function() {
+    exports.isWindows = function () {
+      return !!navigator.userAgent.match(/Windows/i) || ionic.Platform.is("windows");
+    };
 
-            exports.enable = window.cordova && cordova && !!cordova.plugins || false;
+    exports.isUbuntu = function () {
+      return !!navigator.userAgent.match(/Ubuntu|Linux x86_64/i) || ionic.Platform.is("ubuntu");
+    };
 
-            if (exports.enable) {
-              exports.camera.enable = !!navigator.camera;
-              exports.keyboard.enable = cordova && cordova.plugins && !!cordova.plugins.Keyboard;
-              exports.barcode.enable = cordova && cordova.plugins && !!cordova.plugins.barcodeScanner && (!exports.isOSX() || exports.isIOS());
-              exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard;
-              exports.intent.enable = window && !!window.plugins.launchmyapp;
-              exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard;
-              exports.network.enable = navigator.connection && !!navigator.connection.type;
+    exports.isDesktop = function () {
+      if (!angular.isDefined(cache.isDesktop)) {
+        try {
+
+          cache.isDesktop = !exports.enable && (
+            exports.isUbuntu() ||
+            exports.isWindows() ||
+            exports.isOSX() ||
+            // Should have NodeJs and NW
+            (!!process && !!nw && !!nw.App)
+          );
+        } catch (err) {
+          // If error (e.g. 'process not defined')
+          cache.isDesktop = false;
+        }
+      }
+      return cache.isDesktop;
+    };
 
-              if (exports.keyboard.enable) {
-                angular.extend(exports.keyboard, cordova.plugins.Keyboard);
-              }
+    exports.isWeb = function () {
+      return !exports.enable && !exports.isDesktop();
+    };
 
-              console.debug('[device] Cordova plugins: ' + Object.keys(cordova.plugins));
-              console.debug('[device] Windows plugins: ' + Object.keys(window.plugins));
-              console.debug('[device] Ionic platform ready, with {camera: {0}, barcode: {1}, keyboard: {2}, clipboard: {3}, intent: {4}, network: {5}}'
-                .format(exports.camera.enable, exports.barcode.enable, exports.keyboard.enable, exports.clipboard.enable, exports.intent.enable, exports.network.enable));
+    exports.ready = function () {
+      if (started) return $q.when();
+      return startPromise || exports.start();
+    };
 
-              if (cordova.InAppBrowser) {
-                console.debug('[device] Enabling InAppBrowser');
-                window.open = cordova.InAppBrowser.open;
-              }
+    exports.start = function () {
+      startPromise = ionicReady()
+        .then(function () {
 
-              // Add network listeners
-              if (exports.network.enable) {
-                document.addEventListener("offline", function() {
-                  console.info('[device] Network is offline');
-                  api.network.raise.offline();
-                }, false);
-                document.addEventListener("online", function() {
-                  console.info('[device] Network is online');
-                  api.network.raise.online();
-                }, false);
-              }
+          exports.enable = window.cordova && cordova && !!cordova.plugins || false;
+          if (exports.enable) {
+
+            console.debug('[device] Cordova plugins: ' + Object.keys(cordova.plugins));
+            console.debug('[device] Windows plugins: ' + Object.keys(window.plugins));
+
+            exports.camera.enable = !!navigator.camera;
+            exports.keyboard.enable = cordova && cordova.plugins && !!cordova.plugins.Keyboard;
+            exports.barcode.enable = cordova && cordova.plugins && !!cordova.plugins.barcodeScanner && (!exports.isOSX() || exports.isIOS());
+            exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard;
+            exports.intent.enable = window && !!window.plugins.launchmyapp;
+            exports.clipboard.enable = cordova && cordova.plugins && !!cordova.plugins.clipboard;
+            exports.network.enable = navigator.connection && !!navigator.connection.type;
+            exports.file.enable = !!cordova.file && (exports.isAndroid() || exports.isIOS());
+
+            if (exports.keyboard.enable) {
+              angular.extend(exports.keyboard, cordova.plugins.Keyboard);
             }
-            else {
-              console.debug('[device] Ionic platform ready - no device detected.');
+
+            console.info('[device] Ionic platform ready, with {camera: {0}, barcode: {1}, keyboard: {2}, clipboard: {3}, intent: {4}, network: {5}, file: {6}}'
+              .format(exports.camera.enable,
+                exports.barcode.enable,
+                exports.keyboard.enable,
+                exports.clipboard.enable,
+                exports.intent.enable,
+                exports.network.enable,
+                exports.file.enable
+              ));
+
+            if (cordova.InAppBrowser) {
+              console.debug('[device] Enabling InAppBrowser');
+              window.open = cordova.InAppBrowser.open;
             }
 
-            started = true;
-            startPromise = null;
-          });
+            // Add network listeners
+            if (exports.network.enable) {
+              document.addEventListener("offline", function () {
+                console.info('[device] Network is offline');
+                api.network.raise.offline();
+              }, false);
+              document.addEventListener("online", function () {
+                console.info('[device] Network is online');
+                api.network.raise.online();
+              }, false);
+            }
+          } else {
+            console.debug('[device] Ionic platform ready - no device detected.');
+          }
+
+          started = true;
+          startPromise = null;
+        });
 
-        return startPromise;
-      };
+      return startPromise;
+    };
 
-      api.registerEvent('intent', 'new');
-      api.registerEvent('network', 'offline');
-      api.registerEvent('network', 'online');
+    api.registerEvent('intent', 'new');
+    api.registerEvent('network', 'offline');
+    api.registerEvent('network', 'online');
 
-      // Export the event api (see ngApi)
-      exports.api = api;
+    // Export the event api (see ngApi)
+    exports.api = api;
 
-      return exports;
-    })
+    return exports;
+  })
 
-  ;
+;
diff --git a/www/js/services/http-services.js b/www/js/services/http-services.js
index fad7d944e44ff1f45726e3e10096bdee9ac61699..1ccd538cbacb98deca8b80fef954ac444aff409c 100644
--- a/www/js/services/http-services.js
+++ b/www/js/services/http-services.js
@@ -385,11 +385,11 @@ angular.module('cesium.http.services', ['cesium.cache.services'])
 
     var searchParams;
     if (parser.search && parser.search.startsWith('?')) {
-      searchParams = parser.search.substr(1).split('&')
+      searchParams = parser.search.substring(1).split('&')
         .reduce(function(res, searchParam) {
           if (searchParam.indexOf('=') !== -1) {
-            var key = searchParam.substr(0, searchParam.indexOf('='));
-            var value = searchParam.substr(searchParam.indexOf('=') + 1);
+            var key = searchParam.substring(0, searchParam.indexOf('='));
+            var value = searchParam.substring(searchParam.indexOf('=') + 1);
             res[key] = value;
           }
           else {
diff --git a/www/js/services/tx-services.js b/www/js/services/tx-services.js
index ad9aa288872c15ae4cbe641554c3c409296ec122..e68cd08538ff72bcfb96fc5e91c6abb12de69ad3 100644
--- a/www/js/services/tx-services.js
+++ b/www/js/services/tx-services.js
@@ -2,7 +2,7 @@
 angular.module('cesium.tx.services', ['ngApi', 'cesium.bma.services',
   'cesium.settings.services', 'cesium.wot.services' ])
 
-.factory('csTx', function($q, $timeout, $filter, $translate, FileSaver, UIUtils, BMA, Api,
+.factory('csTx', function($q, $timeout, $filter, $translate, FileSaver, UIUtils, Device, BMA, Api,
                           csConfig, csSettings, csWot, csCurrency) {
   'ngInject';
 
@@ -458,11 +458,9 @@ angular.module('cesium.tx.services', ['ngApi', 'cesium.bma.services',
                 tx.pubkey,
                 formatDecimal(tx.amount/100),
                 '"' + (tx.isUD ? translations['COMMON.UNIVERSAL_DIVIDEND'] : tx.comment) + '"'
-              ].join(';') + '\n');
-            }, [headers.join(';') + '\n']);
-
-            var file = new Blob(content, {type: 'text/plain; charset=utf-8'});
-            FileSaver.saveAs(file, filename);
+              ].join(';'));
+            }, [headers.join(';')]).join('\n');
+            return Device.file.save(content, {filename: filename});
           });
       });
   }
diff --git a/www/js/services/wallet-services.js b/www/js/services/wallet-services.js
index 49b1b2ad9436e25028902ca3a21264b974ece1a4..5efc800d7035634fe2a17f28d936ce22393783eb 100644
--- a/www/js/services/wallet-services.js
+++ b/www/js/services/wallet-services.js
@@ -4,8 +4,8 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
 
 
 .factory('csWallet', function($q, $rootScope, $timeout, $translate, $filter, $ionicHistory, UIUtils,
-                              Api, Idle, localStorage, sessionStorage, Modals,
-                              CryptoUtils, csCrypto, BMA, csConfig, csSettings, FileSaver, Blob, csWot, csTx, csCurrency) {
+                              Api, Idle, localStorage, sessionStorage, Modals, Device,
+                              CryptoUtils, csCrypto, BMA, csConfig, csSettings, FileSaver, csWot, csTx, csCurrency) {
   'ngInject';
 
   var defaultBMA = BMA;
@@ -1875,10 +1875,21 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
     },
 
     downloadSaveId = function(record){
-      return getSaveIDDocument(record)
-        .then(function(saveId) {
-          var saveIdFile = new Blob([saveId], {type: 'text/plain; charset=utf-8'});
-          FileSaver.saveAs(saveIdFile, '{0}-recover_ID.txt'.format(data.pubkey.substring(0,8)));
+
+      return $q.all([
+        csCurrency.get(),
+        getSaveIDDocument(record),
+      ])
+        .then(function(res) {
+          var currency = res[0];
+          var document= res[1];
+          return $translate('ACCOUNT.SECURITY.SAVE_ID_FILENAME', {
+            currency: currency.name,
+            pubkey: data.pubkey
+          })
+            .then(function(filename){
+              return Device.file.save(document, {filename: filename});
+            });
         });
     },
 
@@ -1914,8 +1925,7 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
               format: format,
             })
             .then(function(filename){
-              var file = new Blob([document], {type: 'text/plain; charset=utf-8'});
-              FileSaver.saveAs(file, filename);
+              return Device.file.save(document, {filename: filename});
             });
         });
 
@@ -2026,7 +2036,6 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
             addEvent({type: 'pending', message: 'INFO.REVOCATION_SENT_WAITING_PROCESS', context: 'requirements'}, true);
           }
         });
-
     },
 
     downloadRevocation = function(){
@@ -2037,14 +2046,13 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
         .then(function(res) {
           var currency = res[0];
           var revocation = res[1];
-          var revocationFile = new Blob([revocation], {type: 'text/plain; charset=utf-8'});
           return $translate('ACCOUNT.SECURITY.REVOCATION_FILENAME', {
             uid: data.uid,
             currency: currency.name,
             pubkey: data.pubkey
           })
-          .then(function (fileName) {
-            FileSaver.saveAs(revocationFile, fileName);
+          .then(function (filename) {
+            return Device.file.save(revocation, {filename: filename});
           });
         });
     },
@@ -2193,13 +2201,12 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
           var content = (children||[]).reduce(function(res, wallet) {
             return res + [wallet.data.pubkey, wallet.data.uid, wallet.data.localName||wallet.data.name].join('\t') + '\n';
           }, '');
-          var file = new Blob([content], {type: 'text/plain; charset=utf-8'});
           return $translate('ACCOUNT.WALLET_LIST.EXPORT_FILENAME', {
               pubkey: data.pubkey,
               currency: currency.name,
             })
-            .then(function (fileName) {
-              FileSaver.saveAs(file, fileName);
+            .then(function(filename) {
+              return Device.file.save(content, {filename: filename});
             });
         });
     },
diff --git a/www/templates/wallet/modal_security.html b/www/templates/wallet/modal_security.html
index 814694fcddc73e8a11c32567aa309c6999a31a45..040691b732b22cff401b17cb38f603aaaa9aad4f 100644
--- a/www/templates/wallet/modal_security.html
+++ b/www/templates/wallet/modal_security.html
@@ -58,8 +58,8 @@
               </div>
             </div>
 
-            <div class="item item-complex card stable-bg item-icon-left item-icon-right ink hidden-xs"
-                 ng-click="selectOption('saveID')" ng-if="login && !$root.device.enable">
+            <div class="item item-complex card stable-bg item-icon-left item-icon-right ink"
+                 ng-click="selectOption('saveID')" ng-if="login">
               <div class="item-content item-text-wrap">
                 <i class="item-image dark icon ion-person"></i>
                 <b class="ion-ios-redo icon-secondary dark" style="top: -8px; left: 39px; font-size: 12px;"></b>
@@ -73,7 +73,7 @@
 
             <!-- keyfile generation (hidden if device enable, because we do not known were the file is stored) -->
             <div class="item item-complex card stable-bg item-icon-left item-icon-right ink hidden-xs"
-                 ng-click="selectOption('generateKeyfile')" ng-if="login && !$root.device.enable">
+                 ng-click="selectOption('generateKeyfile')" ng-if="login">
               <div class="item-content item-text-wrap">
                 <i class="item-image dark icon ion-document-text"></i>
                 <b class="ion-key icon-secondary dark" style="top: -8px; left: 42px; font-size: 12px;"></b>
@@ -84,8 +84,8 @@
               </div>
             </div>
 
-            <div class="item item-complex card stable-bg item-icon-left item-icon-right ink hidden-xs hidden-sm"
-                 ng-click="downloadRevokeFile()" ng-if="canRevoke && !$root.device.enable">
+            <div class="item item-complex card stable-bg item-icon-left item-icon-right ink"
+                 ng-click="downloadRevokeFile()" ng-if="canRevoke">
               <div class="item-content item-text-wrap">
                 <i class="item-image dark icon ion-person"></i>
                 <b class="ion-ios-redo icon-secondary dark" style="top: -8px; left: 39px; font-size: 12px;"></b>
diff --git a/www/templates/wallet/popover_tx_actions.html b/www/templates/wallet/popover_tx_actions.html
new file mode 100644
index 0000000000000000000000000000000000000000..83900e51a51b23aefe3f93524bd5a4ac830756eb
--- /dev/null
+++ b/www/templates/wallet/popover_tx_actions.html
@@ -0,0 +1,16 @@
+<ion-popover-view class="fit has-header popover-wallet-tx-actions">
+  <ion-header-bar>
+    <h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1>
+  </ion-header-bar>
+  <ion-content scroll="false">
+    <div class="list item-text-wrap">
+
+      <a class="item item-icon-left ink visible-xs visible-sm"
+         ng-click="downloadHistoryFile()">
+        <i class="icon ion-android-download"></i>
+        {{'COMMON.BTN_DOWNLOAD_ACCOUNT_STATEMENT' | translate}}
+      </a>
+
+    </div>
+  </ion-content>
+</ion-popover-view>
diff --git a/www/templates/wallet/view_wallet_tx.html b/www/templates/wallet/view_wallet_tx.html
index 419e89d989971f0148f31e540b8364cf04db577c..4f28827d846993c6ea543c7bc0aa17916fa21912 100644
--- a/www/templates/wallet/view_wallet_tx.html
+++ b/www/templates/wallet/view_wallet_tx.html
@@ -8,6 +8,10 @@
 
   <ion-nav-buttons side="secondary">
     <cs-extension-point name="nav-buttons"></cs-extension-point>
+
+    <button class="button button-icon button-clear icon ion-android-more-vertical visible-xs visible-sm"
+            ng-click="showActionsPopover($event)">
+    </button>
   </ion-nav-buttons>
 
   <ion-content scroll="true" class="refresher-positive-900-bg"
@@ -70,7 +74,7 @@
     <!-- QR code -->
     <ng-include src="::'templates/common/qrcode.html'"></ng-include>
 
-    <!-- Buttons bar-->
+    <!-- Buttons bar -->
     <div class="hidden-xs hidden-sm padding text-center" ng-if="!loading">
 
       <button class="button button-stable button-small-padding icon ion-loop ink"
diff --git a/www/templates/wot/popover_tx_actions.html b/www/templates/wot/popover_tx_actions.html
new file mode 100644
index 0000000000000000000000000000000000000000..83900e51a51b23aefe3f93524bd5a4ac830756eb
--- /dev/null
+++ b/www/templates/wot/popover_tx_actions.html
@@ -0,0 +1,16 @@
+<ion-popover-view class="fit has-header popover-wallet-tx-actions">
+  <ion-header-bar>
+    <h1 class="title" translate>COMMON.POPOVER_ACTIONS_TITLE</h1>
+  </ion-header-bar>
+  <ion-content scroll="false">
+    <div class="list item-text-wrap">
+
+      <a class="item item-icon-left ink visible-xs visible-sm"
+         ng-click="downloadHistoryFile()">
+        <i class="icon ion-android-download"></i>
+        {{'COMMON.BTN_DOWNLOAD_ACCOUNT_STATEMENT' | translate}}
+      </a>
+
+    </div>
+  </ion-content>
+</ion-popover-view>
diff --git a/yarn.lock b/yarn.lock
index f77bfd57f0f714fe2d5ecd66ba5125dd9b0dba76..52bab6fdc0f436119107fdf1263b2c1e92825898 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3163,10 +3163,10 @@ cordova-plugin-dialogs@^2.0.2:
   resolved "https://registry.npmjs.org/cordova-plugin-dialogs/-/cordova-plugin-dialogs-2.0.2.tgz#ac3ce8b73bc885ff847078d5b533e7a4ed418a2f"
   integrity sha512-FUHI6eEVeoz2VkxbF0P56QlUQLGzXcvw3i4xuXyM9gEct6Y+FA3Xzgl2pJTZcTg5wRqLWzN08kgNoHPkom15pw==
 
-cordova-plugin-file@^6.0.2:
-  version "6.0.2"
-  resolved "https://registry.npmjs.org/cordova-plugin-file/-/cordova-plugin-file-6.0.2.tgz#f3911479f8357e9aacb5576674f8d95b31a1fb20"
-  integrity sha512-m7cughw327CjONN/qjzsTpSesLaeybksQh420/gRuSXJX5Zt9NfgsSbqqKDon6jnQ9Mm7h7imgyO2uJ34XMBtA==
+cordova-plugin-file@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.npmjs.org/cordova-plugin-file/-/cordova-plugin-file-8.0.0.tgz#e46fd696dabc3d8d79723caefa1804becd91356f"
+  integrity sha512-pgxCJtDjDKzyeqvrn0KnDubf9b1VLv+OyWTXjUR7T52o7oGDUkR3ubT89i/1ugHtRU6mY7XIGHD4drUByDQClw==
 
 cordova-plugin-ionic-keyboard@^2.2.0:
   version "2.2.0"
@@ -9052,10 +9052,10 @@ node-notifier@10.0.1:
     uuid "^8.3.2"
     which "^2.0.2"
 
-node-sass@^8.0.0:
-  version "8.0.0"
-  resolved "https://registry.npmjs.org/node-sass/-/node-sass-8.0.0.tgz#c80d52148db0ce88610bcf1e1d112027393c13e1"
-  integrity sha512-jPzqCF2/e6JXw6r3VxfIqYc8tKQdkj5Z/BDATYyG6FL6b/LuYBNFGFVhus0mthcWifHm/JzBpKAd+3eXsWeK/A==
+node-sass@^9.0.0:
+  version "9.0.0"
+  resolved "https://registry.npmjs.org/node-sass/-/node-sass-9.0.0.tgz#c21cd17bd9379c2d09362b3baf2cbf089bce08ed"
+  integrity sha512-yltEuuLrfH6M7Pq2gAj5B6Zm7m+gdZoG66wTqG6mIZV/zijq3M2OO2HswtT6oBspPyFhHDcaxWpsBm0fRNDHPg==
   dependencies:
     async-foreach "^0.1.3"
     chalk "^4.1.2"