const { execute, error, loading } = useCreateComment();
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.
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.
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);
};
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.
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.
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,
});
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.
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.
For a comment to be hosted on Momoka it must meet the following criteria:
ANYONE
(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.
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
useCreateComment
is React Hook that allows you to create a new Lens Comment.You MUST be authenticated via useLogin to use this hook.