#pragma once // DragonX Wallet - HushChat outgoing memo construction (the inverse of the receive parser). // // Given the sender's identity and the peer, produce the header memo JSON + payload memo that, // sent as two 0-value memo outputs to the peer's z-address (header at the LOWER memo position), // another HushChat client parses and decrypts. The byte format matches SilentDragonXLite: the // header keys serialize alphabetically (nlohmann default) to cid,e,h,p,t,v,z. Pure — no I/O, no // network; broadcasting the memos is the caller's job (the transport lands in a later phase). #include "chat_crypto.h" // ChatKeyPair #include #include namespace dragonx::chat { struct OutgoingChatMemos { std::string recipientZaddr; // the peer's z-address (recipient of both memo outputs) std::string headerMemo; // JSON header — MUST occupy the lower memo position on the wire std::string payloadMemo; // ciphertext hex (Message) or plaintext (ContactRequest) }; // One of the two 0-value memo outputs a HushChat send produces (amount is always 0). struct ChatSendOutput { std::string address; // the peer's z-address std::string memo; // memo encoded for the target transport (utf8:-prefixed or raw) }; // The two outputs for a HushChat send, HEADER FIRST (it must occupy the lower memo position). // `utf8Prefix` prepends the daemon's "utf8:" marker required by full-node z_sendmany (which then // UTF-8-encodes the bytes on-chain, byte-identical to SDXLite's Memo::from_str); lite backends take // raw UTF-8, so pass false there. std::array chatSendOutputs(const OutgoingChatMemos& memos, bool utf8Prefix); enum class ChatComposeStatus { Ok, EmptyBody, MissingField, BadPeerKey, BadRequestText, // a contact request text must not start with '{' (parser would read it as a header) EncryptFailed, TooLong // a resulting memo exceeds the HushChat 512-byte memo limit }; // Build an ENCRYPTED message to a peer whose public key you already learned from a memo they sent // you. `mine` is the sender's identity keypair; `myPublicKeyHex` its public half (goes in header p). ChatComposeStatus buildOutgoingMessage(const ChatKeyPair& mine, const std::string& myPublicKeyHex, const std::string& myReplyZaddr, const std::string& peerPublicKeyHex, const std::string& peerZaddr, const std::string& conversationId, const std::string& plaintext, OutgoingChatMemos& out); // Build a plaintext contact request — no peer public key needed yet; this is how the peer first // learns your public key + reply address. The payload is the (plaintext) request text. ChatComposeStatus buildOutgoingContactRequest(const std::string& myPublicKeyHex, const std::string& myReplyZaddr, const std::string& peerZaddr, const std::string& conversationId, const std::string& requestText, OutgoingChatMemos& out); } // namespace dragonx::chat