Self-Funded Transactions

Learn how to interact with the Lens Protocol using own funds to pay gas fees.


While the Lens Protocol enables developers to build a gasless experience through Sponsored Transactions, developers also have the option to implement Self-Funded Transactions where users cover their own gas fees.

On this page, we will delve into two common scenarios where app developers may opt to use Self-Funded Transactions:

  • Always: In this scenario, the user's wallet is always used for sending the transaction and covering the associated gas fees.

  • As Fallback: In this case, the user's wallet is used when it's not feasible to use Sponsored Transactions.

The examples on this page assume that you are familiar with the Content Creation documentation.

Always

In cases where your dApp does not require Sponsored Transactions, you can execute all on-chain operations using Self-Funded Transactions.

You can configure the SDK to use self-funded transactions by setting the sponsored flag to false in the LensConfig.

config.ts
import { LensConfig, production } from "@lens-protocol/react-web";import { bindings } from "@lens-protocol/wagmi";
const lensConfig: LensConfig = {  environment: production,  bindings: bindings(wagmiConfig),
  sponsored: false, // <-- this is the important part};

This configuration instructs the whole React SDK to use the user's wallet for sending the transaction and paying the associated gas fees.

Alternatively, you can control the use of self-funded transactions on a case-by-case basis. This can be done by setting the sponsored flag to false in the hooks, as demonstrated below with the useCreatePost hook.

CreatePost.tsx
const { execute, loading, error } = useCreatePost();
// ...
// within an async callbackconst result = await execute({  metadata: await uploadJson(metadata),  sponsored: false, // <-- this is the important part});
// continue ...

Regardless of the approach you chose, you need to handle self-funded related error, like insufficient gas, by examining the Result<T, E> object.

CreatePost.tsx
if (result.isFailure()) {  switch (result.error.name) {    case 'InsufficientGasError':      console.error('Insufficient funds to pay for gas');      break;
    // handle other errors as necessary  }  return;}
// Self-Funded Transaction broadcasted successfully ...

The self-funded transactions approach described above is compatible with any of the following hooks:

As Fallback

Even if your dApp primarily relies on Sponsored Transactions, certain circumstances might cause a request to fail. These include:

  • The Profile exceeding their rate limit for Sponsored Transactions.

  • The operation involving a custom module that hasn't been flagged as sponsored approved.

In such cases, you might want to fall back to Self-Funded Transactions to provide your users with an alternative way to complete the operation.

The steps to do this are as follows:

  1. Handle scenarios where transactions are not sponsored

  2. Fall back to Self-Funded Transactions when necessary

  3. Handle errors related to insufficient funds

In this section, we will illustrate the process outlined above with the useCreatePost hook.

const { execute, loading, error } = useCreatePost();
// within an async callbackconst metadata = "ipfs://bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi";
const sponsored = await execute({ metadata });
// continue ...

In the Transaction Monitoring page, we demonstrated how to use the Result<T, E> object returned by the execute function to monitor your Lens transactions. In this section, we will show you how to use it to identify a non-sponsored transaction scenario.

CreatePost.tsx
import { BroadcastingErrorReason } from "@lens-protocol/react-web";
// ...
// within the same callbackif (sponsored.isFailure()) {  switch (sponsored.error.name) {    case 'BroadcastingError':
      switch (sponsored.error.reason) {        case BroadcastingErrorReason.NOT_SPONSORED:        case BroadcastingErrorReason.RATE_LIMITED:          // continue ...          break;
        // handle other reasons as necessary      }
    break;  }  return}
// sponsored transaction broadcasted successfully ...

The error.reason values we are interested in are:

  • NOT_SPONSORED: The operation involves a custom module that is not flagged as sponsored

  • RATE_LIMITED: The Profile has reached their daily limit of sponsored transactions

In any of these cases, you can fallback to Self-Funded Transactions by passing the sponsored flag as false to the execute function.

CreatePost.tsx
const selfFunded = = await execute({  metadata,  sponsored: false, // <-- this is the important part});
// continue ...

Lastly, it's crucial to handle errors related to insufficient funds, as demonstrated below.

CreatePost.tsx
if (selfFunded.isFailure()) {  switch (selfFunded.error.name) {    case 'InsufficientGasError':      console.error('Insufficient funds to pay for gas');      break;
    // handle other errors as necessary  }  return;}
// Self-Funded Transaction broadcasted successfully ...

That's it—you've successfully created a Post using a Self-Funded Transaction.

The methodology described above can be applied to any of the following hooks: