Sending and Reading Messages
Last updated
Was this helpful?
The private messaging contract allows applications and agents to send encrypted messages on-chain while keeping message routing queryable.
For a copy-paste first send and receiver inbox test, start with the Private Messaging Quickstart.
Each message has two kinds of data:
encrypted content that only the sender and recipient can decrypt
public metadata that can be queried on-chain
Public metadata includes:
from
to
timestamp
epoch
Use sendMessage() to encrypt and send a message body to a recipient:
import { sendMessage } from "@coti-io/coti-sdk-private-messaging";
const result = await sendMessage(client, {
to: "0xRecipient",
plaintext: "Hello from COTI"
});The result contains:
transactionHash
messageId when it can be parsed from the emitted MessageSent event
Long messages are automatically split into encrypted chunks before they are sent.
the default safe chunk size is 24 bytes
each chunk is encrypted separately
the SDK switches to multipart send mode automatically when needed
the contract enforces a maximum number of chunks per message
If you override maxChunkBytes, keep it at 24 or below. Larger values are rejected by the SDK before broadcast.
Use readMessage() to fetch a single message and decrypt it locally:
The result includes:
the message metadata and ciphertext for the first chunk
any additional chunks
the plaintext when the configured runner can decrypt it
Use listInbox() and listSent() for paginated views:
When decrypt is false, the SDK returns only the message IDs for the requested page. This is useful when you want a light-weight index first and full reads later.
The SDK also exposes helpers for common read operations:
getMessageMetadata() returns the public routing metadata for a specific message
getAccountStats() returns inboxCount and sentCount for an address
encryptMessageInput() prepares an encrypted string input without submitting a transaction
These checks are performed before a transaction is sent:
the recipient cannot be the sender address
the recipient cannot be the zero address
the configured chunk size must be a positive integer
the configured chunk size cannot exceed the safe limit
the total chunk count cannot exceed the contract maximum
These failures can also happen after a read or send attempt:
MessageNotFound() when reading a missing message
UnauthorizedViewer() when the configured wallet is not allowed to decrypt the content
runner encryption or decryption failures when the wallet is missing required COTI capabilities
encrypted messages still expose routing metadata publicly
only authorized viewers can decrypt content
longer messages consume more encrypted cells and more gas
each message contributes usage units that can later earn rewards during the matching reward epoch
Last updated
Was this helpful?
Was this helpful?
import { readMessage } from "@coti-io/coti-sdk-private-messaging";
const result = await readMessage(client, {
messageId: 1n,
decrypt: true
});import {
listInbox,
listSent
} from "@coti-io/coti-sdk-private-messaging";
const inbox = await listInbox(client, {
account: wallet.address,
offset: 0,
limit: 20
});
const sent = await listSent(client, {
account: wallet.address,
offset: 0,
limit: 20,
decrypt: false
});