- redeem errors are typed (CEBadgeRedeemError) instead of matched by text in the apps
- service timeout (A_SERVICE) decodes in the apps and offers Retry via the existing retry alert
- unexpected redeem errors show the error itself instead of a generic message
- service error codes are a typed enum in the apps (BadgeServiceErrorCode)
- CRBadgeRedeemed returns badge state, so the apps skip a second round-trip after redeem
- setBadgeAlertAcked is scoped to user_id
- badgeChanged updates non-active profiles, so other profiles' badges don't go stale
- pitch banner is not shown to a profile that already has a badge
- one badgeTypeName per platform, used by the badge screen and the badge info alert
- BadgeAlertKind and BadgeAlertPrice decode via standard JSON, no custom decoders
- dead "Support ended" title branch removed from Your Badge view
- kotlin: users from badge responses carry remoteHostId
- kotlin: redeem code field keeps the IME's cursor and composition state
- kotlin: "Get your code" shown in all flavours
- kotlin: "Don't show again" -> "Dismiss", matching iOS
- kotlin: parseBadgeCode moved next to its FFI in platform/Core.kt
- kotlin: BadgesView no longer cross-fades on badge state updates
- kotlin: section title not uppercased
- ios: redeem code field parses once per change
- ios: A_SERVICE rejected reason is not decoded
- CLI: "cannot redeem badge code: ..." with the source of the error
- comments clarified
/_wallet export name <k> 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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX
Delete re-ran /_wallet, so a successful delete printed "no wallet key",
which is the same words the error uses and reads as a failure. There is
nothing to show after a delete.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX
The mnemonic comes back from the entropy exactly, which is what export
returns, and the seed PBKDF2 derives from the mnemonic is computed when a
key is needed and never stored. The column was the one thing called seed
that is not the seed, which is why it needed a comment saying so.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX
create and import differed only in where the entropy came from and already
shared one store function, so they are one command with the source named:
/_wallet create new, or /_wallet create seed=<phrase>. Naming it means no
seed is generated by typing a prefix.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX
A name's profile is the record it resolves to, not the key that owns it, so
the account level was carrying a mapping nothing needs. It was also the only
source of the profile to account ambiguity after a restore, of /_wallet
bind, and of the index gap and the refusal that told a visible profile an
account was held by one it cannot see. All of it goes.
Names sit in account 0 from index 1. Index 0 is left unused so neither the
names nor the profile accounts, which start at 1, claim the origin of both
dimensions. users gains no columns at all now, so the migration is one
CREATE TABLE.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX
* core: support message signing in p2p groups
* improve
* add member key
* distribute keys and sign
* refactor
* better query
* map
* sign in relay groups too
* clean up
* list
* fix test
* update bot types
* some refactor
* remove unnecessary condition
* simplify
* refactor
* simplify
* move
* clean up
* diff
* diff
* limit attempts for key sending
* optimize
* fix test
* split
* fuse
* null
* only mark as "key sent" when forwarder supports binary encoding
* fix bot apis
* fix some tests
* add key distribution steps, and fix some tests
* fix test
* increase timeout
* fix tests
* fix more tests
* simplify
* disable test output
* mark keys sent with invitations
* fix test
* fix test, query plans
* unify signing of connection info packets
* revert change to createNewGroup
* create key at group/member creation
* rename, remove liftIO
* clean up
* fix type
* remove ad hoc key sending
* update bot api
* diff
* reduce diff
* failing test
* fix sending messages in groups with members before version 18
* remove test delays
* update query plans
* update test
* add tests
* fix tests
---------
Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
The counter path checked it, the explicit one did not, and the parser is not
the only caller: processChatCommand takes APIWalletBind from library callers
too. hardened leaves an index at or above 2^31 alone, so account i and
i + 2^31 are the same key while the duplicate check compares the stored
integers, and two profiles could hold one account's names.
The rfc now says what hiding a profile from /_wallet does and does not
protect: the seed is one per device, so whoever unlocks any profile can
derive every account.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rvc3HbiWBTqbAvRT45G5oX