• useCreateComment is React Hook that allows you to create a new Lens Comment.

    You MUST be authenticated via useLogin to use this hook.

    Returns UseDeferredTask<CommentAsyncResult, BroadcastingError | InsufficientGasError | PendingSigningRequestError | UserRejectedError | WalletConnectionError, CreateCommentArgs>

    Example

    const { execute, error, loading } = useCreateComment();
    

    Basic usage

    Create a text-only comment:

    const { execute, error, loading } = useCreateComment();

    const comment = async (content: string) => {
    // create the desired metadata via the `@lens-protocol/metadata` package helpers
    const metadata = textOnly({ content });

    // upload the metadata to a storage provider of your choice (IPFS in this example)
    const uri = await uploadToIpfs(metadata);

    // invoke the `execute` function to create the comment
    const result = await execute({
    commentOn: publicationId, // the publication ID to comment on
    metadata: uri,
    });
    }

    See the @lens-protocol/metadata package for more information on how to create metadata for other types of publications.

    Failure scenarios

    You can handle possible failure scenarios by checking the result value.

    const { execute, error, loading } = useCreateComment();

    const comment = async (content: string) => {
    // first part is the same as in the initial example

    // invoke the `execute` function to create the comment
    const result = await execute({

    metadata: uri,
    commentOn: publicationId,
    });

    if (result.isFailure()) {
    switch (result.error.name) {
    case 'BroadcastingError':
    console.log('There was an error broadcasting the transaction', error.message);
    break;

    case 'PendingSigningRequestError':
    console.log(
    'There is a pending signing request in your wallet. ' +
    'Approve it or discard it and try again.'
    );
    break;

    case 'WalletConnectionError':
    console.log('There was an error connecting to your wallet', error.message);
    break;

    case 'UserRejectedError':
    // the user decided to not sign, usually this is silently ignored by UIs
    break;
    }
    return;
    }
    };

    At this point the comment creation is completed from an end-user perspective but, in case of on-chain TX, this is not necessarily mined and indexed (yet). See the following section.

    Wait for completion

    In case of successful submission, the result value can be used to wait for the comment to be fully processed.

    This gives you an opportunity to decide what UX to provide to the end-user.

    For example if the comment is on-chain it might take a while to be mined and indexed. So you might want to show a loading indicator or let the user navigate away from the page.

    const { execute, error, loading } = useCreateComment();

    const comment = async (content: string) => {
    // first part is the same as in the initial example

    // invoke the `execute` function to create the comment
    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    });

    if (result.isFailure()) {
    // handle failure scenarios
    return;
    }

    // this might take a while, depends on the type of tx (on-chain or Momoka)
    // and the congestion of the network
    const completion = await result.value.waitForCompletion();

    if (completion.isFailure()) {
    console.log('There was an processing the transaction', completion.error.message);
    return;
    }

    // the comment is now ready to be used
    const comment = completion.value;
    console.log('Comment created', comment);
    };

    Open actions

    Contextually to the comment creation you can configure the open actions.

    As with anything involving amounts in the Lens SDK you can use the Amount helper with currencies from the useCurrencies hook to create the desired amounts.

    Create a comment with a SimpleCollectOpenAction module:

    const wmatic = ... // from useCurrencies hook

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    actions: [
    {
    type: OpenActionType.SIMPLE_COLLECT,
    amount: Amount.erc20(wmatic, 100), // 100 WMATIC
    followerOnly: true,
    collectLimit: 10,
    recipient: '0x4f94FAFEE38F545920485fC747467EFc85C302E0',
    endsAt: new Date('2025-12-31T00:00:00.000Z'),
    }
    ]
    });

    See SimpleCollectActionConfig for more details.

    Create a comment with a MultirecipientCollectOpenAction module:

    const wmatic = ... // from useCurrencies hook

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    actions: [
    {
    type: OpenActionType.MULTIRECIPIENT_COLLECT,
    amount: Amount.erc20(wmatic, 100), // 100 WMATIC
    followerOnly: true,
    collectLimit: 10,
    recipients: [
    {
    recipient: '0x4f94FAFEE38F545920485fC747467EFc85C302E0',
    split: 30, // 30%
    },
    {
    recipient: '0x097A4fE5cfFf0360438990b88549d4288748f6cB',
    split: 70, // 70%
    },
    ],
    endsAt: new Date('2025-12-31T00:00:00.000Z'),
    }
    ]
    });

    See MultirecipientCollectActionConfig for more details.

    Finally you can also create a comment with a custom open action (AKA unknown open action):

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    actions: [
    {
    type: OpenActionType.UNKNOWN_OPEN_ACTION,
    address: '0x4f94FAFEE38F545920485fC747467EFc85C302E0',
    data: '0x.....'
    }
    ]
    });

    See UnknownOpenActionConfig for more details.

    Reference policy

    Contextually to the comment creation you can configure the reference policy.

    No one can comment, quote, or mirror the comment:

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,

    reference: {
    type: ReferencePolicyType.NO_ONE
    }
    });

    Only followers can comment, quote, or mirror the comment:

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,

    reference: {
    type: ReferencePolicyType.FOLLOWERS_ONLY
    }
    });

    You can have finer control over who can comment, quote, or mirror the comment by using the DEGREES_OF_SEPARATION reference policy:

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,

    reference: {
    type: ReferencePolicyType.DEGREES_OF_SEPARATION,
    params: {
    degreesOfSeparation: 2, // followers and followers of your followers
    commentsRestricted: true, // can comment
    mirrorsRestricted: true, // can mirror
    quotesRestricted: false, // cannot quote
    }
    }
    });

    You can even set the DEGREES_OF_SEPARATION reference policy to follow someone elses graph:

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,

    reference: {
    type: ReferencePolicyType.DEGREES_OF_SEPARATION,
    params: {
    degreesOfSeparation: 2, // followers and followers of your followers
    commentsRestricted: true, // can comment
    mirrorsRestricted: true, // can mirror
    quotesRestricted: false, // cannot quote

    sourceProfileId: '0x01', // in relation to Profile Id 0x01
    }
    }
    });

    See DegreesOfSeparationReferencePolicyConfig for more details.

    Creating an app-specific comment

    You can create a comment that is specific to an app by defining the appId when creating the comment metadata.

    This allows apps to build custom experiences by only surfacing publications that were created in their app.

    const metadata = textOnly({
    content: `Hello world!`,
    appId: 'my-app-id',
    });

    const uri = await uploadToIpfs(metadata);

    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    });

    Self-funded approach

    In case you want to pay for the transaction gas costs yourself, you can do so by setting the sponsored parameter to false:

    const comment = async (content: string) => {
    // create and upload metadata as before

    const result = await execute({
    metadata: uri,
    commentOn: : publicationId,
    sponsored: false,
    });

    if (result.isFailure()) {
    switch (result.error.name) {
    case 'InsufficientGasError':
    console.log('You do not have enough funds to pay for the transaction cost.');
    break;

    // ...
    }
    return;
    }

    // ...
    }

    The example above shows how to detect when the user does not have enough funds to pay for the transaction cost.

    Self-funded fallback

    If for some reason the Lens API cannot sponsor the transaction, the hook will fail with a BroadcastingError with one of the following reasons:

    In those cases you can retry the transaction as self-funded like in the following example:

    const comment = async (content: string) => {
    // create and upload metadata as before

    const sponsoredResult = await execute({
    metadata: uri,
    commentOn: : publicationId,
    });

    if (sponsoredResult.isFailure()) {
    switch (sponsoredResult.error.name) {
    case 'BroadcastingError':
    if ([BroadcastingErrorReason.NOT_SPONSORED, BroadcastingErrorReason.RATE_LIMITED].includes(sponsoredResult.error.reason)) {

    const chargedResult = = await execute({
    metadata: uri,
    commentOn: : publicationId,
    sponsored: false,
    });

    // continue with chargedResult as in the previous example
    }
    break;

    // ...
    }
    }

    We omitted the handling of the BroadcastingErrorReason.APP_NOT_ALLOWED error because it's usually something that builder will face when deploying their app to production using the Production Lens API.

    It just requires the app to apply for whitelisting. See https://docs.lens.xyz/docs/gasless-and-signless#whitelisting-your-app.

    Momoka comments

    For a comment to be hosted on Momoka it must meet the following criteria:

    • it must be a comment for a Momoka publication
    • reference policy ANYONE (which is also the default value in case it's not specified)
    • no open actions
    • sponsored by the Lens API (which is also the default value in case it's not specified)

    If the comment does not meet the above criteria, it will be hosted on-chain.

    Upgrading from v1

    Replace the useCreateComment hook with useCreateComment like in the following diff:

    - const { execute, error, isPending } = useCreateComment({ publisher, upload: uploadToIpfs });
    + const { execute, error, loading } = useCreateComment();

    Amend the code that used to call the execute function to:

    // first: create metadata using the `@lens-protocol/metadata` package
    const metadata = textOnly({
    content: `Hello world!`,
    });

    // second: upload it using the upload function you used to pass to `useCreateComment`:
    const uri = await uploadToIpfs(metadata);

    // finally, invoke the `execute` function:
    const result = await execute({
    commentOn: publicationId,
    metadata: uri,
    })

    // continue as usual