This is a plasma based implementation of a decentralized exchange. In fact, this codebase is forked from Omisego's Minimum Viable Plasma implementation.
Plasma MVP DEX is split into three main parts: root_chain
, child_chain
, and webapp
. Below is an overview of each sub-project.
root_chain
represents the Plasma contract to be deployed to the root blockchain. In our case, this contract is written in Solidity and is designed to be deployed to Ethereum. This component also contains a standard ERC-20 token with a name of 'PDEX Token', which will be the only supported token to be traded on the demo plasma DEX.
root_chain
is built using a truffle project, and has deployment and test scripts within the project folder.
RootChain.sol
is based off of the Plasma design specified in Minimum Viable Plasma. Currently, this contract allows a single authority to publish child chain blocks to the root chain. This is not a permanent design and is intended to simplify development of more critical components in the short term.
PDEXToken.sol
is the ERC20 token. It uses Zeppelin's StandardToken implementation.
child_chain
is a Python implementation of a Plasma MVP DEX child chain client. It's useful to think of child_chain
as analogous to Parity or Geth. This component manages a store of Blocks
and Transactions
that are updated when events are fired in the root contract.
child_chain
also contains an RPC server that enables client interactions. By default, this server runs on port 8546
.
webapp
is a simple React web app that interacts with the root chain for deposits of eth or pdex token. It interacts with the child_chain for take_order and make_order requests.
This code has only been tested on an ubuntu 16.04 distrubution running within a VirtualBox Linux machine. Here are instructions to setup that type of machine:
- install virtual box
- create a 64-bit linux virtual machine (memory set to 4GB and hard disk set to 10 GB)
- set the virtual machine's network adapter to be attached to a bridged adaptor (this is to enable the host machine to be able to navigate to my dapp that will be running within the virtual machine)
- start the virtual machine with the ubuntu iso: ubuntu-16.04.5-desktop-amd64.iso (can be retrieved here: http://releases.ubuntu.com/16.04/)
This repository has scripts that will install nearly all of the linux, npm, and python packages. However, the user will need to install a few packages manually before being able to use those scripts. Here are the manual steps the user must first run after the ubuntu machine is created:
- update apt-get 'sudo apt-get update'
- run the command 'sudo apt-get install -y git' to install git
- within your home directory, run 'git clone https://github.com/kevjue/plasma-dex' to clone this repo.
- run the command 'sudo sh ~/plasma-dex/scripts/install_packages.sh' to install all remaining dependencies.
The root chain can be run using ganache-cli. Once ganache-cli is started, then the smart contracts can be deployed to it using the root_chain's truffle migration scripts. Here are the commands to install and start the root chain:
- Start ganache by running the command 'sh ~/plasma-dex/scripts/startGanache.sh'
- Deploy the smart contracts onto ganache by running the command 'sh ~/plasma-dex/scripts/deploy_root_chain.sh' in a new window.
- Make sure to note address for the deployed PDEXToken and RootChain smart contracts. You will need to use them for later steps.
The child chain can be installed and started with the following command:
- start the child chain by running the command 'sh ~/plasma-dex/scripts/run_child_chain.sh
<pdex token address>
<root chain address>
' (e.g. 'sh ~/plasma-dex/scripts/run_child_chain.sh 0x0c561ff0432605518f3f289d7c236c58e01158ef 0x511c8d42b25955dc5cf7e14c2413aa73a54711a8')
The web app can be installed and started with the following command:
- in a new terminal, start the dapp web app with the command 'sudo sh ~/plasma-dex/scripts/run_web_server.sh
<pdex token address>
<root chain address>
' (e.g. 'sudo sh ~/plasma-dex/scripts/run_web_server.sh 0x0c561ff0432605518f3f289d7c236c58e01158ef 0x511c8d42b25955dc5cf7e14c2413aa73a54711a8')
The DEX can be accessed via a chrome brower with the metamask extension installed. To load the DEX, execute the following commands:
- Load chrome with metamask installed. In metamask, set the network to the ganache instance running in your virtual machine (e.g. with the endpoint as http://
<ip address of virtual machine>
:8545 - Navigate to http://
<ip address of virtual machine>
Let's play around a bit:
- The above installation scripts already pre-seeded the account with private key (816ac2ffeb67d3ad96883329601848101795574bf8a47f140519666e7004919a) with some eth. You should import this private key into your metamask. Once you imported the private key, you should see some eth within your wallet.
- You can deposit some eth into the exchange to purchase some tokens. Start by depositing 50 Eth. Once the eth is deposited, then you should see your account eth balance set to 50 and your wallet balance slightly below 50 (for the gas used the deposit transaction).
- You can purchase tokens from the order book, and subsequently sell any purchased tokens. Note that any submitted orders to the exchange will need to be "mined" before that order shows up in the order book and your exchange balance is updated accordingly. It takes about 1 minute for the order to be "mined".
- You could try loading another account with metamask, and then interact with the exchange using that account. Note that you will have to transfer some ether and/or tokens to that new account, if you want to make or take any orders with the new account.
The root chain code is located in the directory plasma-dex/plasma/root_chain. It is a truffle project with the solidity code located in the subdirectory contracts.
The root chain smart contract is defined in the file contracts/RootChain.sol.
The pdex token smart contract is defined in the file contracts/PDEXToken.sol.
The child chain code is located in the direcotry plasma-dex/plasma/child_chain. It is implmented in python. The main child chain code is defined in the file child_chain.py
The web app code is located in the directory plasma-dex/plasma/webapp. It is a react based web app. The main code is defined in the file src/App.js.
Test cases were built for the root chain and pdex token smart contracts. Those tests are located in the directory plasma-dex/plasma/root_chain/test.
The tests for the PDEX token verified the following:
- The deployed token metadata is correct.
- The initial token allocation is correct.
- Transferring of tokens works
- Allowance of tokens (and then subsequent tranferFrom) works.
The above functionality was tested since they are required to be compatible with the plasma DEX.
The tests for the root chain verified the following:
- Testing for eth and PDEX Token deposits
- Testing for eth and PDEX Token exits
- Testing for erroneous eth and pdex token exits
The above functionality was tested since they are the base requirement for the root chain smart contract.
There are three types of child chain transactions: 1) transfer eth or tokens from one address to another, 2) creating of a token sell order, 3) taking of an outstanding token sell order.
Each UTXO has the following fields:
- utxo type - The type of utxo. Possible values are 'transfer' or 'make order'. 'Transfer' types are the standard transferring of eth or tokens to another address.
- address of new owner - The address of the new owner.
- amount - The amount of eth/tokens to transfer.
- tokenprice - This field is only used for 'make order' utxos. It will be ignored for 'transfer' utxos. The price (in wei) of each token put up for sale.
- currency - The address of the token. Is the zero address if the currency is ether. This field should NEVER be set to ether for 'make order' utxos.
Right now, all transactions have a hard coded number of max inputs and max outputs.
There can be up to two inputs and up to four outputs. Details of each transaction type is described below.
For transfer transactions, the following conditions must be true:
- All input and output utxos are type 'transfer'.
- All input and output utxos have the same 'currency'.
- The sum of the input amounts must be greater or equal than the sum of the output amounts.
Here's a sample transfer transaction where 2 eth UTXOs owned by 0x1 is transferred to 0x2:
inputs: ['transfer', 0x1, 5, 0, 0x0], ['transfer', 0x1, 10, 0, 0x0]
outputs: ['transfer', 0x2, 15, 0, 0x0]
For the make order transactions, the following conditions must be true:
- All input utxos are type 'transfer'.
- At least one of the output utxos is the type 'make order'
- All the input and output utxos have the same currency.
- The sum of the input amounts must be greater or equal than the sum of the output amounts.
Here's a sample make order transaction where 1 token UTXO owned by 0x1 is transformed into one make order UTXO and one change utxo.
inputs: ['transfer', 0x1, 10, 0, 0x10]
outputs: ['make order', 0x1, 5, 100, 0x10], ['transfer', 0x1, 5, 0, 0x10]
For the take order transactions, the following conditions must be true:
- There must be exactly 1 'make order' utxo and 1 'transfer' utxo for the inputs.
- The input 'transfer' utxo must be ETH currency.
- There must be 1 output token transfer to the taker such that the amount is less than or equal to the input 'make order's amount. This utxo specifies how many tokens the taker wants to purchase.
- There must be 1 output eth transfer to the maker where the amount of eth transferred is equal to the amount in 3) and the token price in the input make order.
- If the input 'make order' is not fully taken, then there must be a remainder 'make order' for the unsold tokens. The owner of the remainder make order must equal to the owner of the input 'make order'.
- There may be a remainder eth order where the amount is no greater than the amount in 2) minus the amount in 4).
Here's a sample take order transaction where the maker is 0x1 and the taker is 0x2. The taker is planning to purchase 2 tokens.
inputs: ['make order', 0x1, 5, 100, 0x10], ['transfer', 0x2, 200, 0, 0x0]
outputs: ['transfer', 0x2, 2, 0, 0x10] ['transfer', 0x1, 200, 0, 0x0], ['make order', 0x1, 3, 100, 0x10]