Coder Social home page Coder Social logo

daostack / arc Goto Github PK

View Code? Open in Web Editor NEW
46.0 6.0 25.0 14.17 MB

Arc is an operating system for DAOs.

License: GNU General Public License v3.0

JavaScript 66.49% Dockerfile 0.10% Solidity 33.36% Shell 0.05%
blockchain dao ethereum decentralization voting reputation-holders

arc's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

arc's Issues

Some comments on contracts code

I became aware of this project yesterday at a meetup where Matan presented it.
I am not sure what is the security model you have (i.e., who is malicious and who is trusted), but I thought I can give some small comments nevertheless.

  1. When setting reputation, there is a danger of an overflow when totalReputation - reputation[_account] + _amount > 2**256 (note that user is free to set _amount to whatever value he wishes).

  2. The winning proposal function winningProposal is attackable. A malicious user might propose many proposals by calling NamedProposalBallot, which will cause winningProposal to run out of gas, even if the possible maximum gas is allocated for running it.
    A possible fix is to update the winning proposal on the fly, whenever calling vote function.

I can arrange a pull request to fix these two issues if you want.
But I am still not sure I get the full picture.

don't have configuration logic in solidity (but in javascript)

General rule is that only those things that need to be persistent and trustless go to the blockchain/solidity. The reason is that the blockchain is expensive/difficult to work with, in comparison to javascript.

This seems to me a wrong pattern to use:

// deploy a helper contract that creates my controller
helpercontract = new GenesisSchema(configurationoptions)
// do some explicit stuff that the helpercontract is not doing automatically 
helpercontract.collectFoundershare()..
// now get the controller
controller = x.controller()
// if we need to do more config, we can do it by voting
controller.proposeToAddSomeSchema(0x1234, 400)
controller.voteonthis()

This is wrong because (1) configuration logic is spread over javascript and solidity, which is messy and hard to code and understand and (2) is wastes resources by deploying contracts that are just temporary helpers.

Instead, this pattern seems more straightforward to me:

// create a new Controller
controller = new Controller(somebasicsettings)
// the controller is owned by its cerateor, who can now do some more configutaation here in javascript
controller.setReputation(0x123, 100)
controller.addSchema(0x125)
// when configuration is done, the owner can renounce ownership
// (e.g. by setting the owner "to itself")
controller.transferOwnershipt(controller.address)

should SchemeRegistrar also register the controller at the scheme?

The current workflow is to register the schem is:

  1. propose the Scheme
  2. vote for it
  3. deciding vote registers the scheme at the controller
  4. register the controller at the scheme
  5. start using it

Question: should 4. be included in 3?

pro: easier to use, one transacion less
contra: possibily need tokens to register the controller

Anyone can win their own proposed vote every time?

Lets say we have a Reputation system with total supply 100 and I (account[0]) have a reputation of 5.

I can do:

const simpleVote = await SimpleVote.new();
const executable = await ExecutableTest.new();
const paramsHash = await simpleVote.setParameters(reputation.address, 4);

const tx = await simpleVote.propose(paramsHash, helpers.NULL_ADDRESS, executable.address);
const proposalId = await getValueFromLogs(tx, '_proposalId');

await simpleVote.vote(proposalId, true, accounts[0]);

Won't this win every time?

Roadmap

Roadmap

Step 1: Basic solidity infrastructure

At this point we have a generic upgradeable DAO with reputation, majority voting, and the possibility to mint and sell tokens, distribute reputation.

#11 #19 #5 #25 #29

Step 2: Basic UI

See #15 for details.

Next features

  • Sale of tokens for other tokens (not ETH) with fixed rate
  • Varying sale schemes (possibly with vesting) (template for the general token distribution scheme)
  • Possibly (decaying) reputation distribution scheme to token buyers
  • Vested tokens scheme for contributors (template for the general token distribution scheme)
  • Possibly let successful contributor to choose from vested-amount range option
  • Reducing reputation by supermajority vote (80%?) (right now reducing and increasing is symmetric)
  • Internal successful vote translated to external vote
  • Conditions to trigger external contribution
  • Affiliate contract (my own address for buyers / contributors) to give reputation + tokens for deployer
  • Reputation flow upon vote according to alignment

create a generic "AssignNewReputationBallot" contract

  • inherits from "Ballot.sol" and "NamesProposalBallot.sol" (probably)
  • proposals are a set such as "assignnothing, assign10rep, assign20rep, ..."
  • executeWinningProposal calls "setReputation" on the associated reputation contract

Organization.new(..) API

This is the currently implemented API, https://github.com/daostack/daostack/blob/dev/docs/library/organization.md

Here are some questions/suggestions for improvement:

  • Perhaps it is better to pass the founders like this:
    await Organization.new({
    orgName: 'Name of organization', // string, required, name of organization
    tokenName: 'xx', // string, required, name of organization's token
    tokenSymbol: 'xxx', // string, required, symbol of organization's token
    founders: [
    address: '0x1234',
    reputatoin: 30,
    tokens: 12.3333,
    ] })

  • should we offer the optino to set the schemes used. Or do we just offer our ones, or the possibility to "roll your own"?

Important operations should be logged (as events)

Even though ethereum blockchain is public and technically any data is extractable by anyone, it is still technically cumbersome to reason on operations that are not explicitly logged.
Logging important operations, such as votes, token minting, reputation creation etc, as solidity events generates public trace and thus both increase the credability of the contract (e.g., one can witness that the contract is running as expected) and give the user an interface to programmingly react to important operations (e.g., if person X votes Y, then I will also vote Y).

linking schemes to controller

Here's the thing:

In the library, I'd expect this kind of interaction (one of these, I'm not sure about the syntax yet):

organization.proposeNewScheme(...) 
organization.schemeRegistrar.proposeScheme(...)
organization.schemes.schemeRegisterar.proposeScheme(...)

The first problem with this is that at the moment there is no way (as far as I can see) to get the 'schemeRegistrar' from the controller.

There is an extra complication that in theory there is no the schemeRegistrar, there could be many registered.

(Just be clear, what we can do is:

  1. get SchemeRegister events for a controller
  2. get the addresses of the registered schemes from these events
  3. get the permissions and params of each registered scheme from the controller
  4. get info from the scheme instances themselves
    )

Possible solutions:

  • add "type" to schemes mapping (makes registerScheme calls more complex)
  • add "type" property to each Scheme instance
  • add specific properties to the controller for schemeRegistrar, updateScheme and globalConstraintRegistrar (with specific registration functions).

I vote tentatively for the second solution, which seems the least traumatic and does not need any changes in the code.

SimpleVote semantics questions

  • propose(...) does not automatically vote, which is different from the proposeScheme, where proposing -does- imply voting.

  • vote(proposalId, yes, voter): the owner can cast a vote in the name of voter. This renders the contract inherently less "trustless" - trust is transferred to the owner. In our case, the owners is the controller: this means that the organization could accepts a proposal to vote in some minorityes name. It all seems messy and wrong.

  • UX issue with SimpleProposal.vote(...) We now have the situation where, if the decisive vote is cast, the proposal is executed This has the following problem: if for some reason, the executions fails (and it could fail for many reasons), this means the vote will not be counted at all.

test SimpleVote.sol

We need a set of tests (in test/simplevote.js) that test registering a prposal, voting with different parameters, testing permissions.

Alpha architecture

Hi all,

After an architecture session with @fmatan.
Tried to draw the main changes towards architecture for alpha and beta versions.

Main alpha changes are:

  1. Universal schemes: Schemes that can serve several organization.
  2. Voting as a service: Similar to 1, universal voting contracts.
  3. Registry: A registry for universal schemes and voting.
  4. Upgradeability: Agreeing on how a controller is upgraded.
  5. Interoperability: Building at least one case of organization voting in another organization.

We can open an issue for each one. But I think we can start here, and the issues that will raise debate we will separate.

Adam.

proposal for changing registering of global constraints on controller

No, each global contstraints on the controller are kept in an array of address of the global constraints. This makes it possible to only register each GC contract only once on the controller. But it is easy to think of scenarios in which we use the same GC contract for different constraints, using different params (e.ge. the tokenCap constraint can also be used for external tokens).

Propsal: instead, have an array of (gccontractaddres, params) structs (or some other kind of scheme)

Should new ballot/vote be a new contract or just a function?

In the suggested scheme making a new ballot to vote on amounts to deploying a new contract. However, it can also be implemented (as in TheDAO) as a function inside a DAO contract. Should understand what's the main differences and what's better. Moreover, right now we have no DAO contract, but only a Token and Reputation contract, and Ballots to modify them. We do need to tie each Reputation contract to a Token contract 1-1, but do we need a central DAO contract? More generally it'd be useful to define the general architecture for the entire DAO and then implement its elements. A WIP on this can be found here.

Exception running truffle test on a fresh environment (Missing Ownable.sol)

Steps to reproduce:

git clone <daostack URL>
cd daostack
truffle test

Error

Error: Could not find zeppelin/contracts/ownership/Ownable.sol from any sources; imported from /mnt/d/work/eth/daostack/contracts/SimpleVote.sol
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/index.js:76:23
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/internal/onlyOnce.js:12:16
    at next (/mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/whilst.js:68:18)
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/index.js:64:7
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/fs.js:65:5
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/internal/once.js:12:16
    at replenish (/mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/internal/eachOfLimit.js:59:25)
    at iterateeCallback (/mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/internal/eachOfLimit.js:49:17)
    at /mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/node_modules/async/internal/onlyOnce.js:12:16
    at ReadFileContext.callback (/mnt/c/Users/User/AppData/Roaming/nvm/v7.5.0/node_modules/truffle/node_modules/truffle-resolver/fs.js:61:14)

Environment:

  1. Windows 10 (Bash on Ubuntu on Windows)
  2. Truffle 3.2.1

create a generic "AssignNewTokensBallot" contract

See also issue #12

  • inherits from "Ballot.sol" and "NamesProposalBallot.sol" (probably)
  • proposals are a set such as "assignnothing, assign10tokens, assign20tokens, ..." (set in the contstructor)
  • executeWinningProposal calls "mintTokens" on the associated Token contract

What's preventing a malicious Reputation's owner from manipulating proposal results?

https://github.com/daostack/daostack/blob/6a2a928cc130e78638d4f440112e11c147f4b0b3/contracts/VotingMachines/SimpleVote.sol#L168

While a vote is opened, the totalSupply of Reputation can change. The owner of the Reputation is the only one that can mint and set reputation, but what happens when this owner cannot be trusted? He can manipulate totalSupply and affect voting results.

I think reputation should be given via contract and not by the Reputation owner.
E.g. make a reputation registry - like the gov registry - with "plug-able" reputation implementations and allow DOAs to create/choose their own reputation system.

Also I like that you did take into account that reputations change while a proposal is opened (by using proposal.voted[_voter]):
https://github.com/daostack/daostack/blob/6a2a928cc130e78638d4f440112e11c147f4b0b3/contracts/VotingMachines/SimpleVote.sol#L111-L120

deploying a new organization takes a lot of work

One of the main points of the genesisscheme is to simplify the deployment into as few transactions as possible. This is working out not so good.

At the moment of writing (commit 64c1554) the deployment procedure of a new organization that uses only already existing schemes takes 8 different transactions, plus you need to have tokens to pay for registering your organization with the schemes (at the moment 3, possibly different from each other).

The relevant code is here: https://github.com/daostack/daostack/blob/64c1554a003512c1cfc436040acc0bb114a13c8b/lib/organization.js#L24

Beta upgrades

Proposed upgrades for the beta version:

  1. Universal controller - Build a controller like a universal scheme, to serve many organizations.
  2. Complete voting as a service - Voting will take place in the voting contract itself. At the end of the voting the voting machine will called the agreed execution function.
  3. Change the interoperability scheme - Once the voting will take place in the voting machine it will be easier for organizations to vote in other organizations, but will require adjustments. The avatar will delegateCall to the scheme that called it.
  4. Universal scheme (and other schemes) will not hold the hashing of the parameters, only the controller will. The scheme will only hold a mapping from the hashing to the parameters.
  5. Schemes privileges - Instead of treating the upgrading scheme or the GC scheme specially, treat them as usual schemes.
  6. Fix simple voting to account for reputation printing.
  7. Voting based on token - locking of tokens.
  8. Implement a voting that will allow the governance model decided in the coalition.
  9. Reduce gas to have pre and post global constraint.
  10. Organization should pay the fee for scheme registration and not the agents.

@fmatan @jellegerbrandy, your thoughts and ideas will be appreciated :)

renaming proposal

UniversalGCRegister ==> GlobalConstraintsRegistrar
	(not register but registrar, because it is not a register but a contract that is registering global constraints at te controller)
UniversalGenesisScheme ==> GenesisScheme
UniversalOrgRegistry ==> OrganizationRegister 
UniversalScheme ==> Scheme
UniversalSchemeRegister ==>> SchemeRegistrar
	(a scheme that registers other schems)
UniversalSimpleContribution ==> SimpleContributionScheme
UniversalUpgradeScheme ==> UpgradeScheme

UniversalSimpleVote ==> BooleanVotingMachine
BoolVoteInterface is not used: remove?
UniversalSimpleVoteInterface ==> VotingMachineInterface

nativeToken ==> token (anywhere where it does not lead to ambiguity)
nativeReputation ==> reputation (anywhere where it does not elad to ambiguity)

Create Reputation Contract (step 3)

  • Contract initiated with fixed amount of non-transferable reputation score to deployer

  • Assign new reputation score works like this:

    • open a Ballot for assigning new reputation (#12)
    • have reputation owners vote
    • Result of vote is the reputation-weighted median (RWM) of votes (out of entire reputation) (#11)
    • execute the proposal (depends on #11)
  • Assigning new tokens works in a way very similar to assigning reputation, just that it is another type of Ballot (#13)

User Interface

The UI should make interacting with a DCO simple and intuitive. In the spirit of the DAO stack, we implement functionality in an incremental way.

  • Token (see your balance, transfer tokens)
  • MintableToken (create new tokens (owner only))
  • Reputation (see your rep, perhaps see also info about distribution of rep)
  • generic Ballot (vote on an issue. see the proposals, vote for on, see the current voting situation, etc)
  • Backfeed style DCO (...)

possible bug: delete proposals in execute defs

for example, the eecute function in SimpleContributionScheme.sol starts with:

    function execute(bytes32 _proposalId, address _avatar, int _param) returns(bool) {
      // Check if vote was successful:
      // TODO: this seems a security problem
      if (_param != 1) {
        delete proposals[_proposalId];
        return true;
      }

which seems to allow anyone to delete a proposal from the propals list. The same pattern occurs in other places

semantics of SimpleICO.registerOrganization

all other schemes: "registerOrganization" add the avatar to the list of registered organization. SimpleICO also creates a donatino contract and checks for settings on the organization.

Proposal is to have a uniform semantics for registerOrganization in the schemes, and add a 'startICO' or similar for actually starting hte ICO.

Create and deploy Basic Token Contract

This is a standard Token contract that is Ownable and Killable.

  • Contract launches with 10,000 tokens to deployer
  • Anyone can transfer his own tokens to others
  • Contract deployer is first owner
  • Ownership can be transferred
  • Kill/suicide function by owner: funds go back to owner
  • Anyone can send a transaction through the UI

decide about the actual voting-collection method

[matanf wrote:] We need to decide about the actual voting-collection method: we have a default one for now but should consider others. There's a few posts on this topic (including of people from Colony), reviewing different methods and problems. Basically you can compute votes all together, or one by one, etc.

TravisCI integration

We'd like to run tests and perhaps also some formatting checks automatically on each commit

GenesisScheme is schizophrenic

The genesischeme at the moment does two different, basically unrelated, things:

  1. It serves to create a new controller (and has a getFoundershare method linked to that)
  2. It serves as a schema to propose new schemas

I propose to separate this in two different contracts (or, if we do what i propse in #25, just forget about the 1), and just have it do 2).

specs: what happens with decisions if reputation distribution changes?

Reputation distribution changes in time; the decision process takes time. This raises a number of decisions we need to make on how to count votes (i.e. relative to which distribution): Here is a typical case:

  • Ann has 55% of the reputation, Bill has 45%.
  • Ann votes "yes".
  • Reputation distribution changes: Bill now has 60%, Ann has 40%.
  • Bill votes "no"

Question: did the proposal pass? And specifically: how much rep is staked on "yes" and how much on "no"?

Implement reputation-weighted median (RWM) of votes

  • this should (as the code is setup now) go into Ballot.sol, in "winningProposal"
  • proposals in the ballot need to be linearly ordered
  • winningProposal is the median of the proposals weight by reputation of the votes

Javascript library for interfacing with DAOStack contracts

The idea is that the frontend-devs would be much helped with a consistent sane interface.

A JS sessino interacting with an Organization could look like this (simplified by pretending these are all synchronous functions; in reality the code would be full of 'awaits')

import { Organization } from 'lib/Organization.js';

// a new organization is called with an options object that has lots of sane defaults.
// These are the the only obligatory options:
let organisation =  Organisation.new({
   orgName: 'A descriptive name',
   tokenName: 'OrgToken',
   tokenSymbol: 'OTO'
});

// while the full list of options (with its default) looks like this (there will be moer options):

organisation = Organisation.new({
    orgName: null, // no default provided, must be defined in the function call
    tokenName: null, // no default provided
    tokenSymbol: null, // no default provided
    founders: [],
    tokensForFounders: [],
    repForFounders: [],
    genesisSchemeAddress: 0x123, // default is the most recnet DAOStack genesis scheme
    schemeRegistrar: {
          address: 0x12344, // default is the daostack registrar
          votingMachineAddress: 0x1234, // a SimpleVote contract
          reputationAddress, // default is the reputation of the present organisation,
          votePrec: 50, // percentage of votes needed for decision
   },
   GCRegister:  {
     // ... config here
   },
   UpgradeScheme: {

   },
})

// alternative, a deployed organization can be instantiated using "at"
organisation = Organization.at('0x12345..');

// the Organisation object corresponds roughly to the controller and its "spiderweb" of registered schemes, tokens, etc

organisation.token();
organisation.reputation();
organisation.avatar();

// next call returns the registered schemes
let schemes = organization.listSchemes()
// scheme will be an in isntance of Scheme
let scheme = schemes[0];
// the scheme has all the methods of the corresponding contract on the blockchain
// (and perhaps others)
// for example, if scheme is a SimpleICO, we can do:
scheme.haltICO(controller);

// we can also see which proposals have been proposed (in the different schemes)
let proposalsList = organisation.listProposals();
// proposalsList is an array of Proposal instances
let proposal = proposalsList[0];
// we can getinfo from the proposal like how many have voted, what scheme they are 
// registered in, what votingmachine is being used, etc
assert.equal(proposal.yes(), 12);
assert.equal(assert.scheme.address, '0x124...');
proposal.votingMachine;
proposal.votingMachineParams;


// voting looks like this
organisation.vote(proposal, true);
// or we can even do:
proposal.vote(true);

// etc. etc. (still to be defined)

Why does a proposal.owner can vote on behalf of someone else?

https://github.com/daostack/daostack/blob/6a2a928cc130e78638d4f440112e11c147f4b0b3/contracts/VotingMachines/SimpleVote.sol#L106-L108

What is preventing a malicious proposal.owner rapidly voting for its proposal "on behalf" of other voters (just call vote with other voters' addresses) and triggering a successful executeProposal(_proposalId) in https://github.com/daostack/daostack/blob/6a2a928cc130e78638d4f440112e11c147f4b0b3/contracts/VotingMachines/SimpleVote.sol#L133 after enough votes?

I think that _voter should always be msg.sender.

Am I missing someting? When and why would a voter need to vote on behalf of someone else?

Upgrade to solidity and truffle

Hi,

Solidity 0.4.11 was introduced. There were several important changes since 0.4.8 (most of the current code was last written using 0.4.8).
Important changes:
They added

.transfer as a recommended replacement for .send (throws on failure instead of returning false).
They added revert, which is like throw, but does not consume all gas.

I have opened a new branch to implement these new features and will soon merge it to master.

Adam.

fix error assertions in tests

The next pattern is not really testing anything (the value of fail is always 200).

        try {
          web3.eth.sendTransaction({'from':founders[1], 'to':tokenSaleAddress, 'value': web3.toWei(1, "ether")});
          throw 'an error' // make sure that an error is thrown
        } catch(error) {
            fail = 200;
        }
        
        assert.equal(fail,200,"buying tokens should fail"); // todo make less ugly 

Instead it should be:

try {
         web3.eth.sendTransaction({'from':founders[1], 'to':tokenSaleAddress, 'value': web3.toWei(1, "ether")});
         throw 'an error' // make sure that an error is thrown
       } catch(error) {
           // assert something specific about the kind fo error - for example that it is not the error thrown in the previous line 
          assertJump(error)
       }

Specs: should our standard token contract have a limit on the amount of tokens that can be created?

In the current setup, the Token contract can mint unlimited new tokens.

This may be unideal, because it makes all tokens infinitely dilutable, in principle. There is no garantee for a token holder that his tokens will continue to represent a certain guaranteed fraction of the total amount. Anyone who controls the mint function can dilute your tokens as much as he wants (assigning them to himself, for example).

Question: should we put a maximum limit on the amount of tokens that can be created, making them more similar to stocks in the real world?

bundle the library

Our code needs to be usable in the browser - we need to set up a build system that bundles and browserifies our library

make contracts linter consistent

npm run solium should exit without errors or warnings.

once all errors are resolved, we should add solium to the travic tests

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.