Skip to content

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 behalf
  • 2 (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 with bytes32 key and bytes 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 via abi.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 }>;
Contract Format (used by blockchain):
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:

    1. Normalize the URL, e.g. using normalize-url.
    2. Sort the query parameters using sortQueryParameters from normalize-url.
    3. Do not include query parameters unrelated to page content, such as tracking or feature flags.
  • 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

ValueNameDescriptionUsage
0Comment (Default)Standard text commentsRegular discussions, replies, conversations
1ReactionReactions to contentLikes, dislikes, hearts, thumbs up/down

Implementation Notes

  • Default Behavior: If commentType is not explicitly set, it defaults to 0 (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);