Archive for  June 2016

Home / June 2016
2 Posts

If anyone of you believes into ethereum and did not hear about the planned DAO soft fork of ethereum, it’s time now to be careful. Although the supporters of the soft fork have repeatedly mentioned their concerns on the soft fork, they all chimed in to advertise it as the right thing to do after all. It seems as if they are trying to sweep all their concerns under the table, keeping telling themselves it won’t be as wrong as it seems to them. But it is. It is nothing less wrong than violating the basic rules of ethereum and enforcing it onto its users.

But why is that? In order to understand, we have to look at what makes ethereum so valuable. This is how ethereum is defining itself and what all the ethereum users have bought into:

Ethereum is a decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third party interference.

No censorship, fraud or third party interference.

That essentially means, that the ethereum developers will care to fix bugs in ethereum (such as when the software does not follow its specifications), miners will keep mining blocks in order to get rewards and everything is being determined by the code written and the specifications that make up the ethereum platforms. Exactly this is what make ethereum so unique: For the first time in history, there is a truly unregulated (read as unmanipulatable for egoistic interests) way to create contracts.

The problem with regulation: manipulation

If you look at the history of bitcoin you will notice its success is coming from the fact that it is not regulated. All money you own is just virtual, after all it is just a piece of paper, metal or any other physical replacement for a value everyone believes in. If your bank zeros your account, if the state declares that all your money is worthless or if it decides to create more money out of nowhere, you do not have the slightest chance to practically do anything against that. You can go into court theoretically, but you will never win practically.

Bitcoin is different in the sense that there is no regulatory instance that can harm you practically in the first place. This is kind of a game changer, be it with risks on your side. Because if you send bitcoin to a wrong address, or you lose your funds because someone has gained access to your wallet, all your money is gone. Noone can help you, because there is noone supervising and able to rollback transactions. But this isn’t necessarily a bad thing. When the EU banks articificially limited the access of the greece people to their own money (which is a form of misusing regulatory power, ie. manipulation), those foreseeing these actions just turned their funds into bitcoin quickly in order to escape the threat and maintaining their freedom. Mind you: This has been done in order to “save the banks and economy”. So, with freedom comes responsibility.

With freedom comes responsibility!

Those people investing in the DAO had the code. They had the specifications of ethereum, they knew everything. They even knew there is a bug in the split function beforehand. And they signed a contract nonetheless. It was their responsibility to check. Apparently, a lot of them did not and lost a lot of money. By not using some part of their time/money to check and quickly buying DAO tokes, they were simply gambling for higher profits. And they failed. As I did, too. But I knew that and I was prepared to lose everything – such things might happen if you gamble unresponsibly. High risk, high profits.

Creating a case of precendence

The worst thing about the planned DAO soft fork is that is is creating a case of precedence. Today it is the so-called “attacker” of the DAO (which, see above, was just someone exploiting the unresponsibility of those signing the DAO contract), tomorrow it might be a huntdown of people having the “wrong” political opinions. But who determines what is wrong or right, who’s a hero and who’s a terrorist? Often, the heros and the terrorists are the same people, depending on who you ask.

What to do?

The DAO developers should stop spreading propaganda and keep fixing bugs that are non-conformant with the specs. There has really been no bug in ethereum that would justify a correction. By proposing a soft fork, they are violating one the basic rules, acting as a the third party manipulating the ethereum network they never wanted to exist.

Yesterday I started writings contracts, so here is my first attempt. The idea is to make a contract where sellers can register in order to obtain rated transactions. It works as follows:

  1. Sellers register through the register method. They will obtain an id.
  2. From now on, sellers can create invoices in the contract.
  3. A seller sends the invoice id to the buyer, who can pay the required amount of ether. At the same time the buyer qualifies for a seller rating.
  4. When the seller paid the invoice, he may rate the seller.

This way, sellers can build up trusted profiles on the blockchain, with unmanipulatible buyers ratings, so you can check an address before sending ether.

The contract is still BETA, please be careful. More info on trusteth.com.

Here is the contract code, licensed under AGPLv3:

//
// This file is part of TrustEth.
// Copyright (c) 2016 Jacob Dawid <jacob@omg-it.works>
//
// TrustEth is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// TrustEth is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with TrustEth.
// If not, see .
//

contract TrustEth {
    // A registered transaction initiated by the seller.
    struct Transaction {
      // Supplied by the seller (Step 1).
      uint sellerId; // The seller id of the seller who initiated this transaction and is about to receive the payment.
      uint amount; // The amount to pay to the seller for this transaction.

      // Filled out by the contract when transaction has been paid (Step 2).
      address paidWithAddress; // The address of the buyer issueing the payment.
      bool paid; // Flag that states this transaction has already been paid.
   
      // Rating supplied by the buyer (Step 3, optional).
      uint ratingValue; // Seller rating supplied by buyer.
      string ratingComment; // Comment on this transaction supplied by the buyer.
      bool rated; // Flag that states this transaction has already been rated.
    }

    // A registered seller on this contract.
    // Registered sellers can put up transactions and can be rated
    // by those who paid the transactions.
    struct Seller {
      // Seller information
      address etherAddress; // The sellers ether address.
      uint[] ratingIds; // The ids of the rating linked with this seller.
      uint[] transactionIds; // The ids of transactions linked with this seller.
      
      // Statistics about the seller
      uint averageRating; // Average value of ratings.
      uint transactionsPaid; // How many transactions have been paid?
      uint transactionsRated; // How many transactions have been rated?
    }

    Transaction[] public transactions; // All transactions.
    Seller[] public sellers; // All sellers

    // This mapping makes it easier to loopkup the seller that belongs to a certain address.
    mapping (address => uint) sellerLookup;

    // The sole contract owner.
    address public owner;

    // Configured fees.
    uint public registrationFee;
    uint public transactionFee;

    // Only owner administration flag.
    modifier onlyowner { if (msg.sender == owner) _ }

    // Administrative functions.
    function TrustEth() {
      owner = msg.sender;
      
      // Index 0 is a marker for invalid ids.
      sellers.length = 1;
      transactions.length = 1;

      // Initialize fees.
      registrationFee = 1 ether;
      transactionFee = 50 finney;
    }

    function retrieveFunds() onlyowner {
      owner.send(this.balance);
    }

    function adjustRegistrationFee(uint fee) onlyowner {
      registrationFee = fee;
    }

    function adjustTransactionFee(uint fee) onlyowner {
      transactionFee = fee;
    }

    function setOwner(address _owner) onlyowner {
      owner = _owner;
    }

    // Fallback function, do not accepts payments made directly to this contract address.
    function() {
      throw;
    }

    // Make a donation and acknowledge our development efforts. Thank you!
    function donate() {
      // That's awesome. Thank you.
      return;
    }

    // Register your seller address for a small fee to prevent flooding and
    // and recurring address recreation.
    function register() {
      // Retrieve the amount of ethers that have been sent along.
      uint etherPaid = msg.value;
      
      if(etherPaid < registrationFee) { throw; }

      // Create a new seller.
      uint sellerId = sellers.length;
      sellers.length += 1;

      // Store seller details and bind to address.
      sellers[sellerId].etherAddress = msg.sender;
      sellers[sellerId].averageRating = 0;

      // Save sellerId in lookup mapping.
      sellerLookup[msg.sender] = sellerId;
    }


    // Workflow

    // As a seller, put up a transaction.
    function askForEther(uint amount) {
      // Lookup the seller.
      uint sellerId = sellerLookup[msg.sender];

      // Check whether the seller is a registered seller.
      if(sellerId == 0) { throw; }
      
      // Create a new invoice.
      uint transactionId = transactions.length;
      transactions.length += 1;

      // Fill out seller info.
      transactions[transactionId].sellerId = sellerId;
      transactions[transactionId].amount = amount;

      // -> Pass transactionId to customer now.
    }

    // As a buyer, pay a transaction.
    function payEther(uint transactionId) {
      // Bail out in case the transaction id is invalid.      
      if(transactionId < 1 || transactionId >= transactions.length) { throw; }

      // Retrieve the amount of ethers that have been sent along.
      uint etherPaid = msg.value;
      uint etherAskedFor = transactions[transactionId].amount;
      uint etherNeeded = etherAskedFor + transactionFee;

      // If the amount of ethers does not suffice to pay, bail out :(      
      if(etherPaid < etherNeeded) { throw; }

      // Calculate how much has been overpaid.
      uint payback = etherPaid - etherNeeded;
      // ..and kindly return the payback :)
      msg.sender.send(payback);

      // Now take the remaining amount and send to the seller.
      sellers[transactions[transactionId].sellerId].etherAddress.send(etherAskedFor);
      // Rise transactions paid counter.
      sellers[transactions[transactionId].sellerId].transactionsPaid += 1;

      // Overpaid ethers send back, seller has been paid, now we're done.
      // Mark the transaction as finished.

      // Flag the invoice as paid.
      transactions[transactionId].paid = true;
      // Save the payers address so he is eligible to rate.
      transactions[transactionId].paidWithAddress = msg.sender;
    
      // -> Now the transaction can be rated by the address that has paid it.
    }

    // As a buyer, rate a transaction.
    function rate(uint transactionId, uint ratingValue, string ratingComment) {
      // Only the address that has paid the transaction may rate it.
      if(transactions[transactionId].paidWithAddress != msg.sender) { throw; }
      // Bail out in case the transaction id is invalid.        
      if(transactionId < 1 || transactionId >= transactions.length) { throw; }
      // Oops, transaction has already been rated!
      if(transactions[transactionId].rated) { throw; }
      // Oops, transaction has not been paid yet and cannot be rated!
      if(!transactions[transactionId].paid) { throw; }
      // Rating range is from 1 (incl.) to 10 (incl.).
      if(ratingValue < 1 || ratingValue > 10) { throw; }

      transactions[transactionId].ratingValue = ratingValue;
      transactions[transactionId].ratingComment = ratingComment;
      transactions[transactionId].rated = true;
      
      uint previousTransactionCount = sellers[transactions[transactionId].sellerId].transactionsRated;
      uint previousTransactionRatingSum = sellers[transactions[transactionId].sellerId].averageRating * previousTransactionCount;

      sellers[transactions[transactionId].sellerId].averageRating = (previousTransactionRatingSum + ratingValue) / (previousTransactionCount + 1);
      sellers[transactions[transactionId].sellerId].transactionsRated += 1;
    }
}