From ba673f95bffc7345de327f14a76d4679d0411cbb Mon Sep 17 00:00:00 2001 From: Alain Brenzikofer Date: Mon, 14 Sep 2026 08:09:04 +0000 Subject: [PATCH] core: export says which kind of secret, so other kinds can follow /_wallet export name rather than an index straight after export. The bare form stays the seed mnemonic, and a profile's key can be added beside the name one without the argument having to be guessed from its shape. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX --- bots/src/API/Docs/Commands.hs | 2 +- docs/rfcs/2026-09-10-wallet-keys.md | 2 +- src/Simplex/Chat/Controller.hs | 4 ++-- src/Simplex/Chat/Library/Commands.hs | 4 ++-- tests/WalletTests.hs | 6 +++--- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bots/src/API/Docs/Commands.hs b/bots/src/API/Docs/Commands.hs index 8ac5f43238..a12f2bb34b 100644 --- a/bots/src/API/Docs/Commands.hs +++ b/bots/src/API/Docs/Commands.hs @@ -453,7 +453,7 @@ undocumentedCommands = "APIWallet", "APIWalletCreate", "APIWalletDelete", - "APIWalletExportDerivedSecret", + "APIWalletExportNameSecret", "APIWalletExportSeedMnemonic", "CheckChatRunning", "ConfirmRemoteCtrl", diff --git a/docs/rfcs/2026-09-10-wallet-keys.md b/docs/rfcs/2026-09-10-wallet-keys.md index c8f86df1b0..294fac0b75 100644 --- a/docs/rfcs/2026-09-10-wallet-keys.md +++ b/docs/rfcs/2026-09-10-wallet-keys.md @@ -70,7 +70,7 @@ Internal API. The names commands will call these; users will not. /_wallet create new generate the seed, 24 words /_wallet create mnemonic= take the entropy from a mnemonic /_wallet export the seed mnemonic -/_wallet export one name key's secret, 0x and 64 hex digits +/_wallet export name one name key's secret, 0x and 64 hex digits /_wallet delete delete the seed ``` diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 1adbfa3498..d28327b0d6 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -420,7 +420,7 @@ data ChatCommand | APIWallet | APIWalletCreate {recoveryPhrase :: Maybe Text} | APIWalletExportSeedMnemonic - | APIWalletExportDerivedSecret {nameIndex :: NameIndex} + | APIWalletExportNameSecret {nameIndex :: NameIndex} | APIWalletDelete | APISendCallInvitation ContactId CallType | SendCallInvitation ContactName CallType @@ -750,7 +750,7 @@ allowRemoteCommand = \case APIWallet -> False APIWalletCreate {} -> False APIWalletExportSeedMnemonic -> False - APIWalletExportDerivedSecret {} -> False + APIWalletExportNameSecret {} -> False APIWalletDelete -> False _ -> True diff --git a/src/Simplex/Chat/Library/Commands.hs b/src/Simplex/Chat/Library/Commands.hs index e62dd88f7d..630dd9a763 100644 --- a/src/Simplex/Chat/Library/Commands.hs +++ b/src/Simplex/Chat/Library/Commands.hs @@ -1509,7 +1509,7 @@ processChatCommand cxt nm = \case seed <- deviceSeed phrase <- either throwCmdError pure $ recoveryKeyPhrase seed pure $ CRWalletSeedMnemonic user (safeDecodeUtf8 phrase) - APIWalletExportDerivedSecret nameIdx -> withUser $ \user -> do + APIWalletExportNameSecret nameIdx -> withUser $ \user -> do seed <- deviceSeed k <- either throwCmdError pure $ seedMaster seed >>= \m -> deriveNameKey m nameIdx pure $ CRWalletDerivedSecret user (renderNameKeyPath nameIdx) (decodeLatin1 . strEncode $ addressFromPrivateKey k) (safeDecodeUtf8 $ nameKeySecret k) @@ -5585,7 +5585,7 @@ chatCommandP = "/_service_response " *> (APISendServiceResponse <$> A.decimal <* A.space <*> strP <* A.space <*> jsonP), "/_wallet create new" $> APIWalletCreate Nothing, "/_wallet create mnemonic=" *> (APIWalletCreate . Just <$> textP), - "/_wallet export " *> (APIWalletExportDerivedSecret <$> keyIndexP), + "/_wallet export name " *> (APIWalletExportNameSecret <$> keyIndexP), "/_wallet export" $> APIWalletExportSeedMnemonic, "/_wallet delete" $> APIWalletDelete, "/_wallet" $> APIWallet, diff --git a/tests/WalletTests.hs b/tests/WalletTests.hs index 8e25344cba..a2f5a899f3 100644 --- a/tests/WalletTests.hs +++ b/tests/WalletTests.hs @@ -124,13 +124,13 @@ testWalletExportDerivedSecret :: HasCallStack => TestParams -> IO () testWalletExportDerivedSecret ps = withNewTestChat ps "alice" aliceProfile $ \alice -> do alice ##> ("/_wallet create mnemonic=" <> B.unpack testPhrase) _ <- nameRows alice - alice ##> "/_wallet export 1" + alice ##> "/_wallet export name 1" alice <## "m/44'/60'/0'/0/1 0x6Fac4D18c912343BF86fa7049364Dd4E424Ab9C0 0x9a983cb3d832fbde5ab49d692b7a8bf5b5d232479c99333d0fc8e1d21f1b55b6" -- a secret whose first byte is zero keeps its 64 hex digits - alice ##> "/_wallet export 15" + alice ##> "/_wallet export name 15" alice <## "m/44'/60'/0'/0/15 0xa25d37554EB084969C85362f7E6B1A6108e51d0e 0x009a1ccd9c667416d9db6246a35d022b1799517c0cd8547bb07ce280c119ae3c" -- an index BIP-32 cannot reach is rejected, not wrapped into another key - alice ##> "/_wallet export 4294967296" + alice ##> "/_wallet export name 4294967296" alice <## "bad chat command: Failed reading: empty" testWalletDelete :: HasCallStack => TestParams -> IO ()