Mangrove
Developper
Developper
  • Welcome
  • Protocol
    • Introduction
    • Technical References
      • Overview
      • Ticks, ratios, and prices
      • Offer-list
        • Views on offers
      • Market-order
        • Delegation
      • Creating & Updating offers
        • Maker contract
        • Offer provisions
        • Gas requirement
        • Public data structures
        • Executing offers
      • Cleaning offers
      • Governance-parameters
        • Global variables
        • Local variables
        • Data structures and views
      • Periphery Contracts
        • MgvReader
        • MgvOracle
      • Literate Source Code
    • Background
      • Taking available liquidity
      • Making liquidity available
      • Reneging on offers
  • Strat Lib
    • What is the Strat Library?
    • Getting-started
      • Set Up Your Local Environment
      • Post a Smart Offer
    • Guides
      • Unlocking liquidity
      • Reposting an offer in the posthook
      • Using last look to renege trades
      • Determining gas requirements
      • Creating a Direct contract
      • Deploying your contract
      • Testing a maker contract
      • Safe offer logic guidelines
      • Approvals
    • Technical references
      • Principal hooks
      • Liquidity routing
      • API preferences
        • Core
          • SRC
            • IMangrove
        • Strats
          • SRC
            • Strategies
              • MangroveOffer
              • MangroveOrder
              • Integrations
                • AaveV3Borrower
                • AaveV3BorrowerImplementation
                • AaveV3BorrowerStorage
                • AaveV3Lender
                • CompoundModule
              • Interfaces
                • IForwarder
                • ILiquidityProvider
                • IOfferLogic
                • IOrderLogic
              • Offer_forwarder
                • Abstract
                  • Forwarder
              • Offer_maker
                • Abstract
                  • Direct
                • Market_making
                  • Kandel
                    • AaveKandel
                    • AaveKandelSeeder
                    • KandelSeeder
                    • Abstract
                      • AbstractKandelSeeder
                      • CoreKandel
                      • DirectWithBidsAndAsksDistribution
                      • GeometricKandel
                      • HasIndexedBidsAndAsks
                      • KandelLib
                      • TradesBaseQuotePair
              • Routeurs
                • SimpleRouter
                • Abstract
                  • AbstractRouter
                • Integrations
                  • AavePooledRouter
                  • HasAaveBalanceMemoizer
              • Utils
                • AccessControlled
              • Vendor
                • AAVE
                  • V3
                    • Contracts
                      • Dependencies
                        • Oppenzeppelin
                          • Contracts
                            • IERC20
                      • Interfaces
                        • IAToken
                        • IAaveIncentivesController
                        • IAaveOracle
                        • ICreditDelegationToken
                        • IInitializableAToken
                        • IPool
                        • IPoolAddressesProvider
                        • IPriceOracleGetter
                        • IScaledBalanceToken
                      • Protocol
                        • Libraries
                          • Configurations
                            • ReserveConfiguration
                          • Helpers
                            • Errors
                          • Types
                            • DataTypes
                    • Periphery
                      • Contracts
                        • MISC
                          • Interfaces
                            • IEACAggregatorProxy
                        • Rewards
                          • Interfaces
                            • IRewardsController
                            • IRewardsDistributor
                            • ITransferStrategyBase
                          • Libraries
                            • RewardsDataTypes
                • Compound
                  • CarefulMath
                  • Exponential
                  • ExponentialNoError
                  • ICompound
    • Background
      • Building Blocks
        • MangroveOffer
        • Direct
        • Forwarder
  • Vaults
    • Understanding vaults
      • Oracles
    • Managing a vault (CLI)
      • Deploying an oracle
      • Creating a vault
      • Monitoring the vault
      • Setting the vault position
      • Setting the fee data
      • Rebalancing
      • Adding or removing liquidity
    • Custom interactions
      • Oracles
      • Vault Factory
      • Managing a vault
        • Setting the position
        • Rebalancing
        • Setting a manager
        • Setting fee
  • Keeper Bots
    • Keeper Bots
    • Guides
      • Using borrowed funds for cleaning
    • Backgroud
      • The role of cleaning bots in Mangrove
      • The role of gas price updater bots in Mangrove
  • Adresses
    • Deployment Addresses
  • Quick Links
    • Glossary
    • Website
    • Whitepaper
Powered by GitBook
On this page
  • Market order execution​
  • Market order functions​
  • Inputs​
  • Outputs​
  • Bounties for taking failing offers​
  • Token allowance​
  • Active offer lists​
  1. Protocol
  2. Technical References

Market-order

PreviousViews on offersNextDelegation

Last updated 1 month ago

A market order is Mangrove's simplest way of buying or selling assets. Such (taker) orders are run against a specific with its associated token and token. The liquidity taker specifies a max she's willing to accept and how much she wishes to trade: Either how many outbound tokens she wants or how many inbound tokens she wishes to pay.

Mangrove Market Order = TradFi Limit Order

Mangrove's market orders are DeFi market orders - which are different from market orders in TradFi:

In TradFi, a market order is an order to buy or sell immediately at the best available price.

In DeFi, where transactions can be or , adversaries may manipulate the best available price and thus extract value from a market order as there is no limit on the price. TradFi market orders are therefore unsafe for fully on-chain DEX'es like Mangrove.

To protect the user, Mangrove's market order therefore corresponds to a TradFi : An order to buy or sell at given price or better.

More precisely, Mangrove ensures that the "price" of the offers matched with the order does not exceed the specified max tick.

Market order execution

When a market order is processed by Mangrove's matching engine, it consumes the offers on the selected one by one, in order, and starting from lowest tick (offers with the same tick are executed in FIFO order).

Offers match if their is below or equal to the specified max tick.

The market order stops when one of these conditions are met:

  • only offers with tick > max tick are left,

  • the end of the offer list has been reached, or

  • the taker has received or paid the amount they specified.

For each matched offer, Mangrove takes the following steps:

  1. Mangrove determines the amount of outbound tokens the offer should deliver and how much inbound token it should be paid:

    • outbound amount: Either all of what the offer gives or, if that exceeds what the taker wants, the residual amount needed to fill the market order.

    • inbound amount: Determined by the offer's tick: inboundAmount=outboundAmount∗1.0001tickinboundAmount=outboundAmount∗1.0001tickinboundAmount=outboundAmount∗1.0001tickinboundAmount=outboundAmount∗1.0001tickinboundAmount=outboundAmount∗1.0001tickinboundAmount=outboundAmount∗1.0001tick.

  2. Mangrove sends inbound tokens to the offer maker (EOA or ).

  3. Mangrove then executes the offer logic's makerExecute function (a no-op for an EOA).

  4. If the makerExecute call is successful, Mangrove sends outbound tokens to the taker. If the call or the transfer fail, Mangrove reverts the effects of steps 2. and 3.

Mangrove provides two functions for executing market orders which differ in how the "price" limit is specified:

  • marketOrderByTick: The limit is specified as a maxTick which matched offers should not exceed.

  • marketOrderByVolume: The limit is specified as the ratio between two volumes, takerGives/takerWants, which offers should not exceed.

The *ByVolume variant is a convenience wrapper for the *ByTick variant: The provided volumes are converted to a corresponding maxTick, rounding down to the nearest tick allowed on the offer list, such that the taker does not pay more than specified.

The output from the two functions is the same.

  • Signature

  • Events

  • Revert strings

  • Solidity

function marketOrderByTick(
  OLKey memory olKey,
  Tick maxTick,
  uint fillVolume,
  bool fillWants,
  ) external returns (uint takerGot, uint takerGave, uint bounty, uint feePaid);

function marketOrderByVolume(
    OLKey memory olKey,
    uint takerWants,
    uint takerGives,
    bool fillWants
  ) external returns (uint takerGot, uint takerGave, uint bounty, uint feePaid);
    • outbound_tkn: address of the outbound token (that the taker will buy).

    • inbound_tkn: address of the inbound token (that the taker will spend).

  • maxTick: specifies the max tick that can be matched with this order

  • fillVolume: the desired volume of tokens in either olKey.outbound_tkn or olKey.inbound_tkn.

    • If fillWants is true, fillVolume is in olKey.outbound_tkn. This means the taker specified how much they wish to receive ("buy").

    • If fillWants is false, fillVolume is in olKey.inbound_tkn. This means the taker specified how much they wish to send ("sell").

  • fillWants: Whether to stop when the taker has received or spent a specified amount:

    • If true, the order is full when taker has received fillVolume of olKey.outbound_tkn.

    • If false, the order is full when taker has sent fillVolume of olKey.inbound_tkn.

    • outbound_tkn: address of the outbound token (that the taker will buy).

    • inbound_tkn: address of the inbound token (that the taker will spend).

  • takerWants: amount of outbound token the taker wants. Must fit on 127 bits.

  • takerGives: amount of inbound token the taker gives. Must fit on 127 bits.

    • The ratio takerGives/takerWants specifies the max ratio (and thus tick) that can be matched with this order.

  • fillWants: Whether to stop when the taker has received takerWants or spent takerGives:

    • If true, the order is full when taker has received takerWants of olKey.outbound_tkn.

    • If false, the order is full when taker has sent takerGives of olKey.inbound_tkn.

  • takerGave is the amount of inbound tokens the taker has sent.

  • bounty is the amount of native tokens (in units of wei) the taker received in compensation for cleaning failing offers

Let's consider the following DAI-WETH offer list with no fee:

Tick
Ratio (WETH/DAI)
Offer ID
Gives (DAI)

-75103

0.0005476

77

925.26

-75103

0.0005476

177

916.47

-75041

0.0005510

42

871.76

The following two examples illustrate the difference between fillWants = true or false:

Example 1 :

A taker calls marketOrderByTick on the offer list with:

  • maxTick = -75000

    • corresponds to a max ratio of 0.0005539

  • fillVolume = 2,500 * 10**18

  • fillWants = true

Since fillWants = true, we have:

  • fillVolume is in olKey.outbound_tkn and corresponds to 2,500 DAI

  • the market order will be considered filled once 2,500 DAI has been received.

In summary, this corresponds to a buy order for 2,500 DAI and the taker is willing to pay up to 2,500 * 0.0005539 = 1.3832 WETH.

The market order will execute as follows:

  1. Get 925.26 DAI for 925.26 * 0.0005476 = 0.5067 WETH from offer #77

  2. Get 916.47 DAI for 916.47 * 0.0005476 = 0.5019 WETH from offer #177

  3. Get the remaining 2500 - 925.26 - 916.47 = 658.27 DAI for 658.27 * 0.0005510 = 0.3627 WETH from offer #42.

In total, the taker gets 2,500 DAI and sends 0.5067 + 0.5019 + 0.3627 = 1.3713 WETH.

Example 2 :

A taker calls marketOrderByTick on the offer list with:

  • maxTick = -75000

    • corresponds to a max ratio of 0.0005539

  • fillVolume = 1.2 * 10**18

  • fillWants = false

Since fillWants = false, we have:

  • fillVolume is in olKey.inbound_tkn and corresponds to 1.2 WETH

  • the market order will be considered filled once 1.2 WETH has been sent.

In summary, this corresponds to a sell order of 1.2 WETH and the taker wants to receive at least 1.2 / 0.0005539 = 2168.84 DAI.

  1. Sell 925.26 * 0.0005476 = 0.5067 WETH for 925.26 DAI to offer #77

  2. Sell 916.47 * 0.0005476 = 0.5019 WETH for 916.47 DAI to offer #177

  3. Sell the remaining 1.2 - 0.5067 - 0.5019 = 0.1914 WETH for 0.1914 / 0.0005510 = 347.37 DAI to offer #42.

In total, the taker gets 925.26 + 916.47 + 347.37 = 2,189.10 DAI and sends 1.2 WETH.

Suppose one wants to buy or sell some token B (base), using token Q (quote) as payment, on a market with tick spacing T.

  • Market buy: A limit buy order for x B tokens, corresponds to a marketOrderByTick on the (B,Q,T) offer list with fillWants set to true, fillVolume = x (the volume one wishes to buy), and maxTick = ⌊log1.0001(pricelimit)⌋⌊log1.0001​(pricelimit)⌋⌊log1.0001(price limit)⌋⌊log1.0001​(price limit)⌋⌊log1.0001(pricelimit)⌋⌊log1.0001​(pricelimit)⌋.

  • Market sell: A limit sell order for x B tokens, corresponds to a marketOrderByTick on the (Q,B,T) offer list with fillWants set to false, fillVolume = x (the volume one wishes to sell), and maxTick = ⌊−log1.0001(pricelimit)⌋⌊−log1.0001​(pricelimit)⌋⌊−log1.0001(price limit)⌋⌊−log1.0001​(price limit)⌋⌊−log1.0001(pricelimit)⌋⌊−log1.0001​(pricelimit)⌋.

On order residuals :

ERC20 tokens transfers are initiated by Mangrove using transferFrom. If Mangrove's allowance on the taker's address (for tokens to be spent) is too low, the order will revert.

Any failed execution results in a being sent to the caller as compensation for the wasted gas.

Market order functions

Inputs

marketOrderByTick(olKey, maxTick, fillVolume, fillWants)

olKey: identifies the and consists of:

tickSpacing: specifies the space between allowed ticks (see for details)

marketOrderByVolume(olKey, takerWants, takerGives, fillWants)

olKey: identifies the and consists of:

tickSpacing: specifies the space between allowed ticks (see for details)

Outputs

takerGot is the net amount of outbound tokens the taker has received (i.e., after applying the offer list if any).

feePaid is the amount of outbound_tkn that was sent to Mangrove's vault in payment of the potential configured for the olKey .

Example

More on market order behaviour

Contrary to on regular based exchanges, the residual of your order (i.e., the volume you were not able to buy/sell due to hitting your price limit) will not be put on the market as an offer. Instead, the market order will simply end partially filled.

It is possible to implement GTC orders through a . in the Strat Lib implements GTC and other advanced order types.

Bounties for taking failing offers

If an offer fails to deliver, the taker gets a in native token to compensate for the gas spent on executing the offer. The bounty is paid by the and is taken from the they deposited with Mangrove when posting the offer.

Refer to for details on how provisions and bounties work and are calculated.

Token allowance

Active offer lists

Every Mangrove can be either , and Mangrove itself can be either . Taking offers is only possible when Mangrove is alive and on offer lists that are active.

offer list
outbound
inbound
ratio
front-run
sandwiched
limit order
tick
​
offer list
tick
maker contract
offer
bounty
​
​
​
offer list
Ticks, ratios, and prices
​
offer list
Ticks, ratios, and prices
​
fee
fee
offer list
​
​
GTC orders
order book
maker contract
MangroveOrder
​
bounty
offer owner
provision
Offer provisions
​
​
offer list
active or inactive
alive or dead