• useCreateQuote is React Hook that allows you to create a new Lens Quote.

    You MUST be authenticated via useLogin to use this hook.

    Returns UseDeferredTask<QuoteAsyncResult, BroadcastingError | InsufficientGasError | PendingSigningRequestError | UserRejectedError | WalletConnectionError, CreateQuoteArgs>

    Example

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

    Basic usage

    Create a text-only quote:

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

    const quote = (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 quote
    const result = await execute({
    metadata: uri,
    quoteOn: : publicationId, // the publication ID to quote
    });
    }

    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 } = useCreateQuote();

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

    // invoke the `execute` function to create the quote
    const result = await execute({
    metadata: uri,
    quoteOn: : 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 quote 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 quote to be fully processed.

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

    For example if the quote 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 } = useCreateQuote();

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

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

    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 quote is now ready to be used
    const quote = completion.value;
    console.log('quote created', quote);
    };

    Open actions

    Contextually to the quote 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 quote with a SimpleCollectOpenAction module:

    const wmatic = ... // from useCurrencies hook

    const result = await execute({
    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 quote with a MultirecipientCollectOpenAction module:

    const wmatic = ... // from useCurrencies hook

    const result = await execute({
    metadata: uri,
    quoteOn: : publicationId,
    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 quote with a custom open action (AKA unknown open action):

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

    See UnknownOpenActionConfig for more details.

    Reference policy

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

    A quote with reference policy other than ANYONE will be hosted on-chain. If the quote has reference policy ANYONE (which is also the default value) and does not have any open actions, it will be hosted on Momoka.

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

    const result = await execute({
    metadata: uri,
    quoteOn: : publicationId,
    reference: {
    type: ReferencePolicyType.NO_ONE
    }
    });

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

    const result = await execute({
    metadata: uri,
    quoteOn: : publicationId,
    reference: {
    type: ReferencePolicyType.FOLLOWERS_ONLY
    }
    });

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

    const result = await execute({
    metadata: uri,
    quoteOn: : publicationId,
    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({
    metadata: uri,
    quoteOn: : publicationId,
    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.

    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 quote = async (content: string) => {
    // create and upload metadata as before

    const result = await execute({
    metadata: uri,
    quoteOn: : 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 quote = async (content: string) => {
    // create and upload metadata as before

    const sponsoredResult = await execute({
    metadata: uri,
    quoteOn: : 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,
    quoteOn: : 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.

    Create an app-specific quote

    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: 'Quote content',
    appId: 'my-app-id',
    });

    const uri = await uploadToIpfs(metadata);

    const result = await execute({
    quoteOn: publicationId, // the publication ID to quote
    metadata: uri
    });

    Momoka quotes

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

    • it must be a quote of 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 quote does not meet the above criteria, it will be hosted on-chain.