Giter VIP home page Giter VIP logo

dao-contracts's Introduction

MVPR DAO for Casper

Reusable smart contracts for building DAOs on top of Casper.

Repository contains following modules:

  • dao provides smart contracts implementation,
  • dao-macros makes writing code easier,

General Documentation

Technical documentation

To generate rustdoc execute the following:

just rebuild-docs

Live version: https://make-software.github.io/dao-contracts.

Quickstart

Prerequisites

  • Rust toolchain installed (see rustup.rs),
  • cargo odra installed cargo install --version 0.0.10 --force --locked cargo-odra
  • wasmstrip tool installed (see wabt).
  • wasm-opt tool installed (see binaryen).
  • just tool installed (see just).
  • wabt installed (see wabt).

To prepare your environment execute:

just prepare

Build contracts

To build WASM files execute:

just build-dao-contracts

Contracts will be located in the wasm/ folder.

Run tests

To run integration tests execute:

just test

dao-contracts's People

Contributors

kpob avatar kubaplas avatar mrkara avatar mssteuer avatar omahs avatar piotrwitek avatar volodymyr-kuchinskyi avatar zhmakas avatar zie1ony avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dao-contracts's Issues

KYC Contract Skeleton

KYC Contract skeleton

To fully implement contracts that use voting, we need a KYC Contract. But before its specification is cooked, we can use this skeleton with basic implementation for testing other contracts.

entrypoints

has_kyc

This method will return if the user owning a given address is eligible - has passed the KYC process.

fn has_kyc(&self, address: Address)

In the Skeleton, this method will always return true.

Admin Contract

Admin

This contract allows voting for changes in whitelists and change of the owner of the contracts that Admin Contract owns, that is:

  • VariableRepo
  • KYC
  • ReputationToken

The voting mechanism is the same as used in RepoVoter Contract #28 with the only difference being different actions are being executed.

Variables

votings

Stores votings, their configuration and their votes.

votings: TBD

other

variable_repo: Address,
reputation_token: Address,
kyc_contract: Address,
Contracts: Enum(variable_repo, reputation_token, kyc_contract),
Actions: Enum(add_to_whitelist, remove_from_whitelist, change_owner)

Entry points

init

Initializes the contract with addresses of ReputationToken, VariableRepo and KYC contracts

fn init(&mut self, variable_repo: Address, reputation_token: Address, kyc_contract: Address);

create_voting

Creates a new voting. We pass as arguments which contract we want act on, an action and an address which will be a parameter for the action.

fn create_voting(
&mut self,
subject: Contracts,
action: Actions,
argument: Address,
stake: U256
)

Successful call emits an Event:

AdminVotingCreated(
  subject: Contracts,
  action: Actions,
  argument: Address,
  stake: U256,
  creator: Address,
  informal_voting_id: U256,
  informal_voting_finish_time: U256,
  informal_voting_quorum: U32,
  formal_voting_id: U256,
  formal_voting_finish_time: U256,
  formal_voting_quorum: U32
)

vote

Is the same as in RepoVoter Contract #28

finish_voting

Is the same as in RepoVoter Contract #28, with different actions being called in a subject contract.

All variables and Gherkin tests.

  • Change variables names
    • GovenanceVariable -> BidEscrowVariable
    • Variable -> Variable
  • In BidEscrow use BidEscrow* variables and in the rest of votings use standard.
  • Add is_bidescrow in VotingConfiguration.rs
  • InformalQuorumRatio
  • FormalQuorumRatio
  • InformalVotingTime
  • FormalVotingTime
  • Use DefaultReputationSlash and slash when finish_voting->Formal->Internal.
  • VotingStartAfterJobWorkerSubmisson - add blocktime check in BidEscrow::vote

Update docs.

  1. Explain how to get back to above zero reputation.
  2. Changing word increment to increase.

Update JS generic client.

Contract schemas files changed. JS generic client needs to be adjusted to use new format.
Changes:

  • It is JSON format now (YAML before).
  • Each entry point contains a list of events.
  • Type definitions uses correct CLTypes, that should be possible to parse using casper-js-sdk.

Make sure tests are passing.

BidEscrow Tracking Issue.

List of features requested by the DEVxDAO members, that when implemented, should produce a bid escrow process with expected features.

  • Reputation Token

    • Move REP distribution logic into the Reputation Contract.
    • Allow CSPR distribution to all VAs, and take all REP under consideration.
    • Rewrite tests.
    • Burn REP dust.
    • Voters to use new token.
    • Bring back staking.
  • Bid Escrow

    • Update BidEscrow to stake CSPR for an external worker.
    • Implement bidding in BidEscrow.
      • Bidding process.
      • Bidding stakes management.
      • Rewrite job acceptation process.
      • Rewrite job cancelation process.
    • Remove minimum stake from Bidding
    • Automatic REP slash in case of not completing the job.
    • Implement the configurable governance payment (tax).
    • Internal worker participate in voting.
  • Onbarding Voter should allow to stake CSPR and post proof by external worker.

Full Bid Escrow Process

  • Bidding process

    • Job poster posts a job
      • Job poster sends CSPR?
    • Workers posts bids.
    • Check if condions are met
    • Fail the process if needed.
    • Pick a bid.
      • Accept CSPR for nonVA worker.
    • New job is created.
      • Stakes are returned to non-picked workers.
      • Mint new REP (based on CSPR*ratio amount) to nonVA worker and use it as a stake on the job.
      • Add workers CSPR to the job poster reward.
  • Job handling

    • Waiting for worker or job poster to submit a result. Job poster can submit a result if time has passed.
    • If voiting failed:
      • For VA worker - slash REP
      • For nonVA worker
        • Loses CSPR stake.
        • Redistribute staked worker's CSPR to all VAs or just those who particiated in voting.
      • For job poster - gets her CSPR back.
      • Redistribute REP to voting winners.
    • If no quorum (formal and informal) or informal voiting failes
      • Everything is returned.
      • For nonVA worker - REP tokens are burned.
    • If voting succeded:
      • Mint new REP (job_price * conversion_rate) to additional pool.

      • For nonVA that doesn't want to become VA:

        • Move prevously minted REP for the worker to additional poll.
        • Additional pool is redistributed among VA voter.
        • CSPR * governance_payment_ratio is transfered to multisig wallet.
        • rest of CSPR * policing_rate is transfered to all VAs.
        • rest of the rest is given to worker.
      • If nonVA worker wants to become VA:

        • Mint VA Token for the worker.
        • Rest is like the VA worker flow.
      • If VA worker

        • Reputation is redistributed to winners.
        • CSPR * governance_payment_ratio is transfered to multisig wallet.
        • Rest of CSPR is transfered to all VAs.

`final` version tracking issue.

Interface stabilization phase:

  • Refactor voting interface.
  • Complete bid escrow algorith.
  • Special Onboarding.
  • #121
  • Slashing in Voters.
  • Slashing in BidEscrow.
  • DOS Fee based on Dolars.
  • Voters events.
  • BidEscrow events.
  • Move token ids increments into token contracts.
  • Centralize voting id generations.
  • Grace Period

Refactor phase:

  • Refactor DAOWorld.
  • Refactor Bid Escrow and Governance Voting.
  • Fix number conversions.
  • Tests for all contracts in Gherkin.
  • Refactor Reputation.
  • Bid Escrow Bidding tests.
  • Code documentation.

Refactor plan:

Voting rewrite plan:

  • Put validation into separate structures.
  • Rename governance_voting to voting_engine and voting to voting_state_machine.
  • Move stuff from bidescrow down to voting_engine.
  • Remove from bidescrow usages of to_real_voting_id and operate on tuple (voting_id, voting_type).
  • Move bidding and job_offers logic into separate module and use in bidescrow.
  • Unify Informal and Formal under one VotingStateMachine.

E2E test.

Use Code Review DAO as the scenario for setting up the whole DAO:

  1. Setup Reputation token,
  2. Setup Variable repo,
  3. Setup Admin.
  4. Setup Repo Voter
  5. Run a few scenarios of votings.

Add staking to the Reputation contract.

Staking

Staking is used as a way of marking that tokens are used for voting in another contracts.

It should be implemented as:

struct TokenWithStaking {
    stakes: Mapping<Address, U256>,
    token: Token
}

New entry points

Stake

Signature:

fn stake(&mut self, address: Address, amount: U256);

It should increase the stake in the stakes mapping by the amount.

If stakes.get(address) + amount > balance_of(address) throw an error Error::StakingTooMuch.

Only whitelisted addresses can execute stake entry point.

Unstake

Signature:

fn unstake(&mut self, address: Address, amount: U256);

It should decrease the stake in the stakes mapping by the amount.

If stakes.get(address) < amount throw an error Error::UnstakingTooMuch.

Only whitelisted addresses can execute unstake entry point.

Existing entry points

Burn

It should not be possible to burn staked tokens. They need to be unstaked first.

Transfer From

It should not be possible to transfer staked tokens. They need to be unstaked first.

Update types.

Change DocumentHash from U256 to u32.
Change VotingId from U256 to u32.

RepoVoter Contract

RepoVoter

This contract allows voting for changes in the configuration stored in the VariableRepo contract.

Variables

votings

Stores votings, their configuration and their votes.

votings: TBD

other

variable_repo: Address,
reputation_token: Address

Entry points

init

Initializes the contract with addresses of ReputationToken and VariableRepo.

fn init(&mut self, variable_repo: Address, reputation_token: Address);

It emits an Event after a successful call:

RepoVoterCreated(
    repo_voter: Address,
    variable_repo: Address,
    reputation_token: Address
)

Create voting

Creates a new voting.
Preconditions:

  • the caller is eligible (it has an available Reputation > stake)
  • the stake is equal or greater than minimum_governance_reputation value from the Variable Repo
fn create_voting(
&mut self,
variable_repo_to_edit: Address, // for the flexibility, we allow voting on other repos in the future
key: String, // which variable we update
value: Bytes, // value of the variable
activation_time: Option<U256> // when to activate
stake: U256 // initial stake for the vote
);

The created voting should have the configuration based on the Variable Repo configuration, stored in the contract's variable_repo address. The amount of reputation defined in stake is staked by the voter in the first vote in favor. After a successful voting creation, an Event should be emitted containing the votings configuration:

RepoVotingCreated(
  variable_repo_to_edit: Address,
  key: String,
  value: Bytes,
  activation_time: Option<U256>
  stake: U256,
  creator: Address,
  informal_voting_id: U256,
  informal_voting_finish_time: U256,  // calculated based on `informal_voting_time` + current block time
  informal_voting_quorum: U32, // copy of the Variable Repo's value
  formal_voting_id: U256,
  formal_voting_finish_time: U256,  // calculated based on `formal_voting_time` + current block time
  formal_voting_quorum: U32 // copy of the Variable Repo's value
)

vote

Casts a vote. The vote (choice with its stake and voter address) is added to the votings list.
Preconditions:

  • the voter is eligible (it has an available Reputation > stake)
  • the stake is equal or greater than the minimum_governance_reputation value from the Variable Repo
  • the voting is active - _finish_time has not passed for the respective voting
  • if the vote is cast for a formal vote, additionally the result of the informal voting needs to be in favor
fn vote(
  &mut self,
  voting_id: U256,
  choice: bool,
  stake: U256,
);

It emits an Event after a successful call:

VoteCast(
  voter: Address,
  voting_id: U256,
  choice: bool,
  stake: U256
)

finish_voting

Calculates and publishes the result of the voting. Depending on the type of voting, it performs different actions.

fn finish_voting(
&mut self,
voting_id: U256
)

quorum

Quorum is reached if the number of voters is greater or equal to quorum ratio multiplied by total number of eligible voters.
For example:

  • total eligible voters: 10
  • quorum ratio: 0.5
  • voters: 5
    In the example above the quorum is reached as 10*0.5 >= 5.

voting result calculation

If the quorum was reached, the result of the voting is calculated by comparing the sum of the stakes in favor and against.
In the case of a tie, the result is in favor.

informal voting

Preconditions:

  • informal_voting_finish_time is less or equal than the current block time

If the quorum defined in informal_voting_quorum was not reached or the result of the voting was against following things happen:

  • the stake of the creator of the vote is burned
  • the stake of other voters is returned to them

If the voting result was in favor, following things happen:

  • the stake of the creator is converted to the stake of the formal vote in favor
  • the stake of the other voters is returned to them

formal voting

Preconditions:

  • formal_voting_finish_time is less or equal than the current block time

If the quorum defined in informal_voting_quorum was not reached:

  • the stake of the creator of the voting is burned
  • the stake of other voters is returned to them

If the voting result was against:

  • the stake of the voters who voted in favor is redistributed between voters who voted against

If the voting result was in favor:

  • the stake of the voters who voted against is redistributed between voters who voted in favor
  • the update_at method in the Variable Repo is called

Repo Voter redistribution

The redistribution process takes all the tokens staked by the losing side and transfers them to the winning side. The tokens should be divided in a ratio in which the winners voted. For example:

  • Losing side staked: luser1: 50 tokens, luser2: 50 tokens. In total: 100 tokens.
  • Winning side staked: user1: 50 tokens, user2: 50 tokens, user3: 100 tokens. In total: 200 tokens.
  • user1 and user2 should both receive 50 tokens of their stake, plus 25% of the losing side's stake, totaling to 75 tokens each.
  • user3 should receive 100 initial stake + 50% of the losing side's stake - 150 tokens.

It emits the following events:

InformalVotingEnded( // after successful call on informal_voting_id
  result: converted_to_formal | rejected | quorum_not_reached,
  votes_count: U32,
  for_stake: U256,
  against_stake: U256,
  informal_voting_id: U256
  formal_voting_id: U256
)
FormalVotingEnded( // after successful call on formal_voting_id
  result: passed | rejected | quorum_not_reached,
  votes_count: U32,
  for_stake: U256,
  against_stake: U256,
  informal_voting_id: U256
  formal_voting_id: U256
)

Flow diagram

To better illustrate the flow of communication between contracts and users, see the following diagram:
Governance Vote(3)

Split `dao_nft` into `kyc_nft` and `va_nft`.

Right now we reuse dao_nft for KYC and VA Tokens. When deploying as WASM to live network it deploys both tokens under the same name "dao_nft_contract_package_hash", which is problematic.

One of the solutions is actually having two very simmilar files kyc_nft.rs and va_nft.rs and corresponding bins and wasm files.

VariableRepo Contract

VariableRepo

The Variable Repository Contract allows to store, modify and query the configuration. The configuration is stored as bytes.

Variables

values

values: Mapping<key: String, (value: Bytes, future: Option<(Bytes, U256)>)>

Stores the current value and optionally a value for a moment in the future.

Entry points

Change ownership (Ownable)

Should work the same as in ReputationToken.

fn change_ownership(&mut self, owner: Address);

Add to Whitelist (Whitelist)

Should work the same as in ReputationToken.

fn add_to_whitelist(&mut self, address: Address);

Remove from Whitelist (Whitelist)

Should work the same as in ReputationToken.

fn remove_from_whitelist(&mut self, address: Address);

Update At

It should store the value if doesn't exist or update if exists.
If the activation_time is passed and is greater than the current block time, the future part of values should be updated.
If the activation_time is passed and is less than the current block time, the future part of values should be set to None.
If no activation_time is passed, only the current value should be updated, the future part of values should be set to None.
Only whitelisted accounts should be able to call it.

fn update_at(&mut self, key: String, value: Bytes, activation_time: Option<U256>);

A successful call of this method should emit an Event:

ValueUpdated (
  key: String,
  value: Bytes,
  activation_time: Option<U256>
)

Get

It should provide a value or fail if the value doesn't exist.
If the future portion of the value is equal or less than block time, the value from the future should be returned. Otherwise, the current value should be returned.

fn get(&self, key: String) -> Bytes;

Initial configuration

During the creation of the contract, it should be initialized with a set of variables needed for other contracts. Those should be:

Parameter name Parameter Value
default_policing_rate 300
reputation_conversion_rate 10
forum_kyc_required True
formal_voting_quorum 500
informal_voting_quorum 50
voting_quorum 200
formal_voting_time 432000000
informal_voting_time 86400000
voting_time 172800000
minimum_governance_reputation 100
minimum_voting_reputation 10

Complex Mappings.

Extend Mapping to be able to accept other Mappings or even Modules like (OrderedCollection).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.