# Group Module
The group
(opens new window) module enables the creation and management of multisig accounts and enables voting for message execution based on configurable decision policies.
# Usage of the group module
When the group module is enabled in a chain (say the Cosmos Hub), this means that users can create groups and submit group proposals. This means that any number of users can be part of a group and vote on the group's proposals. You can think of it as an enhanced multisig or DAO.
Before starting, let's first review some terminology:
- Group Admin: the account that creates the group is the group administrator. The group administrator is the account that can add, remove and change the group members, but does not need to be a member of the group itself. Choose it wisely.
- Group Policy (opens new window): a group policy is an account associated with a group and a decision policy. In order to perform actions on this account, a proposal must be approved by a majority of the group members; or as defined in the decision policy. For the avoidance of doubt, note that a group can have multiple group policies.
- Decision Policy (opens new window): a policy that defines how the group members can vote on a proposal and how the vote outcome is calculated. A decision policy is associated to a group policy. This means that it is possible for a group to have different decision policies for each of its different group policies.
- Proposal: A group proposal works the same way as a governance proposal: group members can submit proposals to the group and vote on proposals with a Yes, No, No with Veto and Abstain.
In this tutorial, you will learn how to create a group, manage its members, submit a group proposal and vote on it. After that you'll be able to create your own on-chain DAO for your own use case.
# Requirements
The group module has been introduced in the v0.46.0 release (opens new window) of the Cosmos SDK.
In order to follow the tutorial, you must use the binary of a chain with the group module, using a v0.46+ version of the SDK.
For demonstration purposes, you will use simd
, the simulation app of the Cosmos SDK.
To install simd
, first clone the Cosmos SDK GitHub repository and checkout the right version:
Go to the cloned directory:
Install simd
Make sure the installation was successful:
The version number should be greater than or equal to 0.46.0
.
# Configuration
If you have used simd
before, you might already have a .simapp
directory in your home directory. You can skip to the next section or remove the chain directory (rm -rf ~/.simapp
).
In order to configure simd
, you need to set the chain ID and the keyring backend.
Secondly, you need to add keys for group users. Call them Alice and Bob.
With simd keys list
you can verify that your two users have been added.
To avoid having to copy and paste the user addresses, now is a good time to export the user keys to variables that you can access and use for this tutorial.
Now you are ready to fund Alice and Bob accounts and use the Alice account as validator:
Lastly, start the chain:
simapp
is now configured and running. You can now play with the group module.
# Create a group
To create a group, you must decide who is the admin and who are the members. All members have a voting weight that is used to calculate their voting power in the group.
Create a members.json
file that contains group members of a football association.
Replace aliceaddr
and bobaddr
with the literal addresses of Alice ($ALICE
) and Bob ($BOB
) respectively.
For the avoidance of doubt, in the JSON above, Alice is labeled with some metadata that identifies her as the "president"
. The presence of this metadata does not make her the administrator of the group. It only identifies her as a member of the group. Presumably one to whom the group's other members will look up.
Create the group:
It is here, by sending the create transaction, that Alice becomes the administrator of the group.
At what ID was the group created? Recall the transaction and look for the attributes of the event whose type is "cosmos.group.v1.EventCreateGroup"
. For instance:
This returns something like:
Where Z3JvdXBfaWQ=
is a Base64 encoding (opens new window) of group_id
, and IjEi
is a Base64 encoding of "1"
, including the "
. Therefore your group ID is 1
. Or with a one-liner:
Query and verify the group that you just created and its ID that you just extracted:
This last command outputs 1
too. This shows you that the group and its id
can be recalled. Use that id
for querying the group members.
Nice! Your group has best football association
as metadata (which you can recall with the group-info
command), Alice as group admin, and Alice and Bob as group members.
# Manage group members
To update the group's members, you send a transaction using the update-group-members
command and a JSON file modeled on the previous members.json
. The file only needs to contain the changes to the membership. Unchanged members do not need to be included in the members_updates.json
.
To add a member to the group, you mention it in the JSON, and to remove a member from the group, you mention it and set this member's voting weight to 0
.
Let's add Carol, Dave and Emma as group members and remove Bob. Create members_update.json
with:
You can verify that the group members are updated:
As an exercise, please add Bob back in the group and go to the next section.
# Create a group policy
Next you need to create a group policy and its decision policy. This defines how long a proposal can be voted on and how its outcome is calculated. Here you use the ThresholdDecisionPolicy
(opens new window) as decision policy. It defines the threshold that the tally of weighted yes votes must reach in order for a proposal to pass. Each member's vote is weighted by its weight as defined in the group.
Following is the content of the policy.json
. It states that:
- A proposal can be voted on for a maximum of 10 minutes.
- A proposal requires only one vote to pass.
Have the group administrator create the group policy with metadata that identifies it as one with a quick turnaround:
Check and verify your newly created group policy and in particular the address you just created:
You can as well find the group policy by querying the group:
Note how the decision policy's address, at cosmos
plus 59 characters is longer than a regular account's address. This is because a group address is a derived address. You can learn more on that in ADR-28 (opens new window).
# Create a proposal
Now that you have a group with a few members and a group policy, you submit your first group proposal.
Like for members management, you need to create a proposal.json
file that contains the proposal.
A proposal can contain any number of messages defined on the current blockchain.
For this tutorial, you continue with your example of an association. The treasurer, Bob, who wants to send money to a third party to pay the bills, creates a proposal.json
:
This proposal, if passed, will send 100 stake
to cosmos1zyzu35rmctfd2fqnnytthheugqs96qxsne67ad
to pay the bills.
The tokens will be sent from the decision policy address.
The decision policy has no funds yet. You can fund it by sending a transaction with simd tx bank send alice $GROUP_POLICY_ADDRESS 100stake
.
Submit the proposal:
Once more, extract the proposal ID (remember to use the transaction hash you got at the previous command):
You can also find the proposal id via your group policy:
# View and vote on proposals
You can see that your proposal has been submitted. And that it contains a lot of information. For instance, confirm that its final tally is empty:
Which returns:
And that it is in the PROPOSAL_STATUS_SUBMITTED
status:
Next, have Alice and Bob vote Yes on the proposal and verify that both their votes are tallied using the proper query command:
While you wait for the policy-prescribed 10 minutes, you can confirm that the final tally is still empty. After the 10 minutes have gone by your proposal should have passed, because the weighted tally of Yes votes is above the decision policy threshold. Confirm this by looking at its status
. It should be PROPOSAL_STATUS_ACCEPTED
:
By default proposals are not executed immediately. You can confirm this by looking at the proposal, it contains executor_result: PROPOSAL_EXECUTOR_RESULT_NOT_RUN
.
This is to account for the fact that not everything may be in place to successfully execute the proposal's messages. As you recall, you already funded the group policy. If you did not fund it ahead of time, now is the time to do it.
Next time, if you wish to try to execute a proposal immediately after its submission, you can do so by using the --exec 1
flag. It will count the proposers signatures as Yes votes.
Execute the proposal now:
If there were any errors when executing the proposal messages, none of the messages will be executed and the proposal will be marked as Failed.
Verify that the proposal has been executed:
It should return an error: Error: rpc error: code = Unknown desc = load proposal: not found: unknown request
. That is because it has been entirely removed.
Confirm that the tokens have been received by the intended recipient:
# 🎉 Congratulations 🎉
By completing this tutorial, you have learned how to use the group
module. In particular how to:
- Create a group.
- Manage its members.
- Add a group policy.
- Submit a group proposal.
- Vote on a proposal.
- Execute an accepted proposal.
For more information about what else you can do with the CLI, please refer to its help.
To learn more about the group module specs, check out the group (opens new window) module developer documentation.