Comment
The Comment
is a data structure that contains the essential information of a comment.
content
The comment content stores the plain text content of the comment.
- Please use
\n
for line breaks. (Most browsers will normalize the line breaks to\n
regardless of the OS). - any media or links that should be displayed to users should be stored in the content property and rendered by clients based on the media type at the uri.
- For reactions (commentType = 1), the content field contains the reaction type as a lower case string, such as
"like"
,"dislike"
,"repost"
, or whichever custom reaction type your app wants to use.
Reaction Content Types
When commentType = 1
(reaction), the content
field should contain a string indicating the type of reaction:
Standardized Reaction Types
"like"
- General approval or appreciation"downvote"
- Disagreement or negative feedback"repost"
- Sharing or amplifying the content
Implementation Notes
- Reaction content should be a simple string identifier (lowercase recommended)
- Applications should validate reaction types against their supported list
- Unknown reaction types should be handled gracefully by displaying a generic reaction icon or ignored
- Consider internationalization when displaying reaction labels to users
authMethod
The authMethod
field indicates how the comment was authenticated when it was created. This provides transparency about the trust model used for each comment.
Read more about the authentication methods
Authentication Methods
0
(DIRECT_TX) - The user signed the transaction directly (msg.sender == author)1
(APP_APPROVAL) - The user has pre-approved the app to post on their behalf2
(AUTHOR_SIGNATURE) - The user signed the comment hash offline (meta-transaction)
metadata
The metadata
property stores additional data as key-value pairs that shouldn't be shown to the user as-is.
- Stored as an array of
MetadataEntry
structures withbytes32 key
andbytes value
fields - Keys should be UTF-8 encoded strings with format "type key" (e.g., "category string", "priority uint256")
- Values are stored as
bytes
and can contain any encoded data type, encoded viaabi.encodePacked
- Please be mindful that storing large amounts of metadata on the chain will increase the gas cost of the transaction.
Metadata Access
// Get all metadata for a comment
Metadata.MetadataEntry[] memory metadata = commentManager.getCommentMetadata(commentId);
// Get specific metadata value
bytes memory value = commentManager.getCommentMetadataValue(commentId, keccak256("category string"));
// Get all metadata keys
bytes32[] memory keys = commentManager.getCommentMetadataKeys(commentId);
Metadata Format Conversion
The SDK provides functions to convert between two metadata formats:
JS/SDK Format (easier to work with):Record<string, { key: string; type: string; value: Hex }>;
struct MetadataEntry {
bytes32 key;
bytes value;
}
Converting Between Formats
import {
convertRecordToContractFormat,
convertContractToRecordFormat,
createKeyTypeMap,
} from "@ecp.eth/sdk/comments";
// Before sending to contract
const contractData = convertRecordToContractFormat(jsMetadata);
// After receiving from contract (requires key mapping)
const keyTypeMap = createKeyTypeMap([
{ key: "status", type: "string" },
{ key: "reputation", type: "uint256" },
]);
const jsMetadata = convertContractToRecordFormat(contractData, keyTypeMap);
Supported types: string
, bool
, uint256
, address
, bytes32
, bytes
, and other numeric types.
Best practice: Maintain a mapping of your known metadata keys and types for proper conversion.
targetUri
It serves as a unique identifier for locating comments.
Be careful when choosing the value for the targetUri
property as an inconsistent targetUri
will result in some comments missing from the indexer response.
-
Any URIs, as long as it is a unique string that follows the RFC 3986 standard.
-
If your web page is dynamic and accepts query parameters, you should carefully consider which parameters are necessary to locate the correct comments. As a general rule:
- Normalize the URL, e.g. using
normalize-url
. - Sort the query parameters using
sortQueryParameters
fromnormalize-url
. - Do not include query parameters unrelated to page content, such as tracking or feature flags.
- Normalize the URL, e.g. using
-
If the comment is a reply to a comment then set the value to
undefined
.
App/Chain Agnostic URIs
Whenever possible, it is recommended to use app or chain agnostic URIs, e.g. CAIP-19 specification for referencing onchain or offchain assets. This ensures the reference is consistent and maximal compatibility across different applications and chains.
Example (NFT and collection):
chain://eip155:1/erc721:0xa723a8a69d9b8cf0bc93b92f9cb41532c1a27f8f/11
chain://eip155:1/erc721:0xa723a8a69d9b8cf0bc93b92f9cb41532c1a27f8f
parentId
The parentId
property is used to store the parent comment id.
- If the comment is a reply to a comment, set the
parentId
to the id of the parent comment. - If the comment is a top-level comment, leave it
undefined
.
author
The author
property is used to store the author's address. It is the address of the account that created and owns the comment.
app
The app
property is used to store the app signer's address. The app signer represents the the owner of the app or community.
If you are creating features just for yourself to post, such as a blog, you can use your own address as the app
.
To see detailed explanation please refer to the Dual-signature System page.
deadline
The deadline is a timestamp in seconds since the epoch. Posting a comment with an expired deadline will result in the transaction being reverted.
- It must be a future timestamp.
- It provides a guarantee around the timestamp when the user or app countersigned the comment.
commentType
The commentType
property uses a uint8
value to efficiently categorize different types of comments.
Valid Comment Type Values
Value | Name | Description | Usage |
---|---|---|---|
0 | Comment (Default) | Standard text comments | Regular discussions, replies, conversations |
1 | Reaction | Reactions to content | Likes, dislikes, hearts, thumbs up/down |
Implementation Notes
- Default Behavior: If
commentType
is not explicitly set, it defaults to0
(standard comment) - Immutable: Comment type cannot be changed after creation (not included in
EditComment
struct) - Validation: Applications should validate that reaction content contains valid reaction types
- Extensibility: Additional comment types can be added in future versions
channelId
The channelId
property is used to organize comments into different channels or categories.
- Must be a numeric identifier (
uint256
). - Allows applications to segment comments into different groups, communities, or topics.
- Comments with the same
channelId
are logically grouped together. - Applications can use this to implement features like multiple comment sections, communities, or discussion boards.
createdAt
(automatic)
- Timestamp when the comment was first created (in seconds since epoch).
- Set automatically when the comment is posted to the blockchain.
- Cannot be modified after creation.
updatedAt
(automatic)
- Timestamp when the comment was last modified (in seconds since epoch).
- Updated automatically whenever the comment content or metadata is edited.
- Initially equals
createdAt
for new comments.
hookData
(added by hooks)
Hook metadata is additional data that can be added by hooks during comment processing, stored separately from regular metadata.
- Stored as key-value pairs similar to regular metadata
- Used by the protocol's hook system to attach additional information to comments
- The specific format and content depend on the hooks implemented by the application
- Applications can use this for custom features like moderation flags, additional metadata, or integration data
- Since
hookData
is added by hooks, it is not signed by the author nor the app.
Hook Metadata Access
// Get all hook metadata for a comment
Metadata.MetadataEntry[] memory hookMetadata = commentManager.getCommentHookMetadata(commentId);
// Get specific hook metadata value
bytes memory value = commentManager.getCommentHookMetadataValue(commentId, keccak256("moderationStatus string"));
// Get all hook metadata keys
bytes32[] memory keys = commentManager.getCommentHookMetadataKeys(commentId);