An Ethereum Dapp Case Study
Decentralized applications (Dapps) are applications without a centralized owner. You may have heard of Bitcoin or Ethereum, maybe even Augur or IPFS. They are all examples of Dapps. I will not go into why Dapps are useful, you can go to Google or Medium and do a quick search. This post is about my experience building our first end-to-end Dapp — AuctionHouse with Doug Petkanics.
AuctionHouse is a decentralized auction platform for any on-chain non-fungable asset. It’s decentralized because the business logic is an Ethereum smart contract. For people familiar with web development, there is no “server-side” code except for the smart contract that’s written by us and deployed/ran on the global Ethereum network. Any digital asset that implements the “Asset.sol” prototype can be auctioned off on the platform. An example here could be a registered name on the Ethereum Name Service (think of it as a domain name), or the ownership of another smart contract that generates revenue.
AuctionHouse is a straightforward auction app that allow users to create auctions and bid on active auctions. The application largely works like this:
- The user initiates a transaction (in Ethereum-speak, any state-changing command is a transaction). For example, create a new auction.
- Browser signs the transaction with the user’s private key stored in an Ethereum wallet. This step requires an additional piece of client-side software, usually an Ethereum wallet. The Ethereum wallet manages the user’s private key so you can prove that you have enough Ethers to place a bid. We use MetaMask. (more on MetaMask later)
- The transaction gets put onto the Ethereum blockchain. This can be a locally blockchain or a hosted blockchain. (An example of a hosted blockchain is Infura)
- The transaction gets confirmed by the network, and we can read the result after.
It’s very similar to how a web application works, except the “service-side” is replaced by the blockchain, which talks to the client-side code with help from the Ethereum wallet.
Building for Ethereum means utilizing a new set of tools. We used the following tools in our development:
Software frameworks make development easier — and it’s especially true for Ethereum. We tried both Dapple and Truffle, and decided to go with Truffle. It’s a fast-changing framework, but the Consensys folks do a great job helping the community. They have a great gitter room with people eager to answer questions. P.s — we learned about Embark after we made our decision already. But from what I can tell, it’s very similar to Truffle. Congrats to both teams for making awesome tools!
Testrpc is your friend when developing Dapps. Since there the smart contract needs to run on the Ethereum blockchain, you will need a local dev environment that runs an Ethereum blockchain. The TestRPC project is a stub of the Ethereum blockchain with lots of dev/test friendly features.
Awesome Chrome plugin that functions as your Ethereum wallet. It manages your keys, allows you to switch between your local/testnet/mainnet, and does transaction signing through the browser (otherwise, you would have to download a Dapp special browser like Mist to use ANY Dapp).
Local Development / Testing
We are big believers in test-driven development. If tests are important for web development, it becomes essential for smart contracts. Security is of the utmost importance, and writing tests is a great way to make sure your smart contracts are secure. Truffle provides a testing framework built on top of Chai. The TestRPC provides a relatively fast environment to run your tests, though you have to restart it sometimes to reset stats like account balance. The biggest pain point comes from exception handling. If the smart contract throws an exception, you cannot easily catch it in the test code — the test suite simply stops running. This means you cannot test any exception cases, and leaves potential bugs / security holes in the code. Another annoyance is that, since transactions require gas, you have to remember to fetch the gas usage and add it to the end result if your test condition depends on the account balance.
While TestRPC is great for development, we found the additional step of testing on a local Geth node gave us more confidence. Running a local Geth node isn’t that hard, but you should be aware of the security concerns like unlocking accounts before doing it. You can read more about it here.
One annoyance with local testing is the changing contract address every time you do a migration, especially if you are collaborating with someone else. We ended up using Fieldbook as a easily configurable registry, and used different network IDs on our local host so we can just change the address in a web UI and load it dynamically into the front-end code.
Truffle gives you a great way to deploy to the TestNet. You can simply run a local Geth node that syncs with the TestNet, and run ‘truffle migrate’. Make sure you record the addresses of the deployed contracts because you will need to refer to them in your front-end code.
Once you deploy to TestNet, you should consider going to Etherscan and verify your contract.
The front-end code can be deployed in a few different ways. The most decentralized deployment method is through IPFS. It’s a decentralized file storage system that also functions as a CDN. However, we tried to do this with only limited success. You can only ‘write’ (there is no ‘delete’), and the content takes a long time to propagate through the network. We ended up choosing the more centralized approach of deploying to S3 for now. We’d love to give IPFS another try as it becomes more mature.
Security is a huge topic in smart contract development. Our biggest learning developing AuctionHouse was to switch from a “send” model to a “withdraw” model. This is because addresses on Ethereum can be both users and contracts. A malicious user can make a bid, and cause the “send” action to her address to fail every time. This effectively blocks everyone else from making a bid. The fix to this problem is to change to a “withdraw” model, where the contract simply keeps track of the accounting and wait for users to initiate the “withdraw”.
Another good idea is to put in a “maintenance mode” flag which pauses any action to the contract. Many other security concerns are listed out here, I highly recommend everyone to give it a read before deploying your smart contract.
Ethereum programming feels like hardware or financial services programming. The cost of failure is high, and you have to be very careful about the decisions you make. You have to be defensive, assuming every external call can fail. Finally, you should only use the blockchain for parts of the app that absolutely require decentralization. This can help simplify your smart contract reduce security risk.
I recommend these articles if you want to dig in further.
- Tips for a New Ethereum Dapp Developer by Doug Petkanics
- A 101 Noob Intro to Programming Smart Contracts on Ethereum by Consensys
- App Coins and the dawn of the Decentralized Business Model by Fred Ehrsam