As part of my work at PopChest exploring new ways to help content creators using blockchain technologies I set up an experimental Revenue Share smart contract to automatically distribute funds among different beneficiaries in a trustless and transparent way.
It basically works by adding a number of members to the contract indicating their corresponding shares of participation, once the contract is deployed all the payments sent to it will increase the balance ready to be claimed by each of the beneficiaries in the proportion they own.
A contract that split payments to multiple parties can be used in different scenarios, a group of artists that want to set in advance how their proceeds will be distributed, affiliate programs where each party configures the fees and all the payments are sent to the contract, etc. As an added benefit it also gives every party a way to audit all the transactions going in and out.
Considering costs when programming
When you have programmable money and a distributed network that operates based on incentives you have a whole new dimension of decisions to make, it's not only about function, speed and security but also on who pays for what and the friction related to that.
One of the design decisions while building the contract was when to distribute the funds received. The problem is that every transaction that updates the state in Ethereum pay some fees to the network and that means as a developer that you can decide who pays this cost depending on what code is executed and when. I decided to avoid distributing payments as soon as they arrive to the contract, that would mean extra gas costs to the sender, I wanted to keep the payment part as standard as possible. Instead, as a beneficiary you send a claim transaction when you are ready to withdraw your balance which will calculate your take and send it to your account.
Another consideration about costs was that whenever you wanted to create a new Revenue Share contract with your own terms you had to deploy the whole code over and over. To avoid that, the contract is deployed once using a Factory Contract which provide a function to create a Revenue Share contract with the client's parameters.
Building something for humans
Then it was time to build a user interface to make the process of managing your contract easily, that means deploying a new contract, watching for changes in the balance and allowing the withdrawal of funds.
Some challenges and friction points when building for decentralization:
- Wallet: A vital component to participate on any app using a blockchain is the wallet. It holds the private keys to sign transactions on your behalf. This wallet can live in your browser, your mobile phone, a hardware wallet, even a piece of paper. Some services generate their own wallet when you visit them for the first time and store it encrypted on the local storage of the web browser. The empowerment of users having the choice of managing their own wallets and funds is a big change which require a great responsibility from each user on how to use and secure their keys. For convenience this app is currently using Metamask which provides a wallet as a browser extension which you can use across different sites.
- Transactions take time: Whenever you do a transaction on the blockchain you need to wait for it to be mined by the network which can take many seconds. Users are used to millisecond response times on the centralized web, it's important to show proper feedback while the action completes. This can be done different ways, from loading indicators, to queueing multiple actions in the background and letting the user to continue the interaction with the app. Some Dapps show the transaction hash broadcasted to the network as a way to provide a handle to monitor it on Etherscan in case of any trouble.
- Transactions cost Ether (money): As any transaction on the network pays some fees for it's computation it adds a new dimension to the development. Now you have to decide which actions to do on-chain or off-chain, which of them generate friction and to whom is best to assign this cost.
- Authentication: Blockchains are permissionless systems, you don't need to create an account on a centralized service to operate, typically your "account" is your public key and you prove you own your key by signing transactions with your private key. This is a concept very strange to most new users, it requires education as people get exposed to services using crypto. A service could optionally register users in a central database with metadata related to the public key like an avatar or profile. Authentication is not the same as Identity, if you need to prove that someone is some human being in particular there are some project working on this challenge like uPort and Civic.
- Handling exceptions: There are many exceptional conditions and confusion that can happen along the way, some of them related to Ethereum like out of gas exceptions, user rejecting to sign a transaction, timeouts, sending a transaction to a wrong address, no funds available, etc. I think a good designed UX should avoid users to make most of these mistakes, for instance disabling or hiding buttons if they shouldn't be available, reading the contract data and finding out if the action can be performed and preventively guiding the user in other directions.
- Network: When you build an app based on any blockchain whether be Bitcoin, Ethereum or other, there are typically multiple testing platforms called testnets apart from the mainnet or production blockchain. The app should state clearly in which network it's operating to avoid any confusion, however first-time users typically have a hard time understanding what this is all about even though most of the wallets let you select to which network to connect.
As we get more DApps in the open we will develop some standards and best practice on how to provide predictable and easy-to-use applications combining centralized with decentralized elements.