add support for singlesig era hardware wallet
What changed, and why it matters
This commit adds support for a new hardware wallet called ERA Wallet to the Sparrow desktop Bitcoin wallet. It is a straightforward feature addition: a new import class that reuses existing code for another similar wallet (Keystone), plus icons and menu entries. There is no indication of a security bug, vulnerability, or malicious change in the code shown.
No security action required. Treat as normal feature addition. If desired, review the parent class KeystoneSinglesig parsing logic to ensure inherited QR/file import behavior is appropriate for ERA Wallet output.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces EraSinglesig.java, a subclass of KeystoneSinglesig, to handle single-signature keystore imports from the ERA Wallet via QR code. It overrides name, description, wallet model, and keystore label, and disables file-based import. The new importer is registered in WalletImportDialog.java and HwAirgappedController.java. Four SVG icon assets are added. No cryptographic, parsing, or access-control changes are present in the diff.
Changed components
Wallet import dialogHardware airgapped keystore import controllerERA Wallet importer (new)Wallet model icon assetsInspect captured patch +78 / −3
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java b/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java
index 7c56b21..ea9ee1b 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/WalletImportDialog.java
@@ -52,7 +52,7 @@ public class WalletImportDialog extends Dialog<List<Wallet>> {
importAccordion = new Accordion();
List<KeystoreFileImport> keystoreImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(),
- new GordianSeedTool(), new SeedSigner(), new SpecterDIY(), new Krux(), new AirGapVault(), new Samourai(), new KeycardShellSinglesig());
+ new GordianSeedTool(), new SeedSigner(), new SpecterDIY(), new Krux(), new AirGapVault(), new Samourai(), new KeycardShellSinglesig(), new EraSinglesig());
for(KeystoreFileImport importer : keystoreImporters) {
if(!importer.isDeprecated() || Config.get().isShowDeprecatedImportExport()) {
FileWalletKeystoreImportPane importPane = new FileWalletKeystoreImportPane(importer);
diff --git a/src/main/java/com/sparrowwallet/sparrow/io/EraSinglesig.java b/src/main/java/com/sparrowwallet/sparrow/io/EraSinglesig.java
new file mode 100644
index 0000000..4db9480
--- /dev/null
+++ b/src/main/java/com/sparrowwallet/sparrow/io/EraSinglesig.java
@@ -0,0 +1,43 @@
+package com.sparrowwallet.sparrow.io;
+
+import com.sparrowwallet.drongo.policy.PolicyType;
+import com.sparrowwallet.drongo.protocol.ScriptType;
+import com.sparrowwallet.drongo.wallet.Keystore;
+import com.sparrowwallet.drongo.wallet.WalletModel;
+
+import java.io.InputStream;
+
+public class EraSinglesig extends KeystoneSinglesig {
+ @Override
+ public String getName() {
+ return "ERA Wallet";
+ }
+
+ @Override
+ public String getKeystoreImportDescription(int account) {
+ return "Import QR created on your ERA Wallet by opening your wallet and selecting Link > Sparrow from the wallet menu.";
+ }
+
+ @Override
+ public WalletModel getWalletModel() {
+ return WalletModel.ERA_WALLET;
+ }
+
+ @Override
+ public Keystore getKeystore(PolicyType policyType, ScriptType scriptType, InputStream inputStream, String password) throws ImportException {
+ Keystore keystore = super.getKeystore(policyType, scriptType, inputStream, password);
+ keystore.setLabel("ERA Wallet");
+
+ return keystore;
+ }
+
+ @Override
+ public boolean isFileFormatAvailable() {
+ return false;
+ }
+
+ @Override
+ public boolean isWalletImportFileFormatAvailable() {
+ return false;
+ }
+}
diff --git a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
index 78afe00..a66ada2 100644
--- a/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
+++ b/src/main/java/com/sparrowwallet/sparrow/keystoreimport/HwAirgappedController.java
@@ -27,7 +27,7 @@ public class HwAirgappedController extends KeystoreImportDetailController {
public void initializeView() {
List<KeystoreFileImport> fileImporters = Collections.emptyList();
if(getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE_HD) || getMasterController().getWallet().getPolicyType().equals(PolicyType.SINGLE_SP)) {
- fileImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(), new SeedSigner(), new GordianSeedTool(), new SpecterDIY(), new Krux(), new AirGapVault(), new KeycardShellSinglesig());
+ fileImporters = List.of(new ColdcardSinglesig(), new CoboVaultSinglesig(), new Jade(), new KeystoneSinglesig(), new PassportSinglesig(), new SeedSigner(), new GordianSeedTool(), new SpecterDIY(), new Krux(), new AirGapVault(), new KeycardShellSinglesig(), new EraSinglesig());
} else if(getMasterController().getWallet().getPolicyType().equals(PolicyType.MULTI_HD)) {
fileImporters = List.of(new Bip129(), new ColdcardMultisig(), new CoboVaultMultisig(), new JadeMultisig(), new KeystoneMultisig(), new PassportMultisig(), new SeedSigner(), new GordianSeedTool(), new SpecterDIY(), new Krux(), new KeycardShellMultisig());
}
diff --git a/src/main/resources/image/walletmodel/era-icon-invert.svg b/src/main/resources/image/walletmodel/era-icon-invert.svg
new file mode 100644
index 0000000..31c544a
--- /dev/null
+++ b/src/main/resources/image/walletmodel/era-icon-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="15px" viewBox="0 0 15 15" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 7.121094 3.109375 L 7.5 3.488281 L 7.878906 3.109375 L 11.890625 7.121094 L 11.511719 7.5 L 11.890625 7.878906 L 7.878906 11.890625 L 7.5 11.511719 L 7.121094 11.890625 L 3.109375 7.878906 L 3.488281 7.5 L 3.109375 7.121094 Z M 7.878906 12.648438 L 8.257812 13.027344 L 13.03125 8.257812 L 12.648438 7.878906 L 13.03125 7.5 L 12.648438 7.121094 L 13.03125 6.742188 L 8.257812 1.972656 L 7.878906 2.351562 L 7.5 1.96875 L 7.121094 2.351562 L 6.742188 1.972656 L 1.972656 6.742188 L 2.351562 7.121094 L 1.96875 7.5 L 2.347656 7.878906 L 1.972656 8.257812 L 6.742188 13.027344 L 7.121094 12.648438 L 7.5 13.03125 Z M 7.878906 12.648438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 6.726562 8.839844 L 5.023438 7.136719 L 4.371094 7.792969 L 6.214844 9.636719 L 6.726562 10.152344 L 8.910156 7.96875 L 8.253906 7.3125 Z M 6.726562 8.839844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 7.679688 5.6875 L 5.976562 7.390625 L 6.632812 8.042969 L 8.335938 6.34375 L 9.863281 7.871094 L 10.519531 7.214844 L 8.335938 5.03125 Z M 7.679688 5.6875 "/>
+</g>
+</svg>
diff --git a/src/main/resources/image/walletmodel/era-icon.svg b/src/main/resources/image/walletmodel/era-icon.svg
new file mode 100644
index 0000000..d0c88d5
--- /dev/null
+++ b/src/main/resources/image/walletmodel/era-icon.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="15px" height="15px" viewBox="0 0 15 15" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 7.121094 3.109375 L 7.5 3.488281 L 7.878906 3.109375 L 11.890625 7.121094 L 11.511719 7.5 L 11.890625 7.878906 L 7.878906 11.890625 L 7.5 11.511719 L 7.121094 11.890625 L 3.109375 7.878906 L 3.488281 7.5 L 3.109375 7.121094 Z M 7.878906 12.648438 L 8.257812 13.027344 L 13.03125 8.257812 L 12.648438 7.878906 L 13.03125 7.5 L 12.648438 7.121094 L 13.03125 6.742188 L 8.257812 1.972656 L 7.878906 2.351562 L 7.5 1.96875 L 7.121094 2.351562 L 6.742188 1.972656 L 1.972656 6.742188 L 2.351562 7.121094 L 1.96875 7.5 L 2.347656 7.878906 L 1.972656 8.257812 L 6.742188 13.027344 L 7.121094 12.648438 L 7.5 13.03125 Z M 7.878906 12.648438 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 6.726562 8.839844 L 5.023438 7.136719 L 4.371094 7.792969 L 6.214844 9.636719 L 6.726562 10.152344 L 8.910156 7.96875 L 8.253906 7.3125 Z M 6.726562 8.839844 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 7.679688 5.6875 L 5.976562 7.390625 L 6.632812 8.042969 L 8.335938 6.34375 L 9.863281 7.871094 L 10.519531 7.214844 L 8.335938 5.03125 Z M 7.679688 5.6875 "/>
+</g>
+</svg>
diff --git a/src/main/resources/image/walletmodel/era-invert.svg b/src/main/resources/image/walletmodel/era-invert.svg
new file mode 100644
index 0000000..89fc8a4
--- /dev/null
+++ b/src/main/resources/image/walletmodel/era-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="50px" height="50px" viewBox="0 0 50 50" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 23.738281 10.359375 L 25 11.621094 L 26.261719 10.359375 L 39.640625 23.738281 L 38.378906 25 L 39.640625 26.265625 L 26.261719 39.640625 L 25 38.378906 L 23.738281 39.640625 L 10.363281 26.265625 L 11.621094 25.003906 L 10.359375 23.742188 Z M 26.265625 42.167969 L 27.527344 43.429688 L 43.429688 27.527344 L 42.167969 26.265625 L 43.429688 25 L 42.167969 23.738281 L 43.429688 22.472656 L 27.527344 6.570312 L 26.265625 7.832031 L 25 6.570312 L 23.734375 7.835938 L 22.472656 6.574219 L 6.570312 22.476562 L 7.832031 23.742188 L 6.570312 25.003906 L 7.828125 26.265625 L 6.570312 27.523438 L 22.472656 43.429688 L 23.734375 42.167969 L 25 43.433594 Z M 26.265625 42.167969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 22.421875 29.46875 L 16.75 23.792969 L 14.566406 25.976562 L 20.714844 32.125 L 22.421875 33.835938 L 29.703125 26.554688 L 27.519531 24.371094 Z M 22.421875 29.46875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(83.92157%,82.352942%,82.352942%);fill-opacity:1;" d="M 25.597656 18.957031 L 19.921875 24.632812 L 22.105469 26.816406 L 27.78125 21.144531 L 32.875 26.238281 L 35.058594 24.054688 L 27.78125 16.773438 Z M 25.597656 18.957031 "/>
+</g>
+</svg>
diff --git a/src/main/resources/image/walletmodel/era.svg b/src/main/resources/image/walletmodel/era.svg
new file mode 100644
index 0000000..d647c5c
--- /dev/null
+++ b/src/main/resources/image/walletmodel/era.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="50px" height="50px" viewBox="0 0 50 50" version="1.1">
+<g id="surface1">
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 23.738281 10.359375 L 25 11.621094 L 26.261719 10.359375 L 39.640625 23.738281 L 38.378906 25 L 39.640625 26.265625 L 26.261719 39.640625 L 25 38.378906 L 23.738281 39.640625 L 10.363281 26.265625 L 11.621094 25.003906 L 10.359375 23.742188 Z M 26.265625 42.167969 L 27.527344 43.429688 L 43.429688 27.527344 L 42.167969 26.265625 L 43.429688 25 L 42.167969 23.738281 L 43.429688 22.472656 L 27.527344 6.570312 L 26.265625 7.832031 L 25 6.570312 L 23.734375 7.835938 L 22.472656 6.574219 L 6.570312 22.476562 L 7.832031 23.742188 L 6.570312 25.003906 L 7.828125 26.265625 L 6.570312 27.523438 L 22.472656 43.429688 L 23.734375 42.167969 L 25 43.433594 Z M 26.265625 42.167969 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 22.421875 29.46875 L 16.75 23.792969 L 14.566406 25.976562 L 20.714844 32.125 L 22.421875 33.835938 L 29.703125 26.554688 L 27.519531 24.371094 Z M 22.421875 29.46875 "/>
+<path style=" stroke:none;fill-rule:nonzero;fill:rgb(11.372549%,11.372549%,10.588235%);fill-opacity:1;" d="M 25.597656 18.957031 L 19.921875 24.632812 L 22.105469 26.816406 L 27.78125 21.144531 L 32.875 26.238281 L 35.058594 24.054688 L 27.78125 16.773438 Z M 25.597656 18.957031 "/>
+</g>
+</svg>
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.