Sui ecological project|ComingChat, a social application that integrates private communication, mobile wallet, on-chain friends circle and red envelope functions

ComingChat is a decentralized social platform built on the Sui network. It has many functions, among which the encrypted chat function provides users with a secure way to communicate. The feature leverages the Signal encryption protocol, an open source software protocol popular in apps like Signal, WhatsApp and Skype. 

ComingChat provides a full life experience on Sui. It combines ChatGPT's enhanced productivity and social interaction with a full-chain wallet, providing users with a wide range of functions and applications.

In addition to its trusted and verifiable characteristics, ComingChat chose the Signal protocol as the basis for its encrypted communication, which is fully compatible with the Sui Network’s account system.

chat mode

ComingChat's chat module provides users with three different modes to meet their different privacy and security needs. These modes include:

  • Private Chat: This mode provides one-to-one communication between two users. The Signal protocol encrypts these conversations to maintain their confidentiality.
  • Encrypted Group Chat: This mode allows groups to communicate while maintaining a high level of security and privacy. Similar to private chats, the Signal protocol encrypts messages in encrypted group chats.
  • Non-encrypted group chat: In this mode, messages are not encrypted, but the group supports up to 1,000 people, is easy to set up and manage, but has a lower level of protection for message content.

The implementation of the Signal protocol occurs within ComingChat’s chat infrastructure, which uses the Decentralized Moments (Dmens) protocol. The protocol supports common chat functions such as posting, likes, and replies, and also integrates a red envelope function that allows users to send tokens or NFTs to each other.

Implement encryption

ComingChat's encrypted chat feature is based on the Signal protocol's double ratchet algorithm , which provides end-to-end encryption to ensure secure communication between users.

Building an encrypted chat feature requires the following steps:

  1. Implements the Double Ratchet algorithm to enable end-to-end encryption for messages, ensuring that only the intended recipients can decrypt and read these messages.
  2. Store encrypted messages on the Sui network to ensure data integrity and security.
  3. Allows users to exchange public keys for secure communication and establish secure sessions using the Extended Cubic Elliptic Curve Diffie-Hellman (X3DH) key protocol.

ComingChat's encrypted chat architecture allows users to choose to chat privately, where the sender encrypts the messages sent to the other party, and the receiver decrypts the messages after receiving them so that they can be read.

double ratchet algorithm

The double ratchet algorithm is used by two parties to exchange encrypted messages based on a shared key. Typically, these parties negotiate a shared secret key using a key protocol such as X3DH. After reaching an agreement, these parties will use Double Ratchet to send and receive encrypted messages.

The parties derive new keys for each double ratchet message so that previous keys cannot be calculated from later keys. Parties also append Diffie-Hellman public values ​​to their messages. The result of the Diffie-Hellman calculation is mixed into the derived key so that later keys cannot be calculated from previous keys. These features provide some degree of protection for encrypted messages before or after a party's keys are compromised.

Privacy-enhancing red envelope feature

The term "red envelope" for secure online transactions comes from the actual Chinese practice of giving cash to others during holidays and special occasions, often in red envelopes. ComingChat uses this term to refer to the secure messaging packets in the encrypted chat feature.

The Sui Move language allows ComingChat to have some unique differences from Core Move when developing red envelope contracts. In particular, Sui Move requires programmatic adjustments to the synchronous return of transaction status, which helps sort chat messages, and the processing of entry function parameters, which requires an object ID.

Sui red envelopes do not have incremental red envelope IDs, but they have red envelope object IDs because Sui's data model requires all objects to have an ID.

After issuing an open/close transaction, Sui red envelope does not need to obtain status asynchronously; the red envelope status can be updated based on events in the transaction return data.

The server-side node needs to asynchronously obtain the creation status of the red envelope created by the user, because the user's node may be different from the server-side node.

The core contract code below demonstrates how ComingChat considers Sui Move's unique features and requirements. The Config object contains the addresses of the sender, receiver, and administrator, and defines the transaction fee. The RedPacketInfo object includes the coin amount, the sent token, and the receiver's address. The RedPacketEvent object is used to track the token amount.

// Copyright 2022-2023 ComingChat Authors. Licensed under Apache-2.0 License.
module rp::red_packet {
	…
	struct Config has key {
	id: UID, 
	admin: address, 
	beneficiary: address, 
	owner: address, 
	count: u64, 
	fees: Bag
}

struct RedPacketInfo<phantom CoinType> has key,store {
	id: UID, 
	remain_coin: Balance<CoinType>, 
	remain count: u64, 
	beneficiary: address
}

// Event emitted when created/opened/closed a red packet.
struct RedPacketEvent has copy, drop {
	id: ID, 
	event_type: u8, 
	remain_count: u64, 
	remain balance: u64

// One-Time-Witness for the module.
struct RED_PACKET has drop {}

fun init (
	otw: RED_PACKET, 
	ct: &mut TxContext
) {
		…
}

public entry fun create<CoinType> (
	config: &mut Config,
	coins: vector<Coin<CoinType>>, 
	count: u64, 
	total_balance: u64, 
	ctx: &mut TxContext
) {
	// 1. check args
	…

}

public entry fun open<CoinType> (
	info: &mut RedPacketInfo<CoinType>, 
	lucky_accounts: vector<address>, 
	balances: vector<u64>, 
	ct: &mut TXContext
) {
…
}

public entry fun close<CoinType> (
	info: RedPacketInfo CoinType>, 
	ctx: &mut TxContext
) {
…
}

public entry fun withdraw<CoinType> (
	config: Smut Config, 
	ctx: &mut TxContext
) {
…
}

When submitting the open/close transaction of Sui Red Packet, the transaction results will be obtained directly in the response, and the database and cache status will be updated, without the need to obtain the transaction status asynchronously from the browser.

After the user creates a red envelope, the system will asynchronously query the status of the created transaction and obtain the red envelope data based on the event, including the amount, quantity and red envelope ID.

In the ComingChat app, the "Create red envelope" event is sent to the Sui network as a smart contract, and the status of the contract is processed based on the receiver's operations.

Red envelope status change

After the Sui transaction is sent by ComingChat, it gets the transaction result directly, no asynchronous task is needed to update the open/close status, so:

  • After the open condition is triggered, the administrator calls the open transaction and directly sets the record to success based on the open transaction status.
  • After the closing condition is triggered, the administrator calls the closing transaction and directly sets it to closed or failed to close based on the closing transaction status.

If the open/close transaction fails, the failure needs to be recorded to prevent the transaction from being retried, which will incur additional gas fees.

ComingChat will monitor the transaction status and either close successful transactions or confirm failed transactions and stop automatic retries to avoid unnecessary gas fees.

Dmens protocol

ComingChat built the Dmens protocol as an SDK on Sui to provide functions such as user identification, content sharing, and value sharing. The protocol uses Sui to manage user data and content, and uses SUI to pay gas fees. Users can create profiles, post content, follow and interact with other users. The protocol also allows users to convert the content they create into unique NFTs and issue different types of NFTs for different scenarios.

These scenarios include:

  1. KOLs issue valuable NFTs to fans to increase fan engagement, loyalty and revenue.
  2. The project issues proof-of-stake NFTs for operational activities to increase user participation, loyalty, and promote the development of the ecosystem.
  3. Content creators monetize their content through the paid NFT model, achieving better content monetization and more income.
  4. Artists convert their digital artworks into NFTs and sell them to collectors or investors.

Dmens architecture

Dmens are designed in ComingChat to support public and private chat functionality. Overall, when a user creates a message (can be a new message or a reply message), it launches ComingChat's chat feature on Sui. ComingChat uses GraphQL to query user profiles stored off-chain, and uses the Dmens indexer module to ensure messages are properly sorted.

The Dmens architecture uses Sui, GraphQL, and the Dmens indexer to handle user actions such as creating a profile or posting a new message. Here, GraphQL acts as a database query tool for storing data.

In the smart contract code below, a Chat object is defined, which allows users to post messages, forward other messages, like messages, and other typical chat functions.

//chat.move
module chat::chat {
	/// Sui Chat NFT (i.e., a post, retweet, like, chat message etc).
	struct Chat has key, store {
		id: UID,
		// The ID of the chat app.
		app_id: address,
		// Post's text.
		text: String,
		// Set if referencing an another object (i.e., due to a Like, Retweet, Reply etc).
		// We allow referencing any object type, not only Chat NFTs.
		ref id: Option<address>,
		// app-specific metadata. We do not enforce a metadata format and delegate this to app layer.
		metadata: vector<u8>,
	}

	/// Simple Chat.text getter.
	public fun text (chat: &Chat): String {
		chat.text
	}

	/// Mint (post) a Chat object.
	fun post internal (
		app_id: address, 
		text: vector<u8>, 
		ref_id: Option<address>, 
		metadata: vector<u8>, 
		ctx: &mut TxContext,
	) {
		…
	}


	/// Mint (post) a Chat object without referencing another object.
	public entry fun post (
		app_identifier: address, 
		text: vector<u8>, 
		metadata: vector<u8>, 
		ctx: &mut IxContext,
	) {
		post_internal(app_identifier, text, option::none (), metadata, ctx);
	}

	/// Mint (post) a Chat object and reference another object (i.e., to simulate retweet, reply, like, attach).
	/// TODO: Using address as app_identifier & 'ref_identifier type, because we cannot pass 'ID' to entry functions. Using vector<u8>' for text instead of String' for the same reason.
	public entry fun post_with_ref 
		app_identifier: address, 
		text: vector<u8>, 
		ref_identifier: address, 
		metadata: vector<u8>, 
		ctx: &mut TxContext,
	) {
		post_internal(app_identifier, text, some (ref_identifier), metadata, ctx);
	}

	/// Burn a Chat object.
	public entry fun burn (chat: Chat) {
		let Chat { id, app_id: _, text: _ , ref_id: _, metadata: _ } = chat;
		object::delete (id);
	}
}

The Chat structure in the above code snippet represents a chat message. It has ID fields including ref_id, allowing the chat message to forward, reply to or like another message, which is represented in the code as an object. The actual chat message is a text string in a structure.

The post internal function creates a new chat message, and since it is intended to be called from inside the module, it is marked "internal". The object created by this function has an ID field and a text string of the actual message. ref_id allows it to reference another object, for example as a reply or like to an existing chat.

Similarly, there is post public entry function, which calls post internal to create a new chat. However, it sets ref_id to none because this function is intended for people to initiate new chats.

Dmens indexer structure design

ComingChat's encrypted chat module uses Redis (an open source streaming database) as off-chain storage. It handles the message queue and ensures that chat messages are displayed in an orderly manner.

For Redis streaming, first initialize the client.

func (r *BaseRedisCustomer) InitCustomer ( ) error {
	...
}

Redis stores data in memory, so queue data needs to be pruned appropriately and regularly. In the code snippet below, a function to prune the queue is defined.

func (r *BaseRedisCustomer) TrimQueueList (ct context.Context) {
	r.wg.Add (1)
	defer funct( ) { 
		r.wg.Done ( )
	} ( )
	for {
		select {
		case <-ctx.Done ( ) :
			return
	}
	…
}The listener code filters transactions by contract address. The function in the code below is a good example of how to integrate traditional off-chain storage with a Web3 app.

The listener code in the code snippet below filters transactions by contract address. The function below is a good example of integrating traditional off-chain storage with a Web3 app.

func (1 *ListenLastIxByCycle) cycleFetchTransactionNum(ct context. Context, tx chan<-TxDigest) {
	var (
		cursor *types.TransactionDigest
	)
	…
}
下面的代码片段将每个新的事务摘要推送到一个名为transaction-analyze的队列中。

rpip.Evalsha (
	r.Context (), 
	r.script["pushNewT×DigestToStream" ],
	[ ]string{topic, fmt.Sprintf(PrefixChainLastDigest, chain, packageId) },
	"data", 
	preDigest, 
	digest,

	)

ComingChat uses Lua server-side scripts to combine multiple Redis commands to ensure continuity of transaction summaries.

local lastDigest = redis.call( 'get', KEYS[2])
local result = false
if (lastDigest ~= false) and (lastDigest == ARG[2])) or ((lastDigest == false) and (ARGVI 21 == ')) then
	redis.call('xadd', KEYS[1], '*', ARGV[1], ARGV[3]) 
	redis.call ('set', KEYS[2], ARGV[3])
end
return true

The indexer goes through the following process as it receives each message submitted by a user:

timing

  1. Query all consumer fault messages from the queue_message table.
  2. Re-consume according to the theme. If a job exceeds the threshold for re-consumption, it must be stopped and accessed manually.

consumer

1. Analyze transactions

  • Queries the objects affected by this transaction, excluding currency objects
  • Push the affected objects to the queue

2. Object update

  • Get object details and create or update it on object_list table
  • Filter profile objects
  • Filter tweets calling ChatGPT

3. Analysis of personal data

  • Decode profile object

4. GPT reply

  • Get the content of Dmens tweets and use regular expressions to match GPT robot addresses

conclusion

Encrypted chats have proven extremely popular in apps like Signal, WhatsApp and WeChat. This feature in ComingChat fits well with the existing ideas based on the Sui social platform. Encryption provides users with privacy protection, ensuring bad actors cannot eavesdrop on their conversations. Encrypted chat also dovetails with Sui’s functionality, providing an independent and secure platform for users’ online lives.

ComingChat's technical implementation leverages the trusted Signal protocol's double ratchet algorithm, demonstrating how existing technology can be applied to the Web3 platform. The addition of advanced features such as Dmens, red envelopes and chatbots introduced in this article can provide a rich user experience in ComingChat.


About Sui Network

Sui is an L1 public chain redesigned and built based on first principles, aiming to provide creators and developers with a development platform capable of hosting the next billion users in Web3. Applications on Sui are based on the Move smart contract language and are horizontally scalable, allowing developers to support a wide range of application development quickly and at low cost. Get more information: https://linktr.ee/sui_apac

Official website | English Twitter | Chinese Twitter | Discord | English Telegram group | Chinese Telegram group

Guess you like

Origin blog.csdn.net/Sui_Network/article/details/132426958