Skip to content
Lefteris Karapetsas edited this page Jun 7, 2016 · 2 revisions

Intro

The PFOffer contract is a sample impementation of a Contract that follows the Proposal Framework and is intended as a hard requirement for any proposals that want to get whitelisted for the DAO v1.0 contract.

Usage

Contract deployment

A contractor will have to deploy an instance of this contract setting the arguments of the constructor according to the contents of their proposal:

    function PFOffer(
        address _contractor,
        address _client,
        bytes32 _hashOfTheProposalDocument,
        uint _totalCosts,
        uint _oneTimeCosts,
        uint128 _minDailyWithdrawLimit
    ) {

An example deployment call in javascript can be seen below. In all our examples we assume that pfoffer_abi contains the ABI of the contract, pfoffer_bin the compiled binary of the contract and contractor is the address of the contractor.

var offerContract = web3.eth.contract(pfoffer_abi);
var _offerContract = offerContract.new(
    contractor,
    "0xbb9bc244d798123fde783fcc1c72d3bb8c189413", // client DAO address
    '0x0',  // Should be a hash of the paper contract
    web3.toWei(50, "ether"), //total costs
    web3.toWei(10, "ether"), //one time costs
    web3.toWei(1, "ether"), //min daily costs
    {
	    from: contractor,
	    data: pfoffer_bin,
	    gas: 3000000
    }, function (e, contract){
	    if (e) {
            console.log(e+" at PFOffer creation!");
	    } else if (typeof contract.address != 'undefined') {
            console.log("Deployed PFOffer address:" + contract.address);
        }
    });

Addition to the whitelist

After the contract is deployed, the community will have to verify it to see that it does indeed do what it claims and that it indeed a properly deployed instance of PFOffer. Once that is done the curators will have to whitelist the contract.

Proposal Creation

After the contract is whitelisted, the contractor can now create a new Proposal to get their PFOffer signed. An example call can be seen below.

dao.newProposal.sendTransaction(
    pfoffer.address,
    web3.toWei(50, "ether"), // this is the total costs of the offer
    "PFOffer contract description will go in this string",
    "0x2ca15122", // transaction bytecode to call sign() on PFOffer
    2 weeks, // proposal debate period
    false, // no, this is not a split
    {
        from: contractor,
        value: web3.toWei(20, "ether"), // this is the proposal deposit
        gas: 1000000
    });

Calling watchProposal() on the PFOffer

At this point the proposal is up for voting and has a corresponding proposal ID. It is now the responsibility of the contractor to call watchProposal() in order to set the correct proposal ID that corresponds to his contract. The community should check that this is done correctly.

Below you can see an example call where prop_id is the generated proposal ID for the proposal, and pfoffer is the deployed contract instance.

pfoffer.watchProposal.sendTransaction(prop_id, {from:contractor, gas: 400000});

Protecting from last minute yes votes

One of the problems that the proposal framework wants to solve is the last minute yes votes. A proposal that has no chance of passing and everybody ignores it because they all believe it will just never reach quorum can be passed at the very end of the voting period by a lot of surprise yes votes.

The way with which PFOffer protects against this is by allowing anybody to call the checkVoteStatus() on the PFOffer contract. That function will check that the voting has reached a particular quorum (number still under debate, it's set to 15% at the current version) and is X (number still under debate, it's set at 2 in the current version) days before the voting deadline.

This way we can confirm that the vote has reached a positive outcome with sufficient quorum, enough days before the deadline, thus avoiding surprise votes occuring only at the end of the voting period.

Anyone can call this function. The contractor is highly incentivized to call it though since if this function does not succeed his proposal will not be signed.

pfoffer.checkVoteStatus.sendTransaction({from: contractor, gas: 400000});

Vote Results and Proposal Execution

If the contractor's proposal gets:

  1. yea > nay && sufficient quorum
  2. checkVoteStatus() call was succesfull

Then the proposal will pass at the end of the debate period. At that point anyone can execute it. In the example below prop_id is the ID of the proposal.

dao.executeProposal.sendTransaction(
    prop_id,
    "0x2ca15122"
    {from: contractor, gas: 400000}
);

At this point the proposal will have been approved by the DAO and the total costs will be transferred to the Offer Contract.

Payout Freeze Period

The PFOffer contract has a 3 week payout freeze period as an extra protection against surprise proposals being passed at the last minute and as a way to allow the DAO a second chance to change its mind before any money is actually spent.

Within the first week the DAO can cancel the contract without losing any money by making a proposal to call returnRemainingEther() on the PFOffer contract. If that proposal is voted, passed and executed then the PFOffer contract is canceled and all unspent money is sent back to the DAO.

Initial Payment

If the contractor survives the payout freeze period then he can claim the initial costs. That is done by calling getOneTimePayment(). Anyone can call this function, but the end result is the same. The initial payment is sent to the contractor.

    pfoffer.getOneTimePayment.sendTransaction({from: contractor, gas: 500000});

Daily Payments - Business as usual

From this point on the contractor can be withdrawing payments at the agreed burning rate.

    pfoffer.getDailyPayment.sendTransaction({from: contractor, gas: 100000});

Conclusion

We saw a general workflow description of how to use a contract deployed using PFOffer. An important thing to note is that at any point in time the DAO can make a proposal to cancel the contract and return remaining ether just as was seen in the relevant section.

This wiki entry may eventually get outdated so the actual contract code should always be the master reference.

Clone this wiki locally