The kyberDao contract primarily provides the following functionalities:
- Creation and cancellation of campaigns by authorized personnel (namely, the
daoOperator
) - Voting for campaigns
For stakers and pool operators, the actions you will be interested in are:
The voting formula used for deciding the winning options of a campaign may also be of interest.
These actions can only be carried out by the daoOperator
.
There are currently 3 different types of campaigns:
GENERAL
: A generic campaign.NETWORK_FEE
: The fee amount (in basis points) to be charged for every trade.FEE_HANDLER_BRR
: Proportion of fees to be burnt, given to stakers as rewards, and given to reserves as rebates for liquidity contribution.
Note that there can only be a maximum of 1 campaign per epoch for the NETWORK_FEE
and FEE_HANDLER_RR
campaign types.
The formula was designed to be simple enough such that it can be implemented on-chain, and is gas efficient for calculations. Hence, the "1 token 1 vote" idea is used for its simplicity. A quorum is also defined, in order for a winning option to be considered valid.
The quorum needed is linearly inversely proportional to the percentage of votes received for that campaign. In other words, fewer votes received, stricter quorum.
In the event that there is more than 1 winning option (ie. more than 1 option sharing the same no. of votes), the campaign is considered to not have a winner.
A line can be expressed as Y = tX + C
, where t
is the gradient, and C
shifts the line vertically up/down.
winningOption
: Campaign option that received the most votestotalVotes
: Total amount of votes received for a campaignvotedPercentage
: Percentage of votes (out of the total KNC supply at the time of the campaign)minThreshold
: Minimum percentage (out of all campaign votes) needed for the winning option to be valid
- We first find
winningOption
with a simple iteration through the votes received by each option. - Calculate
votedPercentage
:totalVotes
/ total KNC supply at time of campaign minThreshold
:-t * votedPercentage + C
.t
andC
were determined bydaoOperator
upon campaign initialisation (to allow for flexibility). Rearranging this, we getminThreshold = C - t * votedPercentage
- If enough people have voted such that
t * votedPercentage > C
(ie.minThreshold < 0
), then the quorum condition has been met, and we can considerwinningOption
to be valid. - Otherwise, we have to check that
winningOption >= minThreshold
before considering it to be a valid winning option.
MAX_EPOCH_CAMPAIGNS
: Maximum number of campaigns that can be created in an epoch bydaoOperator
MAX_CAMPAIGN_OPTIONS
: Maximum number of options that a campaign can haveminCampaignDurationInSeconds
: Minimum duration for a campaignkncToken
: The KNC token contractstaking
: The staking contractnumberCampaigns
: Number of campaigns in total, used to generate a unique ID for each campaign
Obtain the current epoch number of the Dao contract
function getCurrentEpochNumber
() public view returns (uint)
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let currentEpochNum = await kyberDao.getCurrentEpochNumber().call();
While this section is specific to the NETWORK_FEE
campaign type, the other sections below are of relevance.
networkFeeCampaigns[epoch] = uint
NETWORK_FEE
campaign ID number for a given epoch. Note that there can only be a maximum of 1 NETWORK_FEE
campaign per epoch.
Get the NETWORK_FEE
campaign ID number for epoch 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let epochNum = new BN(5);
let result = await kyberDao.methods.networkFeeCampaigns(epochNum).call();
Gets the network fee (in basis points) charged for trades, and the timestamp for which it expires.
function getLatestNetworkFeeData() public view returns(uint feeInBps, uint expiryTimestamp)
Returns:
Parameter | Type | Description |
---|---|---|
feeInBps |
uint |
Network fee (in basis points) to be charged for trades |
expiryTimestamp |
uint |
Time which the network fee becomes invalid |
Notes:
- Unlike the
getLatestNetworkFeeDataWithCache()
function below, this is aview
function, and does not cache the data
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let result = await kyberDao.methods.getLatestNetworkFeeData().call();
In addition to reading the latest network fee data, it concludes the network fee campaign if necessary, thereby caching the data as well.
function getLatestNetworkFeeDataWithCache`() public returns(uint feeInBps, uint expiryTimestamp)
Returns:
Parameter | Type | Description |
---|---|---|
feeInBps |
uint |
Network fee (in basis points) to be charged for trades |
expiryTimestamp |
uint |
Time which the network fee becomes invalid |
Notes:
- Unlike the
getLatestNetworkFeeData()
function above, the network fee data is cached as well.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let txData = kyberDao.methods.getLatestNetworkFeeDataWithCache().encodeABI();
let txReceipt = await web3.eth.sendTransaction({
from: USER_WALLET_ADDRESS, // obtained from web3 interface
to: kyberDao.address,
data: txData
});
While this section is specific to the FEE_HANDLER_BRR
campaign type, the other sections below are of relevance.
brrCampaigns[epoch] = uint
FEE_HANDLER_BRR
campaign ID number for a given epoch. Note that there can only be a maximum of 1 FEE_HANDLER_BRR
campaign per epoch.
Get the FEE_HANDLER_BRR
campaign ID number for epoch 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let epochNum = new BN(5);
let result = await kyberDao.methods.brrCampaigns(epochNum).call();
Gets the latest BRR distribution for the network fee, and the timestamp for which it expires.
function getLatestBRRData() public returns (uint burnInBps, uint rewardInBps, uint rebateInBps, uint epoch, uint expiryTimestamp)
Returns:
Parameter | Type | Description |
---|---|---|
burnInBps |
uint |
Ratio (in basis points) of fees collected for burning KNC |
rewardInBps |
uint |
Ratio (in basis points) of fees collected for staker rewards |
rebateInBps |
uint |
Ratio (in basis points) of fees collected for reserve rebates |
epoch |
uint |
Current epoch of Staking and Dao contracts |
expiryTimestamp |
uint |
Timestamp for which BRR becomes invalid |
Notes:
epoch
has the same value as callinggetCurrentEpochNumber()
- Unlike the
getLatestBRRDataWithCache()
function below, this is aview
function, and does not cache the data
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let result = await kyberDao.methods.getLatestBRRData().call();
In addition to reading the latest BRR data, it also concludes a BRR campaign if necessary, thereby caching the latest BRR data as well.
function getLatestBRRDataWithCache() public returns (uint burnInBps, uint rewardInBps, uint rebateInBps, uint epoch, uint expiryTimestamp)
Returns:
Parameter | Type | Description |
---|---|---|
burnInBps |
uint |
Ratio (in basis points) of fees collected for burning KNC |
rewardInBps |
uint |
Ratio (in basis points) of fees collected for staker rewards |
rebateInBps |
uint |
Ratio (in basis points) of fees collected for reserve rebates |
epoch |
uint |
Current epoch of Staking and Dao contracts |
expiryTimestamp |
uint |
Timestamp for which BRR becomes invalid |
Notes:
epoch
has the same value as callinggetCurrentEpochNumber()
- Unlike the
getLatestBRRData()
function above, this function caches the BRR data too.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let txData = kyberDao.methods.getLatestBRRDataWithCache().encodeABI();
let txReceipt = await web3.eth.sendTransaction({
from: USER_WALLET_ADDRESS, // obtained from web3 interface
to: kyberDao.address,
data: txData
});
This section details all the APIs related to fetching information about campaigns (including results).
Get a list of all existing campaigns of an epoch.
function getListCampaignIDs
(uint256 epoch) external view returns (uint256[] memory campaignIDs)
Inputs
Parameter | Type | Description |
---|---|---|
epoch |
uint256 | epoch number |
Returns:
List of campaignIDs
for given epoch
.
Get the list of campaign IDs for current epoch.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let currentEpoch = await kyberDao.methods.getCurrentEpochNumber().call();
let result = await kyberDao.methods.campaignIDs(currentEpoch).call();
Get information about a campaign.
function getCampaignDetails
(uint256 campaignID) external view returns (
CampaignType campaignType, uint256 startTimestamp, uint256 endTimestamp,
uint256 totalKNCSupply, uint256 minPercentageInPrecision, uint256 cInPrecision,
uint256 tInPrecision, bytes memory link, uint256[] memory options)
Inputs
Parameter | Type | Description |
---|---|---|
campaignID |
uint256 | campaign ID |
Returns:
Parameter | Type | Description |
---|---|---|
campaignType |
CampaignType | One of the 3 campaign types |
startTimestamp |
uint256 | Starting time of the campaign |
endTimestamp |
uint256 | Ending time of the campaign |
totalKNCSupply |
uint256 | Total KNC supply at the time of campaign creation |
minPercentageInPrecision |
uint256 | Minimum percentage in precision for formula to conclude campaign |
cInPrecision |
uint256 | c value (in precision) for formula to conclude campaign |
tInPrecision |
uint256 | t value (in precision) for formula to conclude campaign |
link |
bytes | Additional information about this campaign. Typically a URL |
options |
uint256[] | List of vote options for the campaign |
Note:
- More information about the formula and its parameters
minPercentageInPrecision
,cInPrecision
andtInPrecision
can be found here
Get the details of campaign number 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let campaignNum = new BN(5);
let result = await kyberDao.methods.getCampaignDetails(campaignNum).call();
Get the vote counts for each option of a campaign, and the total vote count.
function getCampaignVoteCountData
(uint256 campaignID) external view returns (uint256[] memory voteCounts, uint256 totalVoteCount)
Inputs
Parameter | Type | Description |
---|---|---|
campaignID |
uint256 | campaign ID |
Returns:
Parameter | Type | Description |
---|---|---|
voteCounts |
uint256[] | List of vote counts per option |
totalVoteCount |
uint256 | Total vote count for the campaign |
Get the campaign vote count data of campaign number 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let campaignNum = new BN(5);
let result = await kyberDao.methods.getCampaignVoteCountData(campaignNum).call();
Get the winning option and value of a campaign
function getCampaignWinningOptionAndValue(uint256 campaignID) public view returns (uint256 optionID, uint256 value)
Inputs
Parameter | Type | Description |
---|---|---|
campaignID |
uint256 | campaign ID |
Returns:
Parameter | Type | Description |
---|---|---|
optionID |
uint256 | Winning option ID |
value |
uint256 | Winning option value |
Note:
Values (0,0)
will be returned under the following circumstances:
- Campaign does not exist
- Campaign is still ongoing
- Campaign has no winning option based on the formula (more than 1 winning option, insufficient votes, etc.)
Get the winning option and value of campaign number 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let campaignNum = new BN(5);
let result = await kyberDao.methods.getCampaignWinningOptionAndValue(campaignNum).call();
This section details all the APIs related to voting for a campaign, and staker-centric data related to campaign options and results.
numberVotes[stakerAddress][epoch] = uint
To determine the number of campaigns that a staker has voted for at a given epoch number.
Get number of campaigns staker has voted for in epoch 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let staker = "0x12340000000000000000000000000000deadbeef" // staker's address
let epochNum = new BN(5);
let result = await kyberDao.methods.numberVotes(staker, epochNum).call();
stakerVotedOption[stakerAddress][campID] = uint
To obtain the option number a staker voted on, for a campaign.
See which option staker has voted on, for campaign ID 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let staker = "0x12340000000000000000000000000000deadbeef" // staker's address
let campaignID = new BN(5);
let result = await kyberDao.methods.stakerVotedOption(staker, campaignID).call();
Vote for a campaign.
function vote(uint campaignID, uint256 option) public
Inputs
Parameter | Type | Description |
---|---|---|
campaignID |
uint |
Campaign ID voting on |
option |
uint |
Option number |
Vote for option 3
for campaign ID 5
.
// DISCLAIMER: Code snippets in this guide are just examples and you
// should always do your own testing. If you have questions, visit our
// https://t.me/KyberDeveloper
let campaignID = new BN(5);
let option = new BN(3);
let txData = kyberDao.methods.vote(campaignID, option).encodeABI();
let txReceipt = await web3.eth.sendTransaction({
from: VOTING_WALLET_ADDRESS,
to: kyberDao.address,
data: txData
});