Smart Contracts
The eckoDAO is a bespoke system comprised of a pair of smart contracts that interact with each other to accomplish different tasks related to governance. These are referred to as
'The Librarian' and 'The Lexicon'.
The primary smart contract that handles Proposals is called the Librarian. This contract is designed to take care of proposals creation and management as well as keep track of votes for each specific proposal and account. The main features of the DAO contract are the following:
- Create proposal and insert into
proposals-table
- Vote proposal by a specific account and insert into
votes-table
- Give information about proposals and actions taken by an account
The contract is governed by a keyset, "kaddex-ns-admin"
The contract operations are allowed to a keyset, "kaddex-ns-ops"
The contract contains 2 tables with following schema:
- proposals-table:
id
title
description
account
tot-approved
tot-refused
start-date
end-date
creation-date
- votes-table:
proposal-id
account
vp
action
- Creates proposal with the parameters:
title
description
owner-account
start-date
end-date
- Inserts the proposal into
proposals-table
(create-proposal "New proposal" "this is a proposal" "k:govaddress" (time "2022-03-10T23:59:00Z") (time "2022-03-20T23:59:00Z"))
- Takes three parameters:
proposal-id
account
action
- Inserts into
votes-table
the action (approved or refused) taken from an account on a specific proposal
(vote-proposal-helper "proposal-id" "k:bobaddress" "approved")
- Takes
proposal-id
andaccount
as parameters - calls vote-proposal-helper to vote for a proposal as approved
(approved-vote "proposal-id" "k:bobaddress")
- Takes
proposal-id
andaccount
as parameters - calls vote-proposal-helper to vote for a proposal as refused
(refused-vote "proposal-id" "k:bobaddress")
- This function needs an
account
as a required argument and retuns the voting-power, multiplier and staked-amount of that specific account - These info are received from the aggregator contract
(get-account-data "k:bobaddress")
- Get proposal info giving a specific
proposal-id
as argument
(read-proposal "proposal-id")
- Get all proposals info
(read-all-proposals)
- This function takes an
account
and aproposal-id
as arguments. - Checks if an account has already voted a specific proposal.
(check-account-voted "k:bobaddress" "proposal-id")
- Takes
account
as paramenter - Get vote info for each proposal that
account
has voted in thevotes-table
(read-account-votes "k:bobaddress")
- Takes
account
andproposal-id
as paramenter - Get vote info of
account
on specificproposal
(read-account-votes "prposal-id" "k:bobaddress")
This contract is designed to manage each account's Voting Power. Voting Power (VP) is essential for a user that wants to vote a proposal in the DAO. Every time an account vote a proposal, the DAO contract make a call to the Aggregator contract in order to evaluate the VP of that specific account.
The contract is governed by a keyset, "kaddex-ns-admin"
The contract operations are allowed to a keyset, "kaddex-ns-ops"
The contract contains 2 tables with following schema:
- staking-aggregator-table:
account
start-time
staked-amount
shift
- privilege-table:
guards
action
- Takes a guard and an action as arguments.
- This function grants a guard privilege to perform a specific action. If a guard does not have permission, the action won't be executed.
(grant-privilege (read-keyset 'guardaddress ) "aggregate-stake")
- Takes a list of objects as argument.
- Vaulting data are inserted into
staking-aggregator-table
through the use of this function. For a single user, the amount of kdx-locked coming from the vaulting program will be added up with the kdx-amount staked in order to create thePosition
of that specific user.
(insert-lockup-batch [{"account":"k:bobaddress", "amount": 100.0}])
- Takes two parameters:
requesting-account
amount
- It's called every time a new action of staking is made by an account. It is up to this function to verify whether an account is entering staking for the first time or not, if not, it checks if there is some amount already staked. Based on this information one of the three functions create-new-stake-row / update-account-entering-staking-again / update-old-stake-row is called to insert staking info into the
staking-aggregator-table
.
(aggregate-stake "k:bobaddress" 100.0)
- Takes two parameters:
requesting-account
unstaked-amount
- It's called every time a new action of unstaking is made by an account. It is up to this function to call the update-when-unstaking function in order to update the
staking-aggregator-table
with the unstaking info.
(aggregate-unstake "k:bobaddress" 100.0)
- Receiving an account as argument, it returns the VP of that specific account.
(get-voting-power "k:bobaddress")
- Takes an account as parameter.
- This function returns an object containing info about the inserted account. In particular the outcome will be the Position, VP and Multiplier of the account.
(get-account-data "k:bobaddress")
- Get all staking info
(read-all-staking)
The formula to calculate the VP is:
where:
- P: is the account Position, KDX amount (
staked-amount
+ kdx-locked in Vaulting program) - M: is the multiplier
The Voting Power Multiplier is a time-dependent function of your KDX staking amount. After the initial action of staking, in 60 days the Multiplier value goes up to 1 and can reach 2.5 over the course of 4 years. Every time a new action of staking is made, the Multiplier is recalculated based on the prervious amount staked and the new inserted amount. In order to performe this kind of calculation the
shift
value is used and stored. The shift value shifts the curve along the x axis to accommodate adding stakes at different times.Multiplier formula:
M = s • ([ X - shift ] ^ z) + c
where:
- X: is the time passed since the staking started
- s, z, c: are constants used to model the multiplier-curve efficiently
user1:
- entering staking at T(0) with 100 KDX
- after 60 days --> Multiplier = 1 and VP = 10 = Math.sqrt( 100 • 1 )
user2:
- entering staking at T(0) with 10 KDX
- adding 90 KDX after 30 days
- after 60 days --> Multiplier = 0.8158 and VP = 9.03 = Math.sqrt( 100 • 0.8158 )
As it is possible to notice, after a period of 60 days, user1 will have acquired more VP compared to user2. This is due to the fact that user2 have made a new action of staking during the 60 days period, this action leads to an adjustment of the
shift
value, therefore to a lower Multiplier and VP.