Thursday, July 26, 2018

Building an Ethereum DApp: Launching the StoryDao

In part 7 of this tutorial series on building DApps with Ethereum, we showed how to build the app’s front end, setting up and deploying the UI for this story we’ve been working on.

It’s time to do some deploying and write a few final functions.

Suicide

Something could go very, very wrong and the whole DAO somehow get destroyed — either through hacks of bad and hastily written code, or through the inability to make long loops due to too many participants. (Too many voters on a proposal might as well break the system; we really didn’t put any precaution in place for that!) Just in case this happens, it might be useful to have the equivalent of a “big red button”. First, let’s upgrade our StoryDao:

function bigRedButton() onlyOwner external {
    active = false;
    withdrawToOwner();
    token.unlockForAll();
}

Then, let’s make it possible to unlock all the tokens at once in our Token contract:

/**
@dev unlocks the tokens of every user who ever had any tokens locked for them
*/
function unlockForAll() public onlyOwner {
    uint256 len = touchedByLock.length;
    for (uint256 i = 0; i < len; i++) {
        locked[touchedByLock[i]] = 0;
    }
}

Naturally, we need to add this new list of addresses into the contract:

address[] touchedByLock;

And we need to upgrade our increaseLockedAmount function to add addresses to this list:

/**
@dev _owner will be prevented from sending _amount of tokens. Anything
beyond this amount will be spendable.
*/
function increaseLockedAmount(address _owner, uint256 _amount) public onlyOwner returns (uint256) {
    uint256 lockingAmount = locked[_owner].add(_amount);
    require(balanceOf(_owner) >= lockingAmount, "Locking amount must not exceed balance");
    locked[_owner] = lockingAmount;
    touchedByLock.push(_owner);
    emit Locked(_owner, lockingAmount);
    return lockingAmount;
}

We should also update the required interface of the token inside the StoryDao contract to include this new function’s signature:

// ...
    function getUnlockedAmount(address _owner) view public returns (uint256);
    function unlockForAll() public;
}

With the active-story block we added before (inability to run certain functions unless the story’s active flag is true), this should do the trick. No one else will be able to waste money by sending it to the contract, and everyone’s tokens will get unlocked.

The owner doesn’t get the ether people submitted. Instead, the withdrawal function becomes available so people can take their ether back, and everyone’s taken care of.

Now our contracts are finally ready for deployment.

What about selfdestruct?

There’s a function called selfdestruct which makes it possible to destroy a contract. It looks like this:

selfdestruct(address);

Calling it will disable the contract in question, removing its code from the blockchain’s state and disabling all functions, all while sending the ether in that address to the address provided. This is not a good idea in our case: we still want people to be able to withdraw their ether; we don’t want to take it from them. Besides, any ether sent straight to the address of a suicided contract will get lost forever (burned) because there’s no way to get it back.

Deploying the Contract

To deploy the smart contracts fully, we need to do the following:

  1. deploy to mainnet
  2. send tokens to StoryDAO address
  3. transfer ownership of Token contract to StoryDao.

Let’s go.

Mainnet Deployment

To deploy to mainnet, we need to add a new network into our truffle.js file:

mainnet: {
  provider: function() {
    return new WalletProvider(
      Wallet.fromPrivateKey(
        Buffer.from(PRIVKEY, "hex")), "https://mainnet.infura.io/"+INFURAKEY
    );
  },
  gasPrice: w3.utils.toWei("20", "gwei"),
  network_id: "1",
},

Luckily, this is very simple. It’s virtually identical to the Rinkeby deployment; we just need to remove the gas amount (let it calculate it on its own) and change the gas price. We should also change the network ID to 1 since that’s the mainnet ID.

We use this like so:

truffle migrate --network mainnet

There’s one caveat to note here. If you’re deploying on a network you previously deployed on (even if you just deployed the token onto the mainnet and wanted to deploy the StoryDao later) you might get this error:

Attempting to run transaction which calls a contract function, but recipient address XXX is not a contract address

This happens because Truffle remembers where it deployed already-deployed contracts so that it can reuse them in subsequent migrations, avoiding the need to re-deploy. But if your network restarted (i.e. Ganache) or you made some incompatible changes, it can happen that the address it has saved doesn’t actually contain this code any more, so it will complain. You can get around this by resetting migrations:

truffle migrate --network mainnet --reset

The post Building an Ethereum DApp: Launching the StoryDao appeared first on SitePoint.


by Bruno Skvorc via SitePoint

No comments:

Post a Comment