Skip to main content

Class: VotingReputation

VotingReputation (Motions & Disputes)

The VotingReputation extension allows any member of a Colony to propose a Motion to take an action that will pass after a security delay unless somebody Objects. This applies to all actions, such as creating an expenditure, managing funds, or managing teams.

Extension parameters

Before the VotingReputation extension can be used you need to initialize it using a few parameters that heavily influence the Motion lifecycle. For that please see the initialize function and also this document for an in-depth explanation of the various parameters.

What is a Motion?

Within Colony a Motion is an on-chain proposal whose two sides (Yay or Nay) can be supported by staking the Colony's native token for that side. Motions always have an action attached to them which is a contract transaction that can take place in a Colony. For example, Motions could be created to move funds from one team to another, for paying someone that did work or minting new native tokens (even arbitrary transaction on any contract in the name of the Colony are supported!). Motions that pass (the outcome is Yay) will execute the action once they are finalized. If the outcome is Nay, there is no action taking place.

The Motion lifecycle

info

The exact lifecycle is determined by the parameters that were set when the VotingReputation extension was installed for the Colony. You can find a detailed explanation of all the parameters here.

Creating a Motion

See motion or metaMotion.

Anyone within a Colony can start a motion. In Colony SDK, this is as easy as sending a transaction of the same kind. There the action (the contract transaction) for the Motion will be defined. This is essentially nothing else than an encoded contract function string alongside its parameters (see for detailed info here - but don't worry. In Colony SDK this will all be taken care of by the ColonyTxCreator).

Staking

See stakeMotion.

Once a motion is created, native tokens can be staked to support either of its sides (Yay or Nay). A user can only stake as many tokens for either side as they have reputation in the team the motion is created in. A side can be staked by the motion creator and an arbitrary number of additional users as long as they adhere to the minimum stake per user that was defined in the extensions parameters. The maximum amount a user can stake is also determined by the amount of reputation in the team in which the Motion takes place.

Over-staking

Once a side of a Motion is activated, further attempts to stake tokens for that side will revert. It is not necessary or sensible to stake more tokens than needed. Keep in mind that both sides can be activated at the same time (see below for what happens then). You can use the getRemainingStakes method to see how many tokens need to be staked on each side for them to activate.

After the staking phase (which has a predetermined runtime) one of these four cases can happen:

  • Case 1: Yay side reaches minimum stakes, Nay side does not: the motion passed and can be finalized. All stakes are returned
  • Case 2: Nay side reaches minimum stakes, Yay side does not: the motion failed and will not execute. All stakes are returned
  • Case 3: Neither Yay or Nay side have reached minimum stakes: nothing happens. All stakes are returned.
  • Case 4: Both Yay and Nay sides are activated. The Motion will go into Voting immediately (and will not wait out the staking period).

Voting

See submitVote.

As soon as the voting phase starts, anyone with reputation in the team the Motion was created in can vote for a side. Votes are secret (i.e. they're encrypted using your private key), and weighted by reputation. Vote weight is proportional to the voter's reputation in the team in which the vote is occurring.

Voters receive a reward for voting proportional to their reputation in the team in which the vote is occurring. The reward comes from the stake provided by whichever side of the dispute loses. It doesn't matter whether the voter voters for the winning or the losing side, they are rewarded the same either way.

Revealing the votes

See revealVote.

After the voting period is complete, the Reveal phase starts. Votes must be Revealed in order to be counted, and for the voter to receive their voter reward. The Reveal phase ends when either the time runs out, or everyone who has voted reveals their vote, whichever comes first.

Staking penalties

If you staked tokens for the side that eventually lost you will lose some of your stake. The amount lost will be smaller the closer the decision ultimately ended up being.

The structure of a Motion

You can - at any point in the lifecycle inspect the current state of a Motion. Using the getMotion method, the resulting object will have the following properties:

PropertyTypesDescription
events[BigNumberish, BigNumberish, BigNumberish]Timestamps (in seconds) for when the phases for staking, voting and revealing end
rootHashBytesLikeThe root hash of the reputation tree at the time the motion was created
domainIdBigNumberishThe domain/team the Motion is in
skillIdBigNumberishThe skillId associated with the domain
skillRepBigNumberishThe total amount of reputation (among all users) that can vote for this motion
repSubmittedBigNumberishThe amount of reputation that has submitted a vote
paidVoterCompBigNumberishTotal compensation that was paid out to voters who revealed their votes
pastVoterComp[BigNumberish, BigNumberish]Keeps track of previous compensations when escalated
stakes[BigNumberish, BigNumberish]The amounts staked for each of the sides
votes[BigNumberish, BigNumberish]The amount of reputation voted for each side
escalatedbooleanWhether a Motion was escelated to a higher team
finalizedbooleanWhether the motion is finalized (done)
altTargetstringA contract the motion should act on. Can be a Colony or an extension contract
actionBytesLikeThe data for the contract method that will be executed once the motion passes

Constructors

constructor

new VotingReputation(colony, votingReputationContract, deployedVersion)

Parameters

NameType
colonyColony
votingReputationContractSupportedVotingReputationContract
deployedVersion2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Properties

address

address: string


version

version: 2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9


extensionType

Static extensionType: VotingReputation = Extension.VotingReputation


supportedVersions

Static supportedVersions: ({ factory: typeof IVotingReputation__factory = VotingReputationFactory7; version: number = 7 } | { factory: typeof IVotingReputation__factory = VotingReputationFactory8; version: number = 8 })[]

Methods

annotateDecision

annotateDecision(txHash, metadata): MetaTxCreator<SupportedColonyContract, "annotateTransaction", { agent?: string ; metadata?: string ; txHash?: string }, Decision>

Annotate a decision with IPFS metadata to provide extra information

This will annotate a decision with certain metadata (see below). This only really works for transactions that happened within this Colony. This will connect the decision to the (optionally generated) IPFS hash accordingly.

Remarks

If DecisionData is provided directly (as opposed to a CID for a JSON file) this requires an IpfsAdapter that can upload and pin to IPFS. See its documentation for more information. Keep in mind that the annotation itself is a transaction.

Example

// Immediately executing async function
(async function() {

// Create a motion to pay 10 of the native token to some (maybe your own?) address
const [, { transactionHash }] = await colony.ext.motions.createDecision().tx().mined();
// Annotate the decision transaction with important data
// (forced transaction example)
await colony.ext.motions.annotateDecision(
transactionHash,
{
title: 'Should we make the naked-mole-rat our official mascot?',
description: 'I think it is time',
},
).tx().mined();
})();

Parameters

NameTypeDescription
txHashstringTransaction hash of the transaction to annotate (within the Colony)
metadatastring | DecisionDataThe annotation metadata you would like to annotate the transaction with (or an IPFS CID pointing to valid metadata)

Returns

MetaTxCreator<SupportedColonyContract, "annotateTransaction", { agent?: string ; metadata?: string ; txHash?: string }, Decision>

A transaction creator

Event data

PropertyTypeDescription
agentstringThe address that is responsible for triggering this event
txHashstringThe hash of the annotated transaction
metadatastringThe IPFS hash (CID) of the metadata object

Metadata

(can be obtained by calling and awaiting the getMetadata function)

PropertyTypeDescription
titlestringTitle of the decision
descriptionstringLonger description of the decision
motionDomainIdnumberTeam the decision was created in

approveStake

approveStake(amount, teamId?): MetaTxCreator<SupportedColonyContract, "approveStake", { amount?: BigNumber ; approvedBy?: string ; token?: string ; user?: string }, MetadataType>

Approve amount of the "activated" native tokens of a user for staking in a specific team After a token was "activated" (approved and deposited via the native token interface) it can be used for staking motions. To stake a motion, the token amount for staking has to be approved for the domain the motion was created in. See also the example in stakeMotion

Remarks

This method can't be executed as a motion

Parameters

NameTypeDefault valueDescription
amountBigNumberishundefinedAmount of "activated" tokens to be approved for staking
teamIdBigNumberishId.RootDomainTeam that the approved tokens can be used in for staking motions

Returns

MetaTxCreator<SupportedColonyContract, "approveStake", { amount?: BigNumber ; approvedBy?: string ; token?: string ; user?: string }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
tokenstringThe address of the token that is approved for staking
userstringThe address of the VotingReputation contract
approvedBystringThe address of the Colony
amountBigNumberAmount of the token that was approved for staking

createDecision

createDecision(team?): MetaTxCreator<SupportedVotingReputationContract, "createMotion", { creator?: string ; domainId?: BigNumber ; motionId?: BigNumber }, MetadataType>

Annotate a decision with IPFS metadata to provide extra information

Keep in mind that a decision is just a motion without an on-chain action that is being triggered once it finalizes

Remarks

If DecisionData is provided directly (as opposed to a CID for a JSON file) this requires an IpfsAdapter that can upload and pin to IPFS. See its documentation for more information. Keep in mind that the annotation itself is a transaction.

Example

// Immediately executing async function
(async function() {

// Create an empty decision in the Root team
const [, { transactionHash }] = await colony.ext.motions.createDecision().tx().mined();
// Annotate the decision transaction with important data
// (forced transaction example)
await colony.ext.motions.annotateDecision(
transactionHash,
{
title: 'Should we make the naked-mole-rat our official mascot?',
description: 'I think it is time',
},
).tx().mined();
})();

Parameters

NameTypeDefault valueDescription
teamBigNumberishId.RootDomainTeam id to create the decision in

Returns

MetaTxCreator<SupportedVotingReputationContract, "createMotion", { creator?: string ; domainId?: BigNumber ; motionId?: BigNumber }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberId of the decision (motion)
creatorstringAddress of the user who created the decision
domainIdBigNumberTeam the decision was created in

escalateMotion

escalateMotion(motionId, newTeamId): MetaTxCreator<SupportedVotingReputationContract, "escalateMotion", { domainId?: BigNumber ; escalator?: string ; motionId?: BigNumber ; newDomainId?: BigNumber }, MetadataType>

Escalate a motion to a parent team

If all votes for a motion have been revealed but a user is not happy with the outcome, it can be escalated to a parent team (including grandparents, great-grandparents, etc.) as long as the escalation period has not passed yet.

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId of the motion to be escalated
newTeamIdBigNumberishThe id of the team the motion should be escalated to

Returns

MetaTxCreator<SupportedVotingReputationContract, "escalateMotion", { domainId?: BigNumber ; escalator?: string ; motionId?: BigNumber ; newDomainId?: BigNumber }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberID of the motion to be escalated
newTeamIdstringThe ID of the team the motion should be escalated to (has to be a direct parent of the previous team)

finalizeMotion

finalizeMotion(motionId): MetaTxCreator<SupportedVotingReputationContract, "finalizeMotion", { action?: string ; executed?: boolean ; motionId?: BigNumber }, MetadataType>

Finalize a motion, executing its action

Remarks

  • A motion cannot be finalized if:
    • The required Yay or Nay stake amount has not been reached
    • The staking period is not up yet
    • Voting is still in progress
    • The motion was already finalized
  • This method can't be executed as a motion

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId of the motion to be finalized

Returns

MetaTxCreator<SupportedVotingReputationContract, "finalizeMotion", { action?: string ; executed?: boolean ; motionId?: BigNumber }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberID of the motion created
actionstringThe action that was executed in case Yay won
exectuedbooleanWhether the action was executed (Yay won)

getInitializationOptions

getInitializationOptions(): Promise<{ endVoteThreshold: BigNumber ; escalationPhaseDuration: BigNumber ; minimumUserStake: BigNumber ; requiredStake: BigNumber ; revealPhaseDuration: BigNumber ; stakePhaseDuration: BigNumber ; voterReward: BigNumber ; votingPhaseDuration: BigNumber }>

Get the initialized configuration options

Get the configuration options that were set when the extension was initialized. For more information on the individual values see https://docs.colony.io/use/governance/motions-and-disputes/parameters

Returns

Promise<{ endVoteThreshold: BigNumber ; escalationPhaseDuration: BigNumber ; minimumUserStake: BigNumber ; requiredStake: BigNumber ; revealPhaseDuration: BigNumber ; stakePhaseDuration: BigNumber ; voterReward: BigNumber ; votingPhaseDuration: BigNumber }>

The extensions configuration options


getMinStake

getMinStake(motion, vote): Promise<BigNumber>

Get the minimum stake that has to be supplied for a motion and a certain vote (NOT for activation)

Remarks

To get the missing amount for activation, call getRemainingStakes

Parameters

NameTypeDescription
motionMotionA Motion struct object
voteVoteA vote for (Yay) or against (Nay) the motion

Returns

Promise<BigNumber>

The minimum stake amount


getMotion

getMotion(motionId): Promise<Motion>

Get a motion by its id

Remarks

Will throw if motionId does not exist

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId to get the information for

Returns

Promise<Motion>

A Motion object


getMotionState

getMotionState(motionId): Promise<number>

Get the motion state as a number

Will be one of the following:

  • Staking (= 1)
  • Submit (= 2)
  • Reveal (= 3)
  • Closed (= 4)
  • Finalizable (= 5)
  • Finalized (= 6)
  • Failed (= 7)

Example

You can show the state as a string like so

import { MotionState } from '@colony/sdk';

// Immediately executing async function
(async function() {
// Get state of Motion `1`
const state = await colony.ext.motions.getMotionState(1);
const stateStr = MotionState[state]; // `Staking` (or another of the above)
})();

Remarks

Will throw if motionId does not exist

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId to get the state for

Returns

Promise<number>

The motion state


getRemainingStakes

getRemainingStakes(motionId): Promise<{ remainingToFullyNayStaked: BigNumber ; remainingToFullyYayStaked: BigNumber }>

Get the amounts remaining for Yay/Nay sides to be activated

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId of the motion

Returns

Promise<{ remainingToFullyNayStaked: BigNumber ; remainingToFullyYayStaked: BigNumber }>

An object containing the remaining amounts


initialize

initialize(totalStakeFraction, voterRewardFraction, userMinStakeFraction, maxVoteFraction, stakePeriod, submitPeriod, revealPeriod, escalationPeriod): MetaTxCreator<SupportedVotingReputationContract, "initialise", {}, MetadataType>

Before you can use the extension you need to initialize it by calling this function.

Remarks

  • Fractions are in wei to allow for precise adjustments (you can use the w helper method to specify fractions - see example)
  • All periods values are given in seconds

See also this page for a detailed explanation of the parameters.

Example

import { w } from '@colony/sdk';

// Immediately executing async function
(async function() {
// After installing the extension, initialize the extension with the dApp's default values
await colony.ext.motions.initialize(
w`0.01`,
w`0.2`,
w`0.01`,
w`0.7`,
72 * 60 * 60,
72 * 60 * 60,
72 * 60 * 60,
72 * 60 * 60,
).tx().mined();
})();

Parameters

NameTypeDescription
totalStakeFractionBigNumberThe fraction of the domain's reputation we need to stake
voterRewardFractionBigNumberThe fraction of the total stake paid out to voters as rewards
userMinStakeFractionBigNumberThe minimum per-user stake as fraction of total stake
maxVoteFractionBigNumberThe fraction of the domain's reputation which must submit for quick-end
stakePeriodnumberThe length of the staking period in seconds
submitPeriodnumberThe length of the submit period in seconds
revealPeriodnumberThe length of the reveal period in seconds
escalationPeriodnumberThe length of the escalation period in seconds

Returns

MetaTxCreator<SupportedVotingReputationContract, "initialise", {}, MetadataType>

A transaction creator

Event data

No event data attached


revealVote

revealVote(motionId, vote?): MetaTxCreator<SupportedVotingReputationContract, "revealVote", { motionId?: BigNumber ; vote?: BigNumber ; voter?: string }, MetadataType>

Reveal a vote for a motion

Remarks

  • In order for a vote to count it has to be revealed within the reveal period. Only then rewards can be paid out to the voter.
  • This method can't be executed as a motion

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId of the motion to be finalized
vote?VoteThe vote that was cast. If not provided Colony SDK will try to find out which side was voted on (not recommended)

Returns

MetaTxCreator<SupportedVotingReputationContract, "revealVote", { motionId?: BigNumber ; vote?: BigNumber ; voter?: string }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberID of the motion to be revealed
voterstringThe address of the user who voted
voteBigNumberThe vote that was cast (0 = Nay, 1 = Yay)

stakeMotion

stakeMotion(motionId, vote, amount): MetaTxCreator<SupportedVotingReputationContract, "stakeMotion", { amount?: BigNumber ; eventIndex?: BigNumber ; motionId?: BigNumber ; staker?: string ; vote?: BigNumber }, MetadataType>

Stake amount to support a motion with your vote

Remarks

  • In order to stake a motion the amount to stake (or any amount higher than that) needs to be "activated" and approved for staking in the motion's team first. See below for a full example. Usually you would have more tokens "activated" or even approved for a domain than you would stake, to make this process more seamless
  • This method can't be executed as a motion

Example

import { Vote, w } from '@colony/sdk';

// Immediately executing async function
(async function() {
const token = colony.getToken();
// Approve 200 tokens to be "activated"
await token.approve(w`200`);
// Deposit all of approved the tokens
await token.deposit(w`200`);
// Approve 150 tokens for staking in the root domain (can only be forced)
await colony.ext.motions.approveStake(w`150`).tx().mined();
// Stake 100 tokens for motion with id 3
await colony.ext.motions.stakeMotion(3, Vote.Yay, w`100`);
})();

Parameters

NameTypeDescription
motionIdBigNumberish-
voteVote-
amountBigNumberishAmount of the token to be approved

Returns

MetaTxCreator<SupportedVotingReputationContract, "stakeMotion", { amount?: BigNumber ; eventIndex?: BigNumber ; motionId?: BigNumber ; staker?: string ; vote?: BigNumber }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberID of the motion to stake for
stakerstringThe address that staked the tokens
voteVoteThe vote that was staked for (Yay or Nay). See Vote
amountBigNumberThe amount that was staked for that vote
eventIndexBigNumberIf the stake triggered a motion event, this will contain its index

submitVote

submitVote(motionId, vote): MetaTxCreator<SupportedVotingReputationContract, "submitVote", { motionId?: BigNumber ; voter?: string }, MetadataType>

Submit a vote for a motion

Remarks

This method can't be executed as a motion

Parameters

NameTypeDescription
motionIdBigNumberishThe motionId of the motion to be finalized
voteVoteA vote for (Yay) or against (Nay) the motion

Returns

MetaTxCreator<SupportedVotingReputationContract, "submitVote", { motionId?: BigNumber ; voter?: string }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
motionIdBigNumberID of the motion to submit a vote for
voterstringThe address of the user who voted

upgrade

upgrade(toVersion?): ColonyTxCreator<SupportedColonyContract, "upgradeExtension", { colony?: string ; extensionId?: string ; version?: BigNumber }, MetadataType>

Upgrade this extension to the next or a custom version

This method upgrades this extension to a specified version or, if no version is provided to the next higher version.

Remarks

  • Only users with Root role are allowed to upgrade an extension (or another extension with appropriate permissions)
  • Downgrading of extensions is not possible

Parameters

NameTypeDescription
toVersion?BigNumberishSpecify a custom version to upgrade the extension to

Returns

ColonyTxCreator<SupportedColonyContract, "upgradeExtension", { colony?: string ; extensionId?: string ; version?: BigNumber }, MetadataType>

A transaction creator

Event data

PropertyTypeDescription
extensionIdstringExtension id (name of the extension) that was upgraded
oldVersionBigNumberVersion of the extension before the upgrade
newVersionBigNumberVersion of the extension after the upgrade

connect

Static connect(colony): Promise<VotingReputation>

Parameters

NameType
colonyColony

Returns

Promise<VotingReputation>


getLatestSupportedVersion

Static getLatestSupportedVersion(): 2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9

Returns

2 | 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9