LogoLogo
  • WELCOME TO ALEPH ZERO
  • EXPLORE
    • About Aleph Zero
    • AlephBFT Consensus
    • The Economy of Aleph Zero
    • Where to Buy AZERO
    • Decentralized Governance on Aleph Zero
    • Ecosystem
    • Aleph Zero Foundation Treasury Management
    • Community
    • Glossary
    • Audit & Research Papers
  • USE
    • Wallets
    • Explorer
    • Ledger
    • Telegram Notifications
    • Aleph Zero Signer
      • General introduction
      • What does Signer do?
      • What are Sub-accounts and Sub-account paths?
      • Why is it critical to store your Secret Phrase in a safe place?
      • How to forget and restore accounts?
      • What are Networks?
      • What are Trusted apps?
    • Dashboard
      • Dashboard basics
      • Overview
    • Stake
      • Staking Basics
      • Staking Menu Overview
      • How to Start Staking with the Aleph Zero Dashboard
      • How to Start Staking With the Developer Wallet
      • How to start staking using Ledger hardware wallet
      • How to Change Nominations
      • How to Stop Staking
      • Staking Rewards
      • Validators
      • Commission and Foundation Nodes
      • Proxy Accounts
    • Validate
      • Validating Overview
      • Hardware requirements
      • Running an Aleph Node on Testnet
        • Downloading and running the node
        • Verifying your setup
        • Customizing your setup
        • Building and running from source [advanced]
          • Building from source
          • Set environment variables
          • Download DB snapshot
          • Running the binary
        • Appendix: Ports, addresses, validators, and archivists
      • Running an Aleph Node on Mainnet
        • Running the node
        • Building and running from source [advanced]
      • Setting your identity
      • Making the node validate
      • Securing your validator
      • Troubleshooting
      • Elections and Rewards Math
      • Testnet Validator Airdrop
      • Foundation Nomination Program
    • Using the EVM-layer
    • Governance
      • Token
      • Multisig Accounts
  • BUILD
    • Aleph Zero smart contracts basics
      • Setting up a Testnet account
      • Installing required tools
      • Creating your first contract
      • Deploying your contract to Aleph Zero Testnet
      • Extending your contract
    • Cross contract calls
      • Using references
      • Using dynamic calls
    • Migrating from Solidity
    • Writing e2e tests with ink-wrapper
    • Aleph Zero Signer integration
    • Front-end app: smart contract interaction
    • Security Course by Kudelski Security
      • ink! Developers Security Guideline
      • Lesson 1 - Getting started with ink!
      • Lesson 2 - Threat Assessment
      • Lesson 3 - Integer Overflow
      • Lesson 4 - Signed-integer
      • Lesson 5 - Role-Based Access Control
      • Lesson 6 - Address Validation
      • Lesson 7 - Smart Contract Control
    • Development on EVM-layer
  • PROTOCOL DETAILS
    • Shielder
      • Overview
      • Design against Bad Actors
      • Preliminaries - ZK-relations
      • Notes and Accounts
      • ZK-ID and Registrars
      • Anonymity Revokers
      • PoW Anonymity Revoking
      • Relayers
      • Deterministic Secret Management
      • SNARK-friendly Symmetric Encryption
      • SNARK-friendly Asymmetric Encryption
      • Cryptography
      • Token shortlist
      • User Wallet
      • Versioning
      • PoC
      • Version 0.1.0
      • Version 0.2.0
    • Common DEX
      • Common Whitepaper - Differences
      • Dutch Auctions
  • FAQ
  • Tutorials
    • Withdrawing coins from exchanges
      • How to withdraw your AZERO coins from KuCoin
      • How to withdraw your AZERO coins from MEXC Global
      • How to withdraw your AZERO coins from HTX
  • Setting up or restoring a wallet
    • How to set up or recover your AZERO account using Aleph Zero Signer
    • How to set up or recover your AZERO account using the official mainnet web wallet
    • How to set up or recover your AZERO account using Nova Wallet
    • How to set up or recover your AZERO account using SubWallet
    • How to set up or recover your AZERO account using Talisman
  • Staking
    • How to stake via a direct nomination using the Aleph Zero Dashboard
    • How to stake via a nomination pool using the Aleph Zero Dashboard
    • How to destroy a nomination pool via the Aleph Zero Dashboard
Powered by GitBook
On this page
  • High Level Overview
  • Traditional Limit Orders
  • On-chain "Dutch" Orders
  • Details of Dutch Orders
  • Creating Orders
  • Filling Orders
  • Cancelling Orders
  • Fees
  • Incentives for Fillers

Was this helpful?

  1. PROTOCOL DETAILS
  2. Common DEX

Dutch Auctions

Generalized Order Book

Common implements a fully on-chain order book, where each order is, in a sense, a separate dutch auction (or even more general, see the details below).

High Level Overview

Traditional Limit Orders

In a traditional order book, the user typically submits a LimitOrder having the following parameters:

  • token_in - token the user wants to sell

  • token_out - token the user wants to buy

  • amount_in - how many tokens user wants to sell

  • price - determines how many tokens user wants to buy, specifically, the want at least price*amount_in tokens of type token_out.

Such an order sits in the order book until matched by a matching engine. Matching happens against orders in the opposite direction. Orders are matched if they are "crossing", i.e., when both price constraints can be satisfied at the same time. The price at which the trade is executed depends on the matching engine. Orders can be matched partially. Typically some kind of fee is deducted after a trade happens.

On-chain "Dutch" Orders

A Dutch auction is an auction mechanism for selling an asset, in which an initial price p_start is selected for the auctioned item, and then, as the auction progresses, the price gradually decreases, little by little. At the moment when a buyer is satisfied by the current price, they bid, and win the auction right away, paying the current price for the item. Assuming that the initial price p_start was set correctly (higher than what's the item worth) then the auction finishes with the item being sold at an optimal price.

Common uses the Dutch auction mechanism to implement generalized limit orders. Roughly speaking, if the user has some token_in asset and they want to sell amount_in of them for token_out asset, then they can set some initial price p_start and limit price p_stop and let the tokens be traded over some time, at the price varying linearly between p_start and p_stop over a selected time segment. Of course, it is natural to set p_start to be a price that is higher than the current stop market price, so that the auction achieves its goal of trading the assets at a price favorable to the user.

The order book consists then of a set of "living" orders – orders whose prices change in time.

Orders are matched not via a centralized matching engine but via a permissionless group of "fillers" who are actors who can fill one or more orders at the same time. Fillers compete with each other to make profit from arbitrage opportunities.

Details of Dutch Orders

Creating Orders

To create an order user sends the following transaction

fn create_order(token_in, token_out, amount_in, price_curve, expiration_time) {...}

Where token_in, token_out, amount_in are self-explanatory, and:

  • price_curve is a function that takes timestamp as an argument and outputs a price that is acceptable for this order at this time. For instance:

    • For limit orders we have price_curve(t) = const

    • For dutch auctions we have price_curve(t) = ((t1 - t)p1 + (t-t2)p2)/(t1-t2) i.e., a linear function with a specific timestamp t1, t2 and price p1, p2 parameters

    • We could have more general price curves too, for instance exponential, which would be useful for price discovery of very exotic tokens.

  • expiration_time is a timestamp when the order is automatically cancelled. It can be set to infty in order to make the order live till being filled, or manually canceled.

As a result, an order, with a unique order_id is created and stored in the contract.

Note that as part of the create_order transaction, the user locks amount_in tokens token_in in the order book contract.

Filling Orders

To fill an order or multiple orders one uses the following contract call:

fn fill(order_ids: Vec<OrderId>, executor_contract: Address) {
    let orders = {order[order_id] for order_id in order_ids}
    let prices = current prices of orders;
    for order in orders {
        transfer order.amount_in of order.token_in to executor_contract;
    }
    // The results array contains info on what amount of which order was filled
    let results = executor_contract.execute(orders, prices);
    
    Validate results (details below) 
    // Validate that the executor_contract transferred enough token_in and token_out 
    // for each order. Specifically:
    // 1. >= (amount_in-filled) of token_in
    // 2. >= (amount_in-filled)*price of token_out.
    // If validation fails, rollback.
    
    Update orders to take into account filled amounts.
}

Note that the above requires developing an executor contract, so it is expected to be used by a professional filler only. A simplified call for casual traders will be also provided to make it simpler.

The fill method can be logically split into 3 steps:

  1. Send input funds to the executor_contract

  2. Execute a callback by the executor_contract

  3. Receive the swapped funds from the executor_contract

There are a few reasons why the proposed implementation of fill (based on steps 1. 2. 3. as above) is convenient for the fillers:

  • When creating a transaction, the filler cannot predict: 1) if some of the orders they try to fill will not get filled (partially) before the transaction lands on chain, 2) what will be the timestamp of the block their transaction is included. This implies that the filler doesn't know the final amounts of the order and the price at which it will be executed. That's why the execute call includes both orders and prices and is expected to make the final decision on what to trade and how.

  • In case when an order is filled, or the price is not the expected one, the execute method can simply abort, in order to rollback the transaction.

  • Thanks to the fact that the step 1. happens before 3. it is possible for the filler to fill orders without any liquidity held by the filler. Specifically, fill is a variant of a flash-loan. What the filler can do for instance is:

    • Fill one order by trading it against an AMM

    • Fill two orders by trading them against each other.

    • Any combination of these, as long as it's atomic.

Cancelling Orders

Orders can be cancelled at any time by the user who submitted them, in which case they get a full refund on what remains untraded (token_in) + the amount in token_out that was traded.

Fees

Incentives for Fillers

PreviousCommon Whitepaper - DifferencesNextFAQ

Last updated 10 months ago

Was this helpful?