A Basic DApp Example: Auction DApp
In this section we will start building an example DApp, to explore the various decentralization tools. Our DApp will implement a decentralized auction.
The Auction DApp allows a user to register a “deed” token, which represents some unique asset, such as a house, a car, a trademark, etc. Once a token has been registered, the ownership of the token is transferred to the Auction DApp, allowing it to be listed for sale. The Auction DApp lists each of the registered tokens, allowing other users to place bids. During each auction, users can join a chat room created specifically for that auction. Once an auction is finalized, the deed token ownership is transferred to the winner of the auction.
The overall auction process can be seen in Auction DApp: A simple example auction DApp.
The main components of our Auction DApp are:
A smart contract implementing ERC721 non-fungible “deed” tokens (
DeedRepository
)A smart contract implementing an auction (AuctionRepository) to sell the deeds
A web frontend using the Vue/Vuetify JavaScript framework
The web3.js library to connect to Ethereum chains (via MetaMask or other clients)
A Swarm client, to store resources such as images
A Whisper client, to create per-auction chat rooms for all participants
Figure 2. Auction DApp: A simple example auction DApp
You can find the source code for the auction DApp in the book’s repository.
Auction DApp: Backend Smart Contracts
Our Auction DApp example is supported by two smart contracts that we need to deploy on an Ethereum blockchain in order to support the application: AuctionRepository
and DeedRepository.
Let’s start by looking at DeedRepository, shown in DeedRepository.sol: An ERC721 deed token for use in an auction. This contract is an ERC721-compatible non-fungible token (see [erc721]).
Example 1. DeedRepository.sol: An ERC721 deed token for use in an auction
link:code/auction_dapp/backend/contracts/DeedRepository.sol[]
As you can see, the DeedRepository contract is a straightforward implementation of an ERC721-compatible token.
Our Auction DApp uses the DeedRepository contract to issue and track tokens for each auction. The auction itself is orchestrated by the AuctionRepository contract. This contract is too long to include here in full, but AuctionRepository.sol: The main Auction DApp smart contract shows the main definition of the contract and data structures. The entire contract is available in the book’s GitHub repository.
Example 2. AuctionRepository.sol: The main Auction DApp smart contract
contract AuctionRepository {
// Array with all auctions
Auction[] public auctions;
// Mapping from auction index to user bids
mapping(uint256 => Bid[]) public auctionBids;
// Mapping from owner to a list of owned auctions
mapping(address => uint[]) public auctionOwner;
// Bid struct to hold bidder and amount
struct Bid {
address from;
uint256 amount;
}
// Auction struct which holds all the required info
struct Auction {
string name;
uint256 blockDeadline;
uint256 startPrice;
string metadata;
uint256 deedId;
address deedRepositoryAddress;
address owner;
bool active;
bool finalized;
}
The AuctionRepository contract manages all auctions with the following functions:
getCount()
getBidsCount(uint _auctionId)
getAuctionsOf(address _owner)
getCurrentBid(uint _auctionId)
getAuctionsCountOfOwner(address _owner)
getAuctionById(uint _auctionId)
createAuction(address _deedRepositoryAddress, uint256 _deedId,
string _auctionTitle, string _metadata, uint256 _startPrice,
uint _blockDeadline)
approveAndTransfer(address _from, address _to, address _deedRepositoryAddress,
uint256 _deedId)
cancelAuction(uint _auctionId)
finalizeAuction(uint _auctionId)
bidOnAuction(uint _auctionId)
You can deploy these contracts to the Ethereum blockchain of your choice (e.g., Ropsten) using Truffle in the book’s repository:
$ cd code/auction_dapp/backend
$ truffle init
$ truffle compile
$ truffle migrate --network ropsten
DApp governance
If you read through the two smart contracts of the Auction DApp you will notice something important: there is no special account or role that has special privileges over the DApp. Each auction has an owner with some special capabilities, but the Auction DApp itself has no privileged user.
This is a deliberate choice to decentralize the governance of the DApp and relinquish any control once it has been deployed. Some DApps, by comparison, have one or more privileged accounts with special capabilities, such as the ability to terminate the DApp contract, to override or change its configuration, or to “veto” certain operations. Usually, these governance functions are introduced in the DApp in order to avoid unknown problems that might arise due to a bug.
The issue of governance is a particularly difficult one to solve, as it represents a double-edged sword. On the one side, privileged accounts are dangerous; if compromised, they can subvert the security of the DApp. On the other side, without any privileged account, there are no recovery options if a bug is found. We have seen both of these risks manifest in Ethereum DApps. In the case of The DAO ([real_world_example_the_dao] and [ethereum_fork_history]), there were some privileged accounts called the “curators,” but they were very limited in their capabilities. Those accounts were not able to override the DAO attacker’s withdrawal of the funds. In a more recent case, the decentralized exchange Bancor experienced a massive theft because a privileged management account was compromised. Turns out, Bancor was not as decentralized as initially assumed.
When building a DApp, you have to decide if you want to make the smart contracts truly independent, launching them and then having no control, or create privileged accounts and run the risk of those being compromised. Either choice carries risk, but in the long run, true DApps cannot have specialized access for privileged accounts—that’s not decentralized.
Auction DApp: Frontend User Interface
Once the Auction DApp’s contracts are deployed, you can interact with them using your favorite JavaScript console and web3.js, or another web3 library. However, most users will need an easy-to-use interface. Our Auction DApp user interface is built using the Vue2/Vuetify JavaScript framework from Google.
You can find the user interface code in the code/auction_dapp/frontend folder in the book’s repository. The directory has the following structure and contents:
frontend/
|-- build
| |-- build.js
| |-- check-versions.js
| |-- logo.png
| |-- utils.js
| |-- vue-loader.conf.js
| |-- webpack.base.conf.js
| |-- webpack.dev.conf.js
| `-- webpack.prod.conf.js
|-- config
| |-- dev.env.js
| |-- index.js
| `-- prod.env.js
|-- index.html
|-- package.json
|-- package-lock.json
|-- README.md
|-- src
| |-- App.vue
| |-- components
| | |-- Auction.vue
| | `-- Home.vue
| |-- config.js
| |-- contracts
| | |-- AuctionRepository.json
| | `-- DeedRepository.json
| |-- main.js
| |-- models
| | |-- AuctionRepository.js
| | |-- ChatRoom.js
| | `-- DeedRepository.js
| `-- router
| `-- index.js
Once you have deployed the contracts, edit the frontend configuration in frontend/src/config.js and enter the addresses of the DeedRepository and AuctionRepository contracts, as deployed. The frontend application also needs access to an Ethereum node offering a JSON-RPC and WebSockets interface. Once you’ve configured the frontend, launch it with a web server on your local machine:
$ npm install
$ npm run dev
The Auction DApp frontend will launch and will be accessible via any web browser at http://localhost:8080.
If all goes well you should see the screen shown in Auction DApp user interface, which illustrates the Auction DApp running in a web browser.
Figure 3. Auction DApp user interface