Guides

Lens Profile Manager

Previously known as "Dispatcher".

The Profile Manager enables gasless and signless transactions (transactions without signing any approval modals) in your Lens app.

Blockchain technology introduced many drawbacks like wallet popups, seed phrases, passwords, funds, and multi-network (blockchain) dynamics. These are fundamental for securing cryptographic transactions but present many UX challenges. So, are we doomed, or should we be optimistic?

In blockchain terms, Optimistic means that we assume the transaction will come through so we don't need to wait for validators to reach a consensus. This wouldn't be acceptable for financial transactions because of the double spending problem but can be helpful for social media interactions.

Social media is about great frontend experiences so having wallet prompts for every share or follow is not ideal. The challenge is that being optimistic in a front-end experience is possible but still, every action must be approved by the user wallet.

To solve this issue, we created the Profile Manager. Basically, it is an intermediate wallet with funds that act as the signer for every transaction. We only have to delegate signing privileges to this profile manager wallet which operates hidden in the backend. This combined with an optimistic UI creates a seamless experience identical to what we are used to today.

What The Profile Manager Can Be Used For

The profile manager works for creating posts, comments & mirrors and updating profile metadata.

As the profile manager can only use a subset of methods this doesn't mean you can not be gasless for everything. Any withSig methods at the contract level are able to be used by the profile manager.

Profile Manager Examples

Check If a Profile Has The Profile Manager Enabled

The profile manager is something that each profile can opt-in to. So before trying to execute any transactions via the Profile Manager, you should check whether the profile has the functionality enabled.

You can do this by using the signless property available on each Profile.

📘

Important to know

signless is only populated for the currently logged in profile, for all others profile it's always set to null.

Invocation

const profile = await lensClient.profile.fetch({
  profileId: YOUR_PROFILE_ID,
});

if (profile?.signless) {
  console.log('Profile manager is enabled');
} else {
  console.log('Profile manager is disabled');
}
query Profile {
  profile(request: { forProfileId: "0x18" }) {
    signless
  }
}

Response

If the signless boolean flag is set to true, this means they can use the built-in profile manager on the API.

Note: Profiles could have been mapped to another profile manager outside of the Lens API. If so, signless will be false and you will not be able to execute profile manager transactions for this profile.

Enabled/Disable Profile Manager

🚧

This request is protected by authentication

hint: this means it requires an x-access-token header put in the request with your authentication token.

This API call allows you to get the typed data to then call the withSig method to set a profile manager for your Lens profile.

Profile manager allows another address to post, comment, mirror, set follow module and change the profile picture on behalf of you using their wallet

Typed data is a way to try to show the users what they are signing in a more readable format. You can read more about it here.

Constructing that type of data is normally difficult. On the type data, you also need to get the nonce, deadline, contract version, contract address, chain id, and the name of the contract for the signature to be able to be signed and verified.

When using this API the server checks every detail before it generates the typed data. For example: if you try to create typed data on an always failing transaction the server will throw an error in a human-readable form. This is great for debugging but also saves issues with users sending always failing transactions or a mismatch of a bad request.

We will show you the typed data approach using ethers and the API side by side. Keep in mind that with the typed data approach you use the withSig methods which can be called by you with your signature or with that signature any relay could call it for you on your behalf allowing gasless transactions.

Parameters

  • approveSignless: boolean (required)
    • Flag to determine whether the Lens Profile Manager is enabled or not.
  • changeManagers : ChangeProfileManager[] (required)
    • address: EvmAddress
      • The address of the profile manager
    • action: ChangeProfileManagerActionType
      • Either ChangeProfileManagerActionType.ADD to add a new profile manager or ChangeProfileManagerActionType.REMOVE to remove

Invocation

 const typedDataResult = await lensClient.profile.createChangeProfileManagersTypedData({
    approveSignless: true, // or false to disable
    // leave blank if you want to use the lens API dispatcher!
    // changeManagers: [
    //   {
    //     action: ChangeProfileManagerActionType.Add,
    //     address: '0xEEA0C1f5ab0159dba749Dc0BAee462E5e293daaF',
    //   },
    // ],
  });
mutation CreateChangeProfileManagersTypedData(
  $request: ChangeProfileManagersRequest!
  $options: TypedDataOptions
) {
  createChangeProfileManagersTypedData(request: $request, options: $options) {
    id
    expiresAt
    typedData {
      types {
        ChangeDelegatedExecutorsConfigWithSig {
          name
          type
        }
      }
      domain {
        __typename
        name
        chainId
        version
        verifyingContract
      }
      value {
        nonce
        deadline
      }
    }
  }
}

Response

The response is the typed data object for changing profile manager for a profile, you must then broadcast this onchain using Broadcast Onchain Transaction.

Full LensClient Example

const typedDataResult = await lensClient.profile.createChangeProfileManagersTypedData({
  approveSignless: true,
  changeManagers: [
    {
      action: ChangeProfileManagerActionType.Add,
      address: "0x0000000000",
    },
  ],
});

const { id, typedData } = typedDataResult.unwrap();

// sign with the wallet
const signedTypedData = await wallet._signTypedData(
  typedData.domain,
  typedData.types,
  typedData.value
);

// broadcast onchain
const broadcastOnchainResult = await lensClient.transaction.broadcastOnchain({
  id,
  signature: signedTypedData,
});

const onchainRelayResult = broadcastOnchainResult.unwrap();

if (onchainRelayResult.__typename === "RelayError") {
  console.log(`Something went wrong`);
  return;
}

console.log(
  `Successfully changed profile managers with transaction with id ${onchainRelayResult}, txHash: ${onchainRelayResult.txHash}`
);

Full GraphQL API Example

📘

Enable / Disable Profile Manager GraphQL API examples

Enable Profile Manager

Disable Profile Manager

Hooking in without using the type data

You may not want to go down the typed data with the signature route and just send the transaction directly from the client to the blockchain without any API call to map the data for you. You will need to do the encoding and validation yourself if you go down that approach. This is out of scope for the API documentation as would have been explained and showed how to do it in the contract docs. This tries to advise the same practice as what seaport on OpenSea are doing alongside a lot of other projects which tries to improve the visibility of what the user is signing.

Our profile manager resolver contains: