Groups: Custom groups for ZK Badges
Off-chain groups are a reusable tool used by Sismo to generate available groups for attesters.
You will find more information on what are groups in this section:
Generating groups and making them available for an attester require some infrastructures. We have developed a repository, the sismo data source repository, to let anyone propose new groups, and make them available for the HydraS1Attester, with a simple PR.
You will be able to:
  • Create your own group
  • Deploy your own metadata/image for an associated ZK badge
=> Your ZK Badge will be available to mint on the Sismo UI.

Group generators

Generate Function

export default class extends GroupGenerator {
generationFrequency = GenerationFrequency.Once;
async generate(context: GenerationContext): Promise<GroupType[]> {
// add you code here
return [];
}
}
A group generator is a tool that allows to easily generate groups and store them in scalable infrastructure.
The GroupGenerator object is made of a generate function which will be executed at a specific "generationFrequency".
Here the GenerationFrequency is Once. That means it will be executed just one time. It is an Enum that accepts Daily, Weekly or Monthly value.
Let's improve our group generator to return a very simple group:
export default class extends GroupGenerator {
generationFrequency = GenerationFrequency.Once;
async generate(context: GenerationContext): Promise<GroupType[]> {
return [
{
name: "my-simple-group",
timestamp: context.timestamp,
data: {
"0xF61CabBa1e6FC166A66bcA0fcaa83762EdB6D4Bd": 1,
"0x8ab1760889f26cbbf33a75fd2cf1696bfccdc9e6": 2,
},
valueType: ValueType.Info,
tags: [Tags.Mainnet, Tags.User],
},
];
}
}
In the above example, the group generator will create a group named "my-simple-group". Its timestamp will corresponds to the execution of the "generate" function.
This group, "my-simple-group", contains only 2 accounts, which has a value of 1 and 2.
Tags are used to easily retrieve groups once they are generated.

Data Providers

In a group generator, the most interesting part is to query data. We have developed "DataProviders" for that. We currently support:
  • GraphQLProvider: allows to launch arbitrary graphQL queries
  • BigQueryProvider: allows to launch arbitrary BigQuery queries on the ethereum mainnet and polygon dataset
  • SnapshotProvider: allows to query all voters for a proposal or for an entire space
  • SubgraphHostedServiceProvider: allows to launch arbitrary queries on any subGraph.
  • PoapSubgraphProvider: allows to retrieve all attenders of any events.
  • LensProvider: allows to retrieve followers and lens profiles.
You are very welcomed to modify or add your own provider by making a PR.
Let's use a provider to create your group:
export default class extends GroupGenerator {
generationFrequency = GenerationFrequency.Weekly;
async generate(context: GenerationContext): Promise<GroupType[]> {
// Instantiate your snapshot provider
const snapshotProvider = new dataProviders.SnapshotProvider();
// Query all voters
const voters = await snapshotProvider.queryAllVoters({
space: "ens.eth",
});
return [
{
name: "ens-voters",
timestamp: context.timestamp,
data: voters,
valueType: ValueType.Info,
tags: [Tags.Mainnet, Tags.Vote, Tags.User],
},
];
}
}
We saw how we could use data from the "outside" (through API) now we will see how we can combine groups with each others using Data Operators.

Data Operators

Data Operators is an helper to create new groups by combining existing groups.
Currently, there are 3 data operators:
  • Join: join multiples groups data together
  • Intersection: take the intersection between 2 groups data
  • Map: map values of a group data with an other value
export default class extends GroupGenerator {
generationFrequency = GenerationFrequency.Weekly;
async generate(context: GenerationContext): Promise<Group[]> {
// retrieve the latest lens followers group
const sismoFollowers = await this.store.latest("sismo-lens-followers");
// retrieve the latest masquerade followers group
const masqueradeFollowers = await this.store.latest(
"masquerade-lens-followers"
);
// Use the Interesection data operator to create a new group
const sismoAndMasqueradeFollowers = dataOperators.Intersection(
await sismoFollowers.data(),
await masqueradeFollowers.data()
);
return [
{
name: "sismo-and-masquerade-lens-followers",
timestamp: context.timestamp,
data: sismoAndMasqueradeFollowers,
valueType: ValueType.Info,
tags: [Tags.User, Tags.Lens, Tags.Web3Social],
},
];
}
}

Attestations Collections

Once you have made your group generator, you need to make the group available for an attester.
In the attestations-collections/hydra-s1 folder, all the HydraS1Attesters attestations collection are declared.
To make the previous group we created available for the HydraS1SimpleAttestation, we simply needs to add a new AttestationsCollection object for the attester.
Inside it, we will find the group we want to make available and the badge we want to display.
export const hydraS1SimpleAttester = async () =>
new Attester({
collectionIdFirst: 10000001,
attestationsCollections: [
...
// Ethereum-power-users
new AttestationsCollection({
groups: [await Group.store.latest("sismo-and-masquerade-lens-followers")],
badge: new Badge({
name: "Sismo Masquerade Bloomer ZK Badge",
description: "ZK Badge owned by @masquerade.lens and @sismo.lens Lens followers",
image: "./badges/ethereum_power_users.svg",
requirements: [],
}),
}),
]
}
This will automatically deploy the associated metadata for the badge
For more information or help, Join us on discord.