IDEX 2.0 smart contracts
Smart Contracts
Overview
This repo collects source code, tests, and documentation for the IDEX Whistler release Ethereum contracts.
Install
Download and install nvm, yarn, and python3. Then:
pip3 install slither-analyzer
Usage
This repo is setup as a Truffle project, with library and test code written in Typescript. To build:
nvm use
yarn && yarn build
To run test suite, generate coverage report, and perform static analysis:
yarn coverage
yarn analyze
Background
IDEX is in development on a series of major product releases that together comprise IDEX 2.0.
- Release 1 (Whistler): The Whistler release contains all of the off-chain upgrades of IDEX 2.0, including new web and
- Release 2 (Peak2Peak): An original layer-2 scaling solution, known as Optimized Optimistic Rollup (O2R), is part of
- Release 3 (Blackcomb): The Blackcomb release switches settlement and balance tracking from the Whistler contracts to
Contract Structure
The Whistler on-chain infrastructure includes three main contracts and a host of supporting libraries.
- Custodian: custodies user funds with minimal additional logic.
- Governance: implements upgrade logic while enforcing governance constraints.
- Exchange: implements the majority of exchange functionality, including wallet asset balance tracking.
User Interaction Lifecycle
Whistler supports trading Ethereum and ERC-20 tokens, and requires users to deposit Eth and tokens into the Whistler smart contracts before trading. The interaction lifecycle spans three steps.
Deposit
Users must deposit funds into the Whistler contracts before they are available for trading on IDEX. Depositing ETH requires calling depositEther on the Exchange contract; depositing tokens requires an approve call on the token itself before calling depositTokenByAddress on the Exchange contract.
- The
depositEtheranddepositTokenByAddressare functions on the Exchange contract, but the funds are ultimately
- Deposits are only allowed for registered tokens.
- Deposit amounts are adjusted to IDEX 2.0’s normalized precision design to prevent depositing
- Deposits from exited wallets are rejected.
Trade
In Whistler, all order management and trade matching happens off-chain while trades are ultimately settled on-chain. A trade is considered settled when the Exchange contract’s wallet asset balances reflect the new values agreed to in the trade. Exchange’s executeTrade function is responsible for settling trades.
- Unlike deposits, trade settlement can only be initiated via a whitelisted Dispatch wallet controlled by IDEX. Users do
- The primary responsibility of the trade function is order and trade validation. In the case that IDEX off-chain
- Due to business requirements, orders are specified by symbol, eg “UBT-ETH” rather than by token contract addresses.
trade
parameter to the executeTrade function includes the symbol strings separately. This is a gas optimization to order
signature verification as string concat is cheaper than split.
- Due to business requirements, order quantity and price are specified as strings in
- IDEX 2.0 supports partial fills on orders, which requires additional bookkeeping to prevent overfills and replays.
- Fees are assessed as part of trade settlement. The off-chain trading engine computes fees, but the trade function is
Withdraw
Similar to trade settlement, withdrawals are initiated by users via IDEX’s off-chain components, but calls to the Exchange contract’s withdraw function are restricted to whitelisted Dispatch wallets. withdraw calls are limited to the Dispatch wallet in order to guarantee the balance update sequence and thus support trading ahead of settlement. There is also a wallet exit mechanism to prevent withdrawal censorship by IDEX.
- Withdrawals may be requested by asset symbol or by token contract address. Withdrawal by asset symbol is the standard
- IDEX collects fees on withdrawals in order to cover the gas costs of the
withdrawfunction call. Because only an
withdraw call, IDEX is the immediate gas payer for user withdrawals.
IDEX passes along the estimated gas costs to users by collecting a fee out of the withdrawn amount.
- Despite the
withdrawfunction being part of the Exchange contract, funds are returned to the user’s wallet from the
Upgradability
Upon the Whistler release, IDEX users must withdraw funds from the IDEX 1.0 contract and deposit funds into the Whistler contract to continue trading. For an improved UX going forward, Whistler’s contracts include upgrade logic that enables the rollout of the subsequent Blackcomb release without requiring users to withdraw and redeposit funds into a new Custody contract. The upgrade logic is minimalist by design.
- The Custody contract tracks the Governance contract and Exchange contract. The Governance contract is the only actor
- Exchange state data is stored in the Exchange contract itself. Because state data, such as wallet asset balances, is
- The anticipated target of the upgrade is the Blackcomb release’s O2R layer-2 system, where the Exchange state data will
Controls and Governance
The Whistler controls and governance design is captured in its own spec.
Additional Mechanics
Token Symbol Registry
Business rules require orders to be specified in asset symbol terms rather than token contract address terms. For example, an order specifies the market as "UBT-ETH" rather than { "base": "0xb705268213d593b8fd88d3fdeff93aff5cbdcfae", "quote": "0x0" }. Deposits, withdrawals and asset balance tracking, however, must be implemented in token contract address terms. In order to support both usage modes, Whistler includes a token registry that maps symbols to token contract addresses along with additional token metadata, such as precision. Only registered tokens are accepted for deposit.
- Token registration is a two-transaction process, requiring separate calls to
registerTokenandconfirmTokenRegistration.
- Occasionally projects upgrade their token address via a token swap but need to retain the same trading symbol. To
Precision and Pips
In its off-chain components, IDEX 2.0 normalizes all assets to a maximum of 8 decimals of precision, with 1e-8 referred to as a "pip". Because deposit and withdrawals must account for the true token precision, however, the token registry includes token decimals as well as functions to convert pipsToAssetUnits and assetUnitsToPips. All wallet asset balances are tracked in pips.
Nonces and Invalidation
Orders include nonces to prevent replay attacks. IDEX 2.0 uses version-1 UUIDs) as nonces, which include a timestamp as part of the value.
IDEX’s hybrid off-chain/on-chain architecture is vulnerable to a cancelled-order submission attack if the off-chain components are compromised. In this scenario, an attacker gains access to the Dispatch wallet and a set of cancelled orders by compromising the off-chain order book. Because the orders themselves include valid signatures from the placing wallet, the Whistler contract cannot distinguish between active orders placed by users and those the user has since cancelled.
Nonce invalidation via invalidateOrderNonce allows users to invalidate all orders prior to a specified nonce, making it impossible to submit those orders in a subsequent cancelled-order submission attack. The controls and governance spec covers the exact mechanics and parameters of the mechanism.
Wallet Exits
Whistler includes a wallet exit mechanism, which allows users to withdraw funds in the case IDEX is offline or maliciously censoring withdrawals. Calling exitWallet initiates the exit process, which prevents the wallet from subsequent deposits, trades, or normal withdrawals. Wallet exits are a two-step process as defined in controls.
License
The IDEX Whistler Smart Contracts and related code are released under the GNU Lesser General Public License v3.0.