Enclaves DEX launched around 6weeks ago, and since then we’ve seen a great response from the community, with more than 10,500 transactions and around 1,100 ETH being traded through the DEX contract.

Being a decentralised exchange, Enclaves heavily relies on smart contracts running on the Ethereum network to facilitate trading in utility tokens. These smart contracts are at the core of our business, and include some clever functionality to allow trading through multiple liquidity providers, upgradability, pay-by-token mechanics, typed signing of limit orders and lots more.

Smart Contract Overview

There are three main components to the Enclaves DEX smart contracts.

Enclaves DEX Proxy

This is the contract with which users interact, and holds ETH and token balances on behalf of users.

Enclaves DEX Library

This is the contract which defines the logic for trading and other interaction with the Enclaves DEX Proxy contract, and is upgradable.

Enclaves DEX Storage

This is the contract which allows extendable storage, should an upgraded Enclaves DEX Library contract every require it.

Upgradable Contracts

One of the advantages of using a public ledger and blockchain for a decentralised exchange is that it offers immutability guarantees to users. This means that the owner of the DEX contract can not arbitrarily change the logic (for example allowing the owner to withdraw all deposited funds) and so users have confidence about leaving their funds on the contract without needing to check the logic hasn’t changed each time they use the contract.

On the downside this means that upgrading contracts is tougher, both technically, and also in terms of the best practice from a community perspective. As a developer of a DEX I would like the ability to add new features to our DEX contract (for example integrating 0x liquidity) but also very aware that users of the DEX contract will reasonably want some guarantees that I can’t do this entirely arbitrarily with no constraints (to avoid possible bad actors modifying the contract to steal funds).

There are several approaches I’ve seen to this problem, including:

disallowing all upgrades (e.g. EtherDelta DEX contract)

allowing contracts to be upgraded based on a community vote

allow contracts to be upgraded, but users must opt in to use the new contract

a time based restriction whereby an upgrade can be proposed by the contract owner, but only switched over after a period of time has passed.

At Enclaves, we went with the last option. The contract owner (e.g. Enclaves) can propose an upgraded contract, with a two week time delay. This means if any users are uncomfortable with the new proposed contract (which would be specified by the upgraded contracts Ethereum address on mainnet) they would have two weeks to withdraw any funds they held on the old contract.

In practice, along with the two week time delay, the following are also important processes to follow:

announcement of new proposed upgraded contract on the usual social media channels — whilst the proposal is visible on the blockchain, it is good practice to also announce this as widely as possible.

any new contract should be audited, possibly with a bug bounty running on it before during the two week delay period.

This has the advantage that for most users, and upgrade is a non-event, but for those users who are more technically inclined there is an open and transparent process which provides users an option to not trust an upgrade and remove any risk to the upgraded contract.

To upgrade a contract, we follow the Proxy / Library / Storage design, heavily inspired by this article.

This means that the Proxy contract is never changed, and stores Ether and token balances, whilst all business logic is forwarded by a delegatecall method to an underlying Library contract that can be modified.

The reason to introduce a Storage contract (e.g. KeyValueStorage ) is that one of the constraints on using delegatecall is that the contract to which calls are forwarded, should have identical storage to the forwarding contract. In our first implementation of the Enclaves DEX Library contract, this is straightforward as we simply copy the storage layout from the Enclaves DEX Proxy contract, but for any future upgrade we wanted the ability to add additional storage if needed, and having both the Enclaves DEX Proxy and Enclaves DEX Library contract inherit from a KeyValueStorage storage contract provides this facility.

Signing typed data (aka EIP712)

In many DEXs, in order to enter into a limit order (where you agree to buy or sell tokens at a specified price) you need to sign some data that corresponds to the order (for more details on this see this article).

Until fairly recently, signing data in MetaMask involved a call to eth_sign which would pop up a MetaMask dialog box, allowing the user to sign some fairly random looking hex data. This has some serious security concerns (as you can see from the corresponding MetaMask warning) as it is possible you may be signing something which you don’t actually want to.

A scary MetaMask signing dialog

There have been various approaches to improve the situation, with EIP712 (supported by MetaMask) allowing users to sign typed data displayed in a human readable format via a call to eth_signTypedData . This is much less scary!

A nice, human readable and less scary MetaMask dialog

Some concerns with this EIP, as evidenced in the GitHub thread for this, are that it is not currently supported across the board, and the specification is still being actively discussed. As an example, this is not currently supported by hardware wallets, so supporting those, as well as typed signing in MetaMask means having two signature verification routines in your smart contract.

Pay By Token (aka EIP865)

ERC20 vs. Ether

One of the frustrations with DEXs and dApps in general, is that users need Ether in their accounts before they can submit a transaction to the network in order to pay for the corresponding gas.

For DEXs this can be particularly frustrating as a user may have Ether or tokens held in the DEX contract, but not in their MetaMask account, and therefore be unable to withdraw their Ether or tokens back to their MetaMask account!

One solution to this problem is to allow the user to pay for transactions with either tokens or Ether, which is held under their Ethereum address in the DEX contract. In practice this works by having the user sign some data which attests to their willingness to pay a certain amount of tokens or Ether for someone else to execute a transaction on their behalf (for example withdrawing tokens from Enclaves DEX).

For Enclaves, we have initially implemented this only for withdrawals, not for trading or other contract functionality, but in future upgraded contracts we will look at extending this to cover more cases.

More Smarts

These are not the only smart parts of our contracts, we also have some clever functionality to allow seamless trading through other liquidity providers, and allow trades to occur without tokens or Ether ever needing to be deposited to our contracts.

One other point to note is that at Enclaves we don’t believe in punishing users who submit transactions that fail (which is often out of users control, if for example a transaction is valid at the point where it is submitted, but invalid by the time it is mined). Throughout our code we use revert rather than assert when there are failure conditions, including when checking for overflow conditions. This means that failed transactions will refund any unused gas, rather than consuming it. This also applies for trades which are passed through to our liquidity providers (e.g. EtherDelta) providing a safe, and failure tolerant trading experience!

Feedback

We would love to hear any feedback on the exchange, please contact us at any of e-mail, Telegram, Reddit, Slack!

Please note that Enclaves DEX should be used only for trading utility tokens, and any use is entirely at your own risk. Enclaves DEX is not responsible for any losses made from trading tokens, or using our smart contract. See https://enclaves.io/ for full disclaimer.