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 VotingReputation.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 ColonyTxCreator.motion or ColonyTxCreator.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 VotingReputation.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 VotingReputation.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 VotingReputation.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 VotingReputation.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 VotingReputation.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​

new VotingReputation()​

new VotingReputation(colony, votingReputationContract, deployedVersion): VotingReputation

Parameters​

colony​

Colony

votingReputationContract​

SupportedVotingReputationContract

deployedVersion​

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13

Returns​

VotingReputation

Properties​

address​

address: string


version​

version: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13


extensionType​

static extensionType: VotingReputation = Extension.VotingReputation


supportedVersions​

static supportedVersions: ({ factory: typeof IVotingReputation__factory; version: number; } | { factory: typeof IVotingReputation__factory; version: number; } | { factory: typeof IVotingReputation__factory; version: number; })[]

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.

Parameters​

txHash​

string

Transaction hash of the transaction to annotate (within the Colony)

metadata​

The annotation metadata you would like to annotate the transaction with (or an IPFS CID pointing to valid metadata)

string | DecisionData

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

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();
})();

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 VotingReputation.stakeMotion

Parameters​

amount​

BigNumberish

Amount of "activated" tokens to be approved for staking

teamId​

BigNumberish = Id.RootDomain

Team 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

Remarks​

This method can't be executed as a motion


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

Parameters​

team​

BigNumberish = Id.RootDomain

Team 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

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();
})();

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​

motionId​

BigNumberish

The motionId of the motion to be escalated

newTeamId​

BigNumberish

The 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

Parameters​

motionId​

BigNumberish

The 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)

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

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/learn/governance/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)

Parameters​

motion​

Motion

A Motion struct object

vote​

Vote

A vote for (Yay) or against (Nay) the motion

Returns​

Promise\<BigNumber>

The minimum stake amount

Remarks​

To get the missing amount for activation, call getRemainingStakes


getMotion()​

getMotion(motionId): Promise\<Motion>

Get a motion by its id

Parameters​

motionId​

BigNumberish

The motionId to get the information for

Returns​

Promise\<Motion>

A Motion object

Remarks​

Will throw if motionId does not exist


getMotionResult()​

getMotionResult(motionId): Promise\<null | Vote>

Get the result of a motion (if it is finalizeable or finalized)

Parameters​

motionId​

BigNumberish

The motionId to get the result for

Returns​

Promise\<null | Vote>

The result of the motion (0 = Nay, 1 = Yay)

Remarks​

Will return null if the motion is not finalizeable yet


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)

Parameters​

motionId​

BigNumberish

The motionId to get the state for

Returns​

Promise\<number>

The motion state

Example​

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


getRemainingStakes()​

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

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

Parameters​

motionId​

BigNumberish

The 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.

Parameters​

totalStakeFraction​

BigNumber

The fraction of the domain's reputation we need to stake

voterRewardFraction​

BigNumber

The fraction of the total stake paid out to voters as rewards

userMinStakeFraction​

BigNumber

The minimum per-user stake as fraction of total stake

maxVoteFraction​

BigNumber

The fraction of the domain's reputation which must submit for quick-end

stakePeriod​

number

The length of the staking period in seconds

submitPeriod​

number

The length of the submit period in seconds

revealPeriod​

number

The length of the reveal period in seconds

escalationPeriod​

number

The length of the escalation period in seconds

Returns​

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

A transaction creator

Event data​

No event data attached

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();
})();

revealVote()​

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

Reveal a vote for a motion

Parameters​

motionId​

BigNumberish

The motionId of the motion to be finalized

vote?​

Vote

The 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)

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

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

Parameters​

motionId​

BigNumberish

vote​

Vote

amount​

BigNumberish

Amount 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

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`);
})();

submitVote()​

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

Submit a vote for a motion

Parameters​

motionId​

BigNumberish

The motionId of the motion to be finalized

vote​

Vote

A 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

Remarks​

This method can't be executed as a motion


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.

Parameters​

toVersion?​

BigNumberish

Specify 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

Remarks​

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

connect()​

static connect(colony): Promise\<VotingReputation>

Parameters​

colony​

Colony

Returns​

Promise\<VotingReputation>


getLatestSupportedVersion()​

static getLatestSupportedVersion(): 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13

Returns​

1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13