PageSourceSearch

https://lens-protocol-docs.vercel.app/docs/_next/static/chunks/pages/protocol/groups/rules-0aa77776a3a5ea41.js

js lens-protocol-docs.vercel.app collected 2026-10-03 07:16:41 UTC 45,363 bytes, 1 lines download raw bytes

1(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3287],{19543:function(e,n,a){"use strict";a.r(n),a.d(n,{meta:function(){return o}});var r=a(11527),t=a(58627),s=a(89895),o=(a(17063),{showBreadcrumbs:!1,showTableOfContents:!0,showPrev:!0,showNext:!0}),l=function(e){var n=e.children;return(0,r.jsx)(s.Z,{meta:o,children:n})};function i(e){var n=Object.assign({h1:"h1",p:"p",hr:"hr",ul:"ul",li:"li",code:"code",strong:"strong",h2:"h2",a:"a",h3:"h3",pre:"pre",h4:"h4",table:"table",thead:"thead",tr:"tr",th:"th",tbody:"tbody",td:"td"},(0,t.a)(),e.components),a=n.Alert,s=n.Tabs,o=n.TabItem,l=n.MultiCodeBlock,i=n.Steps;return a||c("Alert",!0),l||c("MultiCodeBlock",!0),i||c("Steps",!0),o||c("TabItem",!0),s||c("Tabs",!0),(0,r.jsxs)(r.Fragment,{children:["\n",(0,r.jsx)(n.h1,{children:"Group Rules"}),"\n",(0,r.jsx)(n.p,{children:"This guide explains how to use Group Rules and how to implement custom ones."}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.p,{children:"Group Rules allow administrators to add requirements or constraints for joining or leaving a Group."}),"\n",(0,r.jsx)(n.p,{children:"Lens provides four built-in Group rules:"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"SimplePaymentGroupRule"})," - Requires an ERC-20 or native token payment to join the Group."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"TokenGatedGroupRule"})," - Requires an account to hold a certain token to join the Group."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"MembershipApprovalGroupRule"})," - Requires approval by owner or administrators of the Group to join."]}),"\n"]}),"\n",(0,r.jsx)(a,{tone:"valid",solid:!0,children:(0,r.jsxs)(n.p,{children:["For the ",(0,r.jsx)(n.code,{children:"SimplePaymentGroupRule"}),", a ",(0,r.jsx)(n.strong,{children:"1.5%"})," Lens treasury fee is deducted\nfrom the payment before the remaining amount is transferred to the designated\nrecipient."]})}),"\n",(0,r.jsx)(n.p,{children:"It is also possible to use custom Group Rules to extend the functionality of your Group."}),"\n",(0,r.jsx)(n.h2,{children:"Using Group Rules"}),"\n",(0,r.jsx)(a,{tone:"info",children:(0,r.jsxs)(n.p,{children:["This section presumes you are familiar with the process of ",(0,r.jsx)(n.a,{href:"./create",children:"creating a\nGroup"})," on Lens."]})}),"\n",(0,r.jsx)(n.h3,{children:"Simple Payment Group Rule"}),"\n",(0,r.jsx)(n.p,{children:"This rule requires a native GHO (GRASS on the Lens Testnet) or ERC-20 payment to join a Group. Configuration includes the token address, the payment amount, and the recipient address."}),"\n",(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"ERC-20 Payment",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { bigDecimal, evmAddress, uri } from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [\n      {\n        simplePaymentRule: {\n          erc20: {\n            currency: evmAddress("0x5678\u2026"),\n            value: bigDecimal("1.0"),\n          },\n          recipient: evmAddress("0x9012\u2026"),\n        },\n      },\n    ],\n  },\n});\n'})}),(0,r.jsx)(n.pre,{filename:"Native Payment",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { bigDecimal, evmAddress, uri } from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [\n      {\n        simplePaymentRule: {\n          native: bigDecimal("1.0"),\n          recipient: evmAddress("0x9012\u2026"),\n        },\n      },\n    ],\n  },\n});\n'})})]})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsx)(n.pre,{filename:"Mutation",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  createGroup(\n    request: {\n      metadataUri: "lens://4f91c\u2026"\n      rules: {\n        required: [\n          {\n            simplePaymentRule: {\n              erc20: { currency: "0x5678\u2026", value: "1.0" }\n              # or\n              # native: "1.0",\n\n              recipient: "0x9012\u2026"\n            }\n          }\n        ]\n      }\n    }\n  ) {\n    ... on CreateGroupResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),"\n",(0,r.jsx)(n.h3,{children:"Token Gated Group Rule"}),"\n",(0,r.jsx)(n.p,{children:"This rule requires holding a certain balance of a token (fungible or non-fungible) to join a Group."}),"\n",(0,r.jsx)(n.p,{children:"Configuration includes the token address, the token standard (ERC-20, ERC-721, or ERC-1155), and the required token amount. For ERC-1155 tokens, an additional token type ID is required."}),"\n",(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsx)(n.pre,{filename:"Token Gated Group Rule",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import {\n  bigDecimal,\n  evmAddress,\n  uri,\n  TokenStandard,\n} from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [\n      {\n        tokenGatedRule: {\n          token: {\n            currency: evmAddress("0x1234\u2026"),\n            standard: TokenStandard.Erc721,\n            value: bigDecimal("1"),\n          },\n        },\n      },\n    ],\n  },\n});\n'})})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsx)(n.pre,{filename:"Mutation",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  createGroup(\n    request: {\n      metadataUri: "lens://4f91c\u2026"\n      rules: {\n        required: [\n          {\n            tokenGatedRule: {\n              token: { standard: ERC721, currency: "0x1234\u2026", value: "1" }\n            }\n          }\n        ]\n      }\n    }\n  ) {\n    ... on CreateGroupResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),"\n",(0,r.jsx)(n.h3,{children:"Membership Approval Group Rule"}),"\n",(0,r.jsx)(n.p,{children:"This rule requires approval by the owner or administrators to join a Group."}),"\n",(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsx)(n.pre,{filename:"Membership Approval Group Rule",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { uri } from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [{ membershipApprovalRule: { enable: true } }],\n  },\n});\n'})})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsx)(n.pre,{filename:"Mutation",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  createGroup(\n    request: {\n      metadataUri: "lens://4f91c\u2026"\n      rules: { required: [{ membershipApprovalRule: { enable: true } }] }\n    }\n  ) {\n    ... on CreateGroupResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),"\n",(0,r.jsxs)(n.p,{children:["See the ",(0,r.jsx)(n.a,{href:"./membership-approvals",children:"Membership Approvals"})," guide for more information on how to handle membership approval."]}),"\n",(0,r.jsx)(n.h3,{children:"Custom Group Rules"}),"\n",(0,r.jsx)(n.p,{children:"You can also use custom rules by specifying the rule contract address, when it applies, and the configuration parameters as key-value pairs."}),"\n",(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsx)(n.pre,{filename:"Custom Group Rule",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import {\n  blockchainData,\n  evmAddress,\n  GroupRuleExecuteOn,\n  uri,\n} from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [\n      {\n        unknownRule: {\n          address: evmAddress("0x1234\u2026"),\n          executeOn: [GroupRuleExecuteOn.Joining],\n          params: [\n            {\n              raw: {\n                // 32 bytes key (e.g., keccak(name))\n                key: blockchainData("0xac5f04\u2026"),\n                // an ABI encoded value\
1n                data: blockchainData("0x00"),\n              },\n            },\n          ],\n        },\n      },\n    ],\n  },\n});\n'})})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsx)(n.pre,{filename:"Mutation",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  createGroup(\n    request: {\n      metadataUri: "lens://4f91c\u2026"\n      rules: {\n        required: [\n          {\n            unknownRule: {\n              address: "0x1234\u2026"\n              executeOn: [JOINING]\n              params: [\n                {\n                  raw: {\n                    key: "0x4f\u2026" # 32-byte key (e.g., keccak(name))\n                    data: "0x00" # ABI-encoded value\n                  }\n                }\n              ]\n            }\n          }\n        ]\n      }\n    }\n  ) {\n    ... on CreateGroupResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),"\n",(0,r.jsx)(n.h3,{children:"Combining Rules"}),"\n",(0,r.jsx)(n.p,{children:"Additionally, multiple rules can be combined:"}),"\n",(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsx)(n.pre,{filename:"Combining Rules",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import {\n  bigDecimal,\n  evmAddress,\n  TokenStandard,\n  uri,\n} from "@lens-protocol/client";\nimport { createGroup } from "@lens-protocol/client/actions";\n\nconst result = await createGroup(sessionClient, {\n  metadataUri: uri("lens://4f91c\u2026"),\n  rules: {\n    required: [\n      {\n        simplePaymentRule: {\n          erc20: {\n            currency: evmAddress("0x5678\u2026"),\n            value: bigDecimal("10.42"),\n          },\n          recipient: evmAddress("0x9012\u2026"),\n        },\n      },\n    ],\n    anyOf: [\n      {\n        tokenGatedRule: {\n          token: {\n            currency: evmAddress("0x1234\u2026"),\n            standard: TokenStandard.Erc721,\n            value: bigDecimal("1"),\n          },\n        },\n      },\n      {\n        tokenGatedRule: {\n          token: {\n            currency: evmAddress("0x3456\u2026"),\n            standard: TokenStandard.Erc721,\n            value: bigDecimal("1"),\n          },\n        },\n      },\n    ],\n  },\n});\n'})})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsx)(n.pre,{filename:"Mutation",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  createGroup(\n    request: {\n      metadataUri: "lens://4f91c\u2026"\n      rules: {\n        required: [\n          {\n            simplePaymentRule: {\n              erc20: { currency: "0x5678\u2026", value: "1.0" }\n              # or\n              # native: "1.0",\n              recipient: "0x9012\u2026"\n            }\n          }\n        ]\n        anyOf: [\n          {\n            tokenGatedRule: {\n              token: { standard: ERC721, currency: "0x1234\u2026", value: "1" }\n            }\n          }\n          {\n            tokenGatedRule: {\n              token: { standard: ERC721, currency: "0x3456\u2026", value: "1" }\n            }\n          }\n        ]\n      }\n    }\n  ) {\n    ... on CreateGroupResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),"\n",(0,r.jsx)(n.h3,{children:"Update a Group Rules"}),"\n",(0,r.jsx)(n.p,{children:"To update a Group rules configuration, follow these steps."}),"\n",(0,r.jsx)(a,{tone:"info",children:(0,r.jsxs)(n.p,{children:["You MUST be authenticated as ",(0,r.jsx)(n.a,{href:"../authentication",children:"Builder"}),", ",(0,r.jsx)(n.a,{href:"../authentication",children:"Account\nManager"}),", or ",(0,r.jsx)(n.a,{href:"../authentication",children:"Account Owner"})," and be\neither the owner or admin of the Group to update its Rules."]})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsx)(n.h4,{children:"Identify Current Rules"}),(0,r.jsx)(n.p,{children:"First, inspect the:"}),(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"group.membershipApprovalEnabled"})," flag to know if the Group has the ",(0,r.jsx)(n.code,{children:"MembershipApprovalGroupRule"})," enabled."]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"group.rules"})," field to know details on all rules configuration of the Group."]}),"\n"]}),(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"ts",label:"TypeScript",default:!0,children:(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"GroupRules",children:(0,r.jsx)(n.code,{className:"language-ts",children:'type GroupRules = {\n  __typename: "GroupRules";\n  required: GroupRule[];\n  anyOf: GroupRule[];\n};\n'})}),(0,r.jsx)(n.pre,{filename:"GroupRule",children:(0,r.jsx)(n.code,{className:"language-ts",children:'type GroupRule = {\n  __typename: "GroupRule";\n  id: RuleId;\n  type: GroupRuleType;\n  address: EvmAddress;\n  executesOn: GroupRuleExecuteOn[];\n  config: AnyKeyValue[];\n};\n'})}),(0,r.jsx)(n.pre,{filename:"AnyKeyValue",children:(0,r.jsx)(n.code,{className:"language-ts",children:"type AnyKeyValue =\n  | IntKeyValue\n  | IntNullableKeyValue\n  | AddressKeyValue\n  | StringKeyValue\n  | BooleanKeyValue\n  | RawKeyValue\n  | BigDecimalKeyValue\n  | DictionaryKeyValue\n  | ArrayKeyValue;\n"})}),(0,r.jsx)(n.pre,{filename:"ArrayKeyValue",children:(0,r.jsx)(n.code,{className:"language-ts",children:'type ArrayKeyValue = {\n  __typename: "ArrayKeyValue";\n  key: string;\n  array:\n    | IntKeyValue\n    | IntNullableKeyValue\n    | AddressKeyValue\n    | StringKeyValue\n    | BooleanKeyValue\n    | RawKeyValue\n    | BigDecimalKeyValue\n    | DictionaryKeyValue;\n};\n'})}),(0,r.jsx)(n.pre,{filename:"DictionaryKeyValue",children:(0,r.jsx)(n.code,{className:"language-ts",children:'type DictionaryKeyValue = {\n  __typename: "DictionaryKeyValue";\n  key: string;\n  dictionary:\n    | IntKeyValue\n    | IntNullableKeyValue\n    | AddressKeyValue\n    | StringKeyValue\n    | BooleanKeyValue\n    | RawKeyValue\n    | BigDecimalKeyValue;\n};\n'})}),(0,r.jsx)(n.pre,{filename:"Others",children:(0,r.jsx)(n.code,{className:"language-ts",children:'type IntKeyValue = {\n  __typename: "IntKeyValue";\n  key: string;\n  int: number;\n};\n\ntype IntNullableKeyValue = {\n  __typename: "IntNullableKeyValue";\n  key: string;\n  optionalInt: number | null;\n};\n\ntype AddressKeyValue = {\n  __typename: "AddressKeyValue";\n  key: string;\n  address: EvmAddress;\n};\n\ntype StringKeyValue = {\n  __typename: "StringKeyValue";\n  key: string;\n  string: string;\n};\n\ntype BooleanKeyValue = {\n  __typename: "BooleanKeyValue";\n  key: string;\n  boolean: boolean;\n};\n\ntype RawKeyValue = {\n  __typename: "RawKeyValue";\n  key: string;\n  data: BlockchainData;\n};\n\ntype BigDecimalKeyValue = {\n  __typename: "BigDecimalKeyValue";\n  key: string;
1\n  bigDecimal: BigDecimal;\n};\n'})})]})}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"GroupRules",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"type GroupRules {\n  required: [GroupRule!]!\n  anyOf: [GroupRule!]!\n}\n"})}),(0,r.jsx)(n.pre,{filename:"GroupRule",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"type GroupRule {\n  id: RuleId!\n  type: GroupRuleType!\n  address: EvmAddress!\n  executesOn: [GroupRuleExecuteOn!]!\n  config: [AnyKeyValue!]!\n}\n"})}),(0,r.jsx)(n.pre,{filename:"AnyKeyValue",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"fragment AnyKeyValue on AnyKeyValue {\n  ... on IntKeyValue {\n    ...IntKeyValue\n  }\n  ... on IntNullableKeyValue {\n    ...IntNullableKeyValue\n  }\n  ... on AddressKeyValue {\n    ...AddressKeyValue\n  }\n  ... on StringKeyValue {\n    ...StringKeyValue\n  }\n  ... on BooleanKeyValue {\n    ...BooleanKeyValue\n  }\n  ... on RawKeyValue {\n    ...RawKeyValue\n  }\n  ... on BigDecimalKeyValue {\n    ...BigDecimalKeyValue\n  }\n  ... on DictionaryKeyValue {\n    ...DictionaryKeyValue\n  }\n  ... on ArrayKeyValue {\n    ...ArrayKeyValue\n  }\n}\n"})}),(0,r.jsx)(n.pre,{filename:"ArrayKeyValue",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"fragment ArrayKeyValue on ArrayKeyValue {\n  __typename\n  key\n  array {\n    ... on IntKeyValue {\n      ...IntKeyValue\n    }\n    ... on IntNullableKeyValue {\n      ...IntNullableKeyValue\n    }\n    ... on AddressKeyValue {\n      ...AddressKeyValue\n    }\n    ... on StringKeyValue {\n      ...StringKeyValue\n    }\n    ... on BooleanKeyValue {\n      ...BooleanKeyValue\n    }\n    ... on RawKeyValue {\n      ...RawKeyValue\n    }\n    ... on BigDecimalKeyValue {\n      ...BigDecimalKeyValue\n    }\n    ... on DictionaryKeyValue {\n      ...DictionaryKeyValue\n    }\n  }\n}\n"})}),(0,r.jsx)(n.pre,{filename:"DictionaryKeyValue",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"fragment DictionaryKeyValue on DictionaryKeyValue {\n  __typename\n  key\n  dictionary {\n    ... on IntKeyValue {\n      ...IntKeyValue\n    }\n    ... on IntNullableKeyValue {\n      ...IntNullableKeyValue\n    }\n    ... on AddressKeyValue {\n      ...AddressKeyValue\n    }\n    ... on StringKeyValue {\n      ...StringKeyValue\n    }\n    ... on BooleanKeyValue {\n      ...BooleanKeyValue\n    }\n    ... on RawKeyValue {\n      ...RawKeyValue\n    }\n    ... on BigDecimalKeyValue {\n      ...BigDecimalKeyValue\n    }\n  }\n}\n"})}),(0,r.jsx)(n.pre,{filename:"Others",children:(0,r.jsx)(n.code,{className:"language-graphql",children:"fragment IntKeyValue on IntKeyValue {\n  __typename\n  key\n  int\n}\n\nfragment IntNullableKeyValue on IntNullableKeyValue {\n  __typename\n  key\n  optionalInt\n}\n\nfragment AddressKeyValue on AddressKeyValue {\n  __typename\n  key\n  address\n}\n\nfragment StringKeyValue on StringKeyValue {\n  __typename\n  key\n  string\n}\n\nfragment BooleanKeyValue on BooleanKeyValue {\n  __typename\n  key\n  boolean\n}\n\nfragment RawKeyValue on RawKeyValue {\n  __typename\n  key\n  data\n}\n\nfragment BigDecimalKeyValue on BigDecimalKeyValue {\n  __typename\n  key\n  bigDecimal\n}\n"})})]})})]}),(0,r.jsx)(n.p,{children:"The configuration for the built-in rules with one or more parameters is as follows."}),(0,r.jsxs)(s,{children:[(0,r.jsx)(o,{value:"SimplePayment",label:"SimplePaymentGroupRule",default:!0,children:(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetContract"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"EvmAddress"})}),(0,r.jsx)(n.td,{children:"Address of the ERC-20 or native token contract."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetName"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"String"})}),(0,r.jsx)(n.td,{children:"Name of the ERC-20 or native token."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetSymbol"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"String"})}),(0,r.jsx)(n.td,{children:"Symbol of the ERC-20 or native token."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"amount"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"BigDecimal"})}),(0,r.jsx)(n.td,{children:"Payment required to join."})]})]})]})}),(0,r.jsx)(o,{value:"TokenGated",label:"TokenGatedGroupRule",children:(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Key"}),(0,r.jsx)(n.th,{children:"Type"}),(0,r.jsx)(n.th,{children:"Description"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetContract"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"EvmAddress"})}),(0,r.jsx)(n.td,{children:"Address of the token contract."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetName"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"String"})}),(0,r.jsx)(n.td,{children:"Name of the token."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"assetSymbol"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"String"})}),(0,r.jsx)(n.td,{children:"Symbol of the token."})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"amount"})}),(0,r.jsx)(n.td,{children:(0,r.jsx)(n.code,{children:"BigDecimal"})}),(0,r.jsx)(n.td,{children:"Minimum number of tokens required to join."})]})]})]})})]}),(0,r.jsx)(a,{tone:"valid",solid:!0,children:(0,r.jsx)(n.p,{children:"Keep note of the Rule IDs you might want to remove."})}),(0,r.jsx)(n.h4,{children:"Update the Rules Configuration"}),(0,r.jsx)(n.p,{children:"Next, update the rules configuration of the Group as follows."}),(0,r.jsxs)(s,{children:[(0,r.jsxs)(o,{value:"ts",label:"TypeScript",default:!0,children:[(0,r.jsxs)(n.p,{children:["Use the ",(0,r.jsx)(n.code,{children:"updateGroupRules"})," action to update the rules configuration of a given group."]}),(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"Add Rules",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { bigDecimal, evmAddress, TokenStandard } from "@lens-protocol/client";\nimport { updateGroupRules } from "@lens-protocol/client/actions";\n\nconst result = await updateGroupRules(sessionClient, {\n  group: group.address,\n  toAdd: {\n    required: [\n      {\n        tokenGatedRule: {\n          token: {\n            currency: evmAddress("0x1234\u2026"),\n            standard: TokenStandard.Erc721,\n            value: bigDecimal("1"),\n          },\n        },\n      },\n    ],\n  },\n});\n'})}),(0,r.jsx)(n.pre,{filename:"Remove Rules",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { updateGroupRules } from "@lens-protocol/client/actions";\n\nconst result = await updateGroupRules(sessionClient, {\n  group: group.address,\n  toRemove: [group.rules.required[0].id],\n});\n'})})]})]}),(0,r.jsxs)(o,{value:"api",label:"GraphQL",children:[(0,r.jsxs)(n.p,{children:["Use the ",(0,r.jsx)(n.code,{children:"updateGroupRules"})," mutation to update the rules configuration of a given group."]}),(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"Add Rules",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  updateGroupRules(\n    request: {\n      group: "0x1234\u2026"\n      toAdd: {\n        required: [\n          {\n            tokenGatedRule: {\n              token: { standard: ERC20, currency: "0x5678\u2026", value: "1.5" }\n            }\n          }\n        ]\n      }\n    }\n  ) {\n    ... on UpdateGroupRulesResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})}),(0,r.jsx)(n.pre,{filename:"Remove Rules",children:(0,r.jsx)(n.code,{className:"language-graphql",children:'mutation {\n  updateGroupRules(request: { group: "0x1234\u2026", toRemove: ["ej6g\u2026"] }) {\n    ... on UpdateGroupRulesResponse {\n      hash\n    }\n    ... on SponsoredTransactionRequest {\n      ...SponsoredTransactionRequest\n    }\n    ... on SelfFundedTransactionRequest {\n      ...SelfFundedTransactionRequest\n    }\n    ... on TransactionWillFail {\n      reason\n    }\n  }\n}\n'})})]})]}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]}),(0,r.jsx)(n.h4,{children:"Handle Result"}),(0,r.jsxs)(s,{children:[(0,r.jsxs)(o,{value:"ts",label:"TypeScript",default:!0,children:[(0,r.jsx)(n.p,{children:"The
1n, handle the result using the adapter for the library of your choice:"}),(0,r.jsxs)(l,{children:[(0,r.jsx)(n.pre,{filename:"viem",highlight:"1,9,10",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { handleOperationWith } from "@l ens-protocol/client/viem";\n\n// \u2026\n\nconst result = await updateGroupRules(sessionClient, {\n  group: group.address,\n  // \u2026\n})\n  .andThen(handleOperationWith(walletClient))\n  .andThen(sessionClient.waitForTransaction);\n'})}),(0,r.jsx)(n.pre,{filename:"ethers",highlight:"1,9,10",children:(0,r.jsx)(n.code,{className:"language-ts",children:'import { handleOperationWith } from "@lens-protocol/client/ethers";\n\n// \u2026\n\nconst result = await updateGroupRules(sessionClient, {\n  group: group.address,\n  // \u2026\n})\n  .andThen(handleOperationWith(signer))\n  .andThen(sessionClient.waitForTransaction);\n'})})]}),(0,r.jsxs)(n.p,{children:["See the ",(0,r.jsx)(n.a,{href:"../best-practices/transaction-lifecycle",children:"Transaction Lifecycle"})," guide for more information on how to determine the status of the transaction."]})]}),(0,r.jsx)(o,{value:"api",label:"GraphQL",children:(0,r.jsxs)(n.p,{children:["Then, handle the result as explained in the ",(0,r.jsx)(n.a,{href:"../best-practices/transaction-lifecycle",children:"Transaction Lifecycle"})," guide."]})}),(0,r.jsx)(o,{value:"react",label:"React",children:(0,r.jsx)(n.p,{children:"Coming soon"})})]})]}),"\n",(0,r.jsx)(n.hr,{}),"\n",(0,r.jsx)(n.h2,{children:"Building a Group Rule"}),"\n",(0,r.jsx)(n.p,{children:"Let's illustrate the process with an example. We will build a custom Group Rule that requires accounts to have more than a certain amount of Followers in order to join the Group."}),"\n",(0,r.jsxs)(n.p,{children:["To build a custom Group Rule, you must implement the following ",(0,r.jsx)(n.code,{children:"IGroupRule"})," interface:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"interface IGroupRule {\n    function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external;\n\n    function processAddition(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external;\n\n    function processRemoval(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external;\n\n    function processJoining(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external;\n\n    function processLeaving(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external;\n}\n"})}),"\n",(0,r.jsx)(a,{tone:"warning",children:(0,r.jsxs)(n.p,{children:["Each function of this interface must assume to be invoked by the Group\ncontract. In other words, assume the ",(0,r.jsx)(n.code,{children:"msg.sender"})," will be the Group contract."]})}),"\n",(0,r.jsx)(a,{tone:"info",children:(0,r.jsx)(n.p,{children:"A Lens dependency package with all relevant interfaces will be available soon."})}),"\n",(0,r.jsxs)(i,{children:[(0,r.jsx)(n.h3,{children:"Implement the Configure Function"}),(0,r.jsxs)(n.p,{children:["First, implement the ",(0,r.jsx)(n.code,{children:"configure"})," function. This function has the purpose of initializing any required state for the rule to work properly."]}),(0,r.jsxs)(n.p,{children:["It receives two parameters, a 32-byte configuration salt (",(0,r.jsx)(n.code,{children:"configSalt"}),"), and an array of custom parameters as key-value pairs (",(0,r.jsx)(n.code,{children:"ruleParams"}),")."]}),(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"configSalt"})," is there to allow the same rule contract to be used many times, with different configurations, for the same Group. So, for a given Group Rule implementation, the pair (Group Address, Configuration Salt) should identify a rule configuration."]}),(0,r.jsxs)(n.p,{children:["For example, let's think about the ",(0,r.jsx)(n.code,{children:"TokenGatedGroupRule"}),', we could want to achieve the restriction "To join this Group, you must hold 10 WETH and 1 WBTC". However, the ',(0,r.jsx)(n.code,{children:"TokenGatedGroupRule"})," only allows to configure a single token as a gate. So, instead of writing a whole new contract that receives two tokens instead of one, we would just configure the ",(0,r.jsx)(n.code,{children:"TokenGatedGroupRule"})," rule twice in the same Group, once for WETH with some configuration salt, and once for WBTC with another configuration salt."]}),(0,r.jsx)(a,{tone:"warning",children:(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"configure"})," function can be called multiple times by the same Group\npassing the same configuration salt in order to update that rule configuration\n(i.e. reconfigure it)."]})}),(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"ruleParams"})," is an array of key-value pairs that can be used to pass any custom configuration parameters to the rule. Each key is ",(0,r.jsx)(n.code,{children:"bytes32"}),", we put the hash of the parameter name there, and each value is ",(0,r.jsx)(n.code,{children:"bytes"}),", we set the ABI-encoded parameter value there. Given that ",(0,r.jsx)(n.code,{children:"ruleParams"})," is an array, this allows the rule to define which parameters are optional and which are required, acting accordingly when any of them are not present."]}),(0,r.jsx)(n.p,{children:"In our example, we need to decode two parameters: an address, representing the Graph where to perform the amount of followers check, and an integer, which will represent the minimum amount of Followers an account must have in order to become a member of the Group. Let's define a storage mapping to store this configuration:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n    mapping(address group => mapping(bytes32 configSalt => address graph)) internal _graphToCheck;\n    mapping(address group => mapping(bytes32 configSalt => uint256 minFollowers)) internal _minFollowers;\n}\n"})}),(0,r.jsx)(a,{tone:"info",children:(0,r.jsx)(n.p,{children:"The configuration is stored in the mapping using the Group contract address\nand the configuration salt as keys. With this setup, the same rule can be used\nby different Groups, as well as be used by the same Group many times."})}),(0,r.jsxs)(n.p,{children:["Now let's code the ",(0,r.jsx)(n.code,{children:"configure"})," function itself, decoding the parameters and putting them into the storage:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:'contract FollowerCountGatedGroupRule is IGroupRule {\n    mapping(address group => mapping(bytes32 configSalt => address graph)) internal _graphToCheck;\n    mapping(address group => mapping(bytes32 configSalt => uint256 minFollowers)) internal _minFollowers;\n\n    function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override {\n        address graphToCheck;\n        uint256 minFollowers = 100;\n        for (uint256 i = 0; i < ruleParams.length;
1 i++) {\n            if (ruleParams[i].key == keccak256("lens.param,graph")) {\n                graphToCheck = abi.decode(ruleParams[i].value, (address));\n            } else if (ruleParams[i].key == keccak256("lens.param,minFollowers")) {\n                minFollowers = abi.decode(ruleParams[i].value, (uint256));\n            }\n        }\n        // Aims to check if the graph is a valid Graph contract\n        IGraph(graphToCheck).getFollowersCount(address(this));\n        _graphToCheck[msg.sender][configSalt] = graphToCheck;\n        _minFollowers[msg.sender][configSalt] = minFollowers;\n    }\n}\n\n'})}),(0,r.jsxs)(n.p,{children:["As you can see, we treated the minimum followers parameter as optional, setting a default value of 100 followers for it in case that the parameter was not found in the ",(0,r.jsx)(n.code,{children:"ruleParams"}),". On the other hand, the graph parameter is treated as required, without default value, and needing to be found as a valid graph address in order for the ",(0,r.jsx)(n.code,{children:"getFollowersCount"})," call to not revert."]}),(0,r.jsx)(n.h3,{children:"Implement the Process Joining function"}),(0,r.jsxs)(n.p,{children:["Next, implement the ",(0,r.jsx)(n.code,{children:"processJoining"})," function. This function is invoked by the Group contract every time someone tries to join the Group, so then our custom logic can be applied to shape under which conditions the operation can succeed."]}),(0,r.jsxs)(n.p,{children:["The function receives the configuration salt (",(0,r.jsx)(n.code,{children:"configSalt"}),"), so we know which configuration to use, the account attempting to join the Group (",(0,r.jsx)(n.code,{children:"account"}),"), an array of key-value pairs with the custom parameters passed to the Group (",(0,r.jsx)(n.code,{children:"primitiveParams"}),"), and an array of key-value pairs in case the rule requires additional parameters to work (",(0,r.jsx)(n.code,{children:"ruleParams"}),")."]}),(0,r.jsx)(n.p,{children:"The function must revert in case of not meeting the requirements imposed by the rule."}),(0,r.jsx)(n.p,{children:"We first get the configured Graph where to perform the check:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n    mapping(address group => mapping(bytes32 configSalt => address graph)) internal _graphToCheck;\n    mapping(address group => mapping(bytes32 configSalt => uint256 minFollowers)) internal _minFollowers;\n\n    // . . .\n\n    function processJoining(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        // We get the Graph where to check the followers count\n        IGraph graph = IGraph(_graphToCheck[msg.sender][configSalt]);\n    }\n}\n"})}),(0,r.jsxs)(n.p,{children:["Next we require that ",(0,r.jsx)(n.code,{children:"account"})," has at least the amount of followers required by the rule configuration."]}),(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"IGraph"})," interface contains this function in order to check the amount of followers of a given account:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"    function getFollowersCount(address account) external view returns (uint256);\n"})}),(0,r.jsx)(n.p,{children:"So, let's add the requirement check and we are done with this function:"}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n    mapping(address group => mapping(bytes32 configSalt => address graph)) internal _graphToCheck;\n    mapping(address group => mapping(bytes32 configSalt => uint256 minFollowers)) internal _minFollowers;\n\n    // . . .\n\n    function processJoining(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        IGraph graph = IGraph(_graphToCheck[msg.sender][configSalt]);\n        // We check if the account has the min required amount of followers\n        require(graph.getFollowersCount(account) >= _minFollowers[msg.sender][configSalt]);\n    }\n}\n"})}),(0,r.jsx)(n.h3,{children:"Implement the Process Leaving function"}),(0,r.jsxs)(n.p,{children:["Next, implement the ",(0,r.jsx)(n.code,{children:"processLeaving"})," function. This function is invoked by the Group contract every time someone tries to leave the Group, so then our custom logic can be applied to shape under which conditions the operation can succeed."]}),(0,r.jsxs)(n.p,{children:["The parameters are the same as in the ",(0,r.jsx)(n.code,{children:"processJoining"})," function except that the ",(0,r.jsx)(n.code,{children:"account"})," is trying to leave the Group instead of joining it."]}),(0,r.jsxs)(n.p,{children:["Given that we do not want to apply any restriction to the leaving operation, we can just revert the function with a ",(0,r.jsx)(n.code,{children:"NotImplemented"})," error, which is the safest approach in case someone accidentally applies this rule:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n\n    // . . .\n\n    function processLeaving(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\
1n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n}\n"})}),(0,r.jsx)(n.h3,{children:"Implement the Process Removal function"}),(0,r.jsxs)(n.p,{children:["Next, implement the ",(0,r.jsx)(n.code,{children:"processRemoval"})," function. This function is invoked by the Group contract every time a Group member is trying to be removed, so then our rule can define if this operation must succeed or not."]}),(0,r.jsxs)(n.p,{children:["The function receives the configuration salt (",(0,r.jsx)(n.code,{children:"configSalt"}),"), so we know which configuration to use, the address that is trying to remove the member (",(0,r.jsx)(n.code,{children:"originalMsgSender"}),"), the account trying to be removed of the Group (",(0,r.jsx)(n.code,{children:"account"}),"), an array of key-value pairs with the custom parameters passed to the Group (",(0,r.jsx)(n.code,{children:"primitiveParams"}),"), and an array of key-value pairs in case the rule requires additional parameters to work (",(0,r.jsx)(n.code,{children:"ruleParams"}),")."]}),(0,r.jsx)(n.p,{children:"The function must revert in case of not meeting the requirements imposed by the rule. In this case, we do not want to impose any restriction on the removal operation. As a good practice, we revert for unimplemented rule functions, as it is safer in case the rule becomes accidentally applied."}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n\n    // . . .\n\n    function processRemoval(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n}\n"})}),(0,r.jsx)(n.h3,{children:"Implement the Process Addition function"}),(0,r.jsxs)(n.p,{children:["Finally, implement the ",(0,r.jsx)(n.code,{children:"processAddition"})," function. This function is invoked by the Group contract every time a Group member is trying to be added, so then our rule can define if this operation must succeed or not."]}),(0,r.jsxs)(n.p,{children:["The parameters are the same as in the ",(0,r.jsx)(n.code,{children:"processRemoval"})," function except that the ",(0,r.jsx)(n.code,{children:"account"})," is trying to be added to the Group instead of removed from it."]}),(0,r.jsxs)(n.p,{children:["Same as in the ",(0,r.jsx)(n.code,{children:"processRemoval"}),", here in the ",(0,r.jsx)(n.code,{children:"processAddition"})," we do not want to impose any restriction, so we revert the function with a ",(0,r.jsx)(n.code,{children:"NotImplemented"})," error:"]}),(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:"contract FollowerCountGatedGroupRule is IGroupRule {\n\n    // . . .\n\n    function processAddition(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n}\n"})})]}),"\n",(0,r.jsxs)(n.p,{children:["Now the ",(0,r.jsx)(n.code,{children:"FollowerCountGatedGroupRule"})," is ready to be applied into any Group. See the full code below:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-solidity",children:'contract FollowerCountGatedGroupRule is IGroupRule {\n    mapping(address group => mapping(bytes32 configSalt => address graph)) internal _graphToCheck;\n    mapping(address group => mapping(bytes32 configSalt => uint256 minFollowers)) internal _minFollowers;\n\n    function configure(bytes32 configSalt, KeyValue[] calldata ruleParams) external override {\n        address graphToCheck;\n        uint256 minFollowers = 100;\n        for (uint256 i = 0; i < ruleParams.length; i++) {\n            if (ruleParams[i].key == keccak256("lens.param,graph")) {\n                graphToCheck = abi.decode(ruleParams[i].value, (address));\n            } else if (ruleParams[i].key == keccak256("lens.param,minFollowers")) {\n                minFollowers = abi.decode(ruleParams[i].value, (uint256));\n            }\n        }\n        // Aims to check if the graph is a valid Graph contract\n        IGraph(graphToCheck).getFollowersCount(address(this));\n        _graphToCheck[msg.sender][configSalt] = graphToCheck;\n        _minFollowers[msg.sender][configSalt] = minFollowers;\n    }\n\n    function processAddition(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\
1n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n\n    function processRemoval(\n        bytes32 configSalt,\n        address originalMsgSender,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n\n    function processJoining(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        // We get the Graph where to check the followers count\n        IGraph graph = IGraph(_graphToCheck[msg.sender][configSalt]);\n        // We check if the account has the min required amount of followers\n        require(graph.getFollowersCount(account) >= _minFollowers[msg.sender][configSalt]);\n    }\n\n    function processLeaving(\n        bytes32 configSalt,\n        address account,\n        KeyValue[] calldata primitiveParams,\n        KeyValue[] calldata ruleParams\n    ) external override {\n        revert Errors.NotImplemented();\n    }\n}\n'})}),"\n",(0,r.jsx)(n.p,{children:"Stay tuned for API integration of rules and more guides!"})]})}function c(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}n.default=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return(0,r.jsx)(l,Object.assign({},e,{children:(0,r.jsx)(i,e)}))}},17046:function(e,n,a){(window.__NEXT_P=window.__NEXT_P||[]).push(["/protocol/groups/rules",function(){return a(19543)}])}},function(e){e.O(0,[9774,3788,9895,2888,179],(function(){return n=17046,e(e.s=n);var n}));var n=e.O();_N_E=n}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.