Chat sends move 0 value, so the network fee is structurally load-bearing (it's the only thing that forces a real shielded input; 0-value + 0-fee builds a degenerate, unrelayable tx). Three gaps addressed: 1. Fee floor — broadcastChatMemos now uses max(getDefaultFee(), kChatMinFeeDrgx), so a 0 / too-low global default-fee setting can't silently break chat. 2. Real delivery status — the echo was marked Sent on SUBMIT regardless of the on-chain outcome (the z_sendmany callback was empty), so failures were invisible and the Retry affordance never fired for async failures. Add a third ChatDelivery::Sending state (appended so persisted 0=Sent stays valid); record the echo in-memory as Sending, and resolve it to Sent/Failed from the z_sendmany completion callback — persisting only the final status (so a restart never shows a stuck spinner; a stray persisted Sending loads as Sent). A subtle "sending…" label shows while in flight. 3. Pay-from-funded + pre-check — z_sendmany spends from one z-address, and the identity reply address may be unfunded while funds sit elsewhere. chatPayFromZaddr picks a spendable z-address that can cover the fee (preferring the identity address); the memo still advertises the identity address as reply-to, so paying from a different note is transport-transparent. If nothing can cover the fee, a clear "need a small shielded balance" toast replaces the cryptic failure. Full node only for the callback path; lite resolves optimistically on queue. 8-language strings + CJK subset (+1 glyph 賄). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33 lines
1.5 KiB
C++
33 lines
1.5 KiB
C++
#pragma once
|
|
|
|
// DragonX Wallet - HushChat decrypted message model. Held in memory by ChatStore and persisted at
|
|
// rest (encrypted under a seed-derived key) by ChatDatabase.
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
|
|
namespace dragonx::chat {
|
|
|
|
enum class ChatDirection { Incoming, Outgoing };
|
|
enum class ChatMessageKind { Message, ContactRequest };
|
|
// Outgoing delivery status. Sending = broadcast in flight (async op not yet resolved); Sent = the
|
|
// daemon accepted + broadcast the tx; Failed = it didn't (not connected, no funded address, rejected).
|
|
// Always Sent for incoming. NB: the values are persisted (chat DB serializes the int), so Sent MUST
|
|
// stay 0 and new states are APPENDED — never reordered.
|
|
enum class ChatDelivery { Sent, Failed, Sending };
|
|
|
|
struct ChatMessage {
|
|
ChatDirection direction = ChatDirection::Incoming;
|
|
ChatMessageKind kind = ChatMessageKind::Message;
|
|
std::string txid;
|
|
std::string conversation_id; // cid — the conversation thread key
|
|
std::string peer_zaddr; // header "z": peer's reply z-address
|
|
std::string peer_public_key_hex; // header "p": peer's crypto_kx public key
|
|
std::string body; // decrypted plaintext (Message) or request text (ContactRequest)
|
|
std::int64_t timestamp = 0; // tx time in seconds; set by the ingesting caller
|
|
std::size_t payload_position = 0; // together with txid, the dedup key
|
|
ChatDelivery delivery = ChatDelivery::Sent; // outgoing only
|
|
};
|
|
|
|
} // namespace dragonx::chat
|