HQ20 / contracts

A set of reusable smart-contracts

Home Page:https://hq20-contracts.netlify.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DAO should be able to raise funds through a Voting process

uivlis opened this issue · comments

The goal is to be able to restart the DAO funding through a Voting, much like when proposing a new venture, or releasing dividends.

However, that would require the DAO (or the Voting?) to call on the DAO itself several methods from IssuanceEth (for example, setIssuePrice, or startDistribution etc.) which can be called only by the owner (the deployer of the DAO, that is).

This task is also to find a possible solution to this dilemma.

One way of bypassing the issue would be to have the owner call on the DAO transferOwnership to the DAO once the DAO is launched.

I think that transferring ownership to the DAO contract is an elegant solution.

Once that is done we can put all actions through votes.

To allow the several functions to be called we can put them all together in a DAO function, when they all can be executed in the same transaction (for example transition, setIssuePrice and startIssuance).

We probably should also allow the DAO to accept proposals with arbitrary proposalData, so that a proposal can be done for any single function and parameter combination in the DAO contract. Instead of proposeVenture and proposeDividends we would have propose(contractAddress, proposalData)

Thoughts @uivlis?

Sure, I'll do this.

And I think there might be an even more elegant solution for the ownership issue, that does not require any call on behalf of the owner, but that will be a surprise (because I'm not sure it will work).

I've been thinking about your suggestion of having propose(address, data) replace all the other propose functions, but I see some major setbacks: it would require participants to manually check (if it's available) the contract code of every proposal in order to know what they are voting for. It would also make room for memory abuse of the proposals storage variable. Should we better stay with individuated propose functions? After all, we still have to keep the individuated enacting functions in the DAO.

Oh, and regarding that surprise: I was thinking at calling address(this).delegatecall(abi.encodeWithSignature("transferOwnership(address)", address(this))); inside the DAO constructor, apparently it works. However, that would mean that I have to override setIssuePrice, startIssuance and so on for the initial round since now, only the DAO could call these functions and there's no voting since there are no tokens, yet. So I would do this:

function startDistribution() public {
        require(
            totalSupply() == 0 || proposals.contains(msg.sender),
            "Could not start distribution."
        );
        super.startDistribution();
        proposals.remove(msg.sender);
    }

for example, which would work both for the initial round, and for future voted rounds.

Let me know your thought on these.

Oh, and regarding that surprise: I was thinking at calling address(this).delegatecall(abi.encodeWithSignature("transferOwnership(address)", address(this))); inside the DAO constructor, apparently it works.

  1. Can't you just call transferOwnership(address(this)) in the constructor (link)?

  2. While that is a cool idea, wouldn't be cleaner to transferOwnership inside startDistribution? To mee it seems like the point in time when the DAO actually comes to life. During the initial funding round the DAO doesn't actually exist, it's only a proposal (coded as an issuance process).

  3. I'm thinking of getting rid of setIssuePrice and take price as a constructor parameter (inheriting contracts can create a function to reset the issue price if they need to).

  1. No, I don't think so, since transferOwnership has to be called by the owner, that's why I use delegatecall.

  2. Yes.

  3. Should I do this in Issuance?

  1. Interesting.
  2. Let's try in startDistribution then.
  3. Yes, please remove from Issuance

I just merged #226, please start a new branch from master for this issue.

I've been thinking at another issue. When opening a new investment round, the startDistribution call must be voted (as the DAO is now the owner, after the initial phase), as well as in the case of cancelAllInvestments, which made me think at this: why do we need the states in Issuances? That is, why can't we just have invest and claim and cancel called haphazardly? It would simplify a lot, not just the DAO, but also the Issuance.

invest cannot be called at will, because that would allow anyone to mint more issuance tokens at the ICO price, regardless of the market price.

cancelAllInvestments can be simply removed from IssuanceEth.sol, IMHO.

To remove startDistribution we could modify IssuanceEth.sol so that it takes a targetAmount at the constructor, and then invest checks msg.value:

  • amountRaised + msg.value < targetAmount -> Continue
  • amountRaised + msg.value > targetAmount -> Revert
  • amountRaised + msg.value = targetAmount -> _transition("LIVE")

The latest one would be hard to achieve if the gas used is removed from msg.value (is it?).

In plain English this issuance would be "I want to raise this much, if I get it go live immediately.". If the funds are not raised the issuance would be come a kind of zombie.

I'm not too bothered about changing the mechanics of IssuanceEth as long as we keep it a simple contract.