Follow
This request is protected by authentication
hint: this means it requires an x-access-token header put in the request with your authentication token.
Lens Profile Manager Compatible: Gasless & Signless
This action can be used through the Lens Profile Manager to enable a gasless and signless experience.
Follow a Lens Profile so that the profile's content is included in all feed based queries and gain the ability to perform actions only available to a profile's followers.
There are two different approaches you can use to follow a profile. Depending on the whitelist status of your app and the settings of the profile you would like to follow from, you can use:
a) Follow via Lens Profile Manager
- Criteria:
- Your app is whitelisted (see Whitelisting Your App)
- AND
- The profile you would like to follow from has enabled the Lens Profile Manager (see Lens Profile Manager)
b) Follow Using TypedData and Broadcasting Onchain via the API
- Criteria:
- Your app is not whitelisted
- OR
- The profile you would like to follow from has not enabled the Lens Profile Manager
a) Follow via Lens Profile Manager
If possible, using the Lens Profile Manager is the best way to execute a follow action. This will be a gasles and signless operation.
Request
You can follow many people in a single contract call so the interface here is designed around that as well.
- follow:
Array<Follow>
(required)- profileId:
string
(required)- The profileId of the profile you would like to follow.
- followModule:
FollowModule
(optional)- If you are following someone who has a follow module defined you must pass in the properties to redeem it. We make you pass in the properties from the client-side because if we read it from the server each time someone could front-run the request and make you sign something which your client was not seeing at the time of generating the signature. Follow modules can be changed at any time by the profile. If no follow module is setup for this profile you do not need to pass anything in.
- Lens Profile Manager only supports the free follow module.
- profileId:
Invocation
const result = await lensClient.profile.follow({
follow: [
{
profileId: "PROFILE_TO_FOLLOW_ID",
},
],
});
mutation Follow($request: FollowLensManagerRequest!) {
follow(request: $request) {
... on RelaySuccess {
...RelaySuccess
}
... on LensProfileManagerRelayError {
...LensProfileManagerRelayError
}
}
}
Response
{
"txHash": "0x000000",
"txId": "0x01"
}
{
"reason": "FAILED" // LensProfileManagerRelayErrorReasonType
}
b) Follow Using TypedData and Broadcasting Onchain via the API
Request
You can follow many people in a single contract call so the interface here is designed around that as well.
- follow:
Array<Follow>
(required)- profileId:
string
(required)- The profileId of the profile you would like to follow.
- followModule:
FollowModule
(optional)- The follow module data. Lens Profile Manager only supports the free follow module.
- profileId:
Additional Information on Follow Modules
If you are following someone who has a follow module defined you must pass in the properties to redeem it. We make you pass in the properties from the client-side because if we read it from the server each time someone could front-run the request and make you sign something which your client was not seeing at the time of generating the signature. Follow modules can be changed at any time by the profile. If no follow module is setup for this profile you do not need to pass anything in.
Defining the follow module to be redeemed is very easy with the schema we have created:
Fee Follow module
The person you want to follow requires sets a fee required in order to follow them. To enable this you need to set the feeFollowModule
to true
.
mutation CreateFollowTypedData {
createFollowTypedData(
request: {
follow: [{ profileId: "0x01", followModule: { feeFollowModule: true } }]
}
) {
...CreateFollowBroadcastItemResult
}
}
Unknown Follow Module
If the profile you want to follow has an unknown follow module set, you must compose the follow module request to match.
mutation CreateFollowTypedData {
createFollowTypedData(
request: {
follow: [
{
profileId: "0x01"
followModule: {
unknownFollowModule: { address: "0x000", data: "..." }
}
}
]
}
) {
...CreateFollowBroadcastItemResult
}
}
Invocation
const result = await lensClient.profile.createFollowTypedData({
follow: [
{
profileId: "PROFILE_ID",
},
],
});
mutation CreateFollowTypedData {
createFollowTypedData(request: { follow: [{ profile: "0x01" }] }) {
...CreateFollowBroadcastItemResult
}
}
Response
{
"id": "0x01",
"expiresAt": "2023-10-01T00:00:00Z",
"typedData": {
"types": {
"Follow": [
{ "name": "...", "type": "..." },
{ "name": "...", "type": "..." }
]
},
"domain": {
"name": "...",
"chainId": "...",
"version": "...",
"verifyingContract": "0x0000000"
},
"value": {
"nonce": "...",
"deadline": "2023-10-01T01:00:00Z"
}
}
}
Broadcasting the TypedData
Once you have the typed data for the follow action, you need to get the user to sign with their wallet and then broadcast it onchain.
See Broadcasting Onchain for more information.
Calling the Contract Directly
If you opt to bypass the API and directly push transactions from the client to the blockchain, you'll be responsible for encoding and validation.
This approach isn't covered in the API documentation, you can find guidance in the contract documentation.
Aligned with best practices demonstrated by projects like seaport on OpenSea, this is aimed at enhancing the user's awareness of what they're signing.
Full LensClient Example
Using the Lens Profile Manager:
// lensClient is an authenticated instance of LensClient
const recommendedProfiles = await lensClient.profile.recommendations({
for: "YOUR_PROFILE_ID",
});
console.log(
`First 3 recommended profiles`,
recommendedProfiles.items.slice(0, 3).map((p) => ({
id: p.id,
handle: p.handle,
isFollowedByMe: p.isFollowedByMe,
}))
);
const result = await lensClient.profile.follow({
follow: [
{
profileId: "PROFILE_TO_FOLLOW_ID",
},
],
});
console.log(
`Follow of ${recommendedProfiles[0].id} triggered with through the Lens Profile Manager: `,
result.unwrap()
);
const followResultValue = result.unwrap();
if (!isSuccessfulLensProfileManagerResponse(followResultValue)) {
throw new Error(`Something went wrong`);
}
await lensClient.transaction.waitUntilComplete({
txId: followResultValue.txId,
});
Using TypedData and Broadcasting Onchain:
const recommendedProfiles = await lensClient.profile.recommendations({
for: "profile-id",
});
const result = await lensClient.profile.createFollowTypedData({
follow: [
{
profileId: recommendedProfiles[1].id,
},
],
});
const data = result.unwrap();
const signedTypedData = await wallet._signTypedData(
data.typedData.domain,
data.typedData.types,
data.typedData.value
);
const broadcastResult = await lensClient.transaction.broadcastOnchain({
id: data.id,
signature: signedTypedData,
});
const followBroadcastResultValue = broadcastResult.unwrap();
if (!isRelaySuccess(followBroadcastResultValue)) {
console.log(`Something went wrong`, followBroadcastResultValue);
return;
}
console.log(
`Transaction to follow ${recommendedProfiles[1].id} was successfuly broadcasted with txId ${followBroadcastResultValue.txId}`
);
// wait for follow to be indexed
console.log(`Waiting for the transaction to be indexed...`);
await lensClient.transaction.waitUntilComplete({
txId: followBroadcastResultValue.txId,
});
Full GraphQL API Example
Updated about 1 month ago