# What is Oxium?

Oxium is an order book DEX that allows liquidity providers to post arbitrary smart contracts (hooks) as offers. This enables features such as re-staking of liquidity held on other protocols, liquidity amplification and liquidity provision via custom strategies.

## Unlock your liquidity​

Oxium's order book DEX lists promises instead of locked commitments (liquidity is not locked on Oxium). It can be employed elsewhere until the offer is matched. For example, you can provide liquidity (LP) on another exchange and use this LPed liquidity on Oxium at the same time to trade or run strategies. This way, you can earn from up to any sources of yields, spread and rewards.


# Smart offers

The main difference between Oxium and other DEXs is the ability to attach code to offers (check out Smart Offers for more information). This translates into several disruptive mechanisms:

* **Reactive liquidity**\
  The liquidity on offer on Oxium **is not locked in a pool**. As long as an offer posted on Oxium is not taken, it can generate yield elsewhere on the chain - Aave, Compound or Morpho are great examples of protocols where you could leave your liquidity to grow, waiting to be sourced.
* **Last look** \
  Since an offer contains code, **defensive mechanisms can be baked in** to cancel a promise previously made:
  * For instance, if the market conditions are not anymore satisfactory at the time the offer is taken VS when it was posted
  * Code can cover any unwanted case scenarios (ex: high volatility), and therefore can mitigate/solve problems of slippage and arbitrage
  * Code helps make zero-latency trading decisions, with as much information as available on-chain at the time the trade occurs
* **Persistence** \
  Through the executed code, the **offer can automatically repost itself** on the order book. For someone who is posting offers (we call them Makers, or Market Makers), this is very handy because they can immediately update the amount of tokens they are offering after some of it has been taken. People that take offers are called Takers.

Smart contracts can be attached to offers, which gives the Maker total freedom in setting his sourcing trade parameters.

**Other powerful applications of smart offers**[**​**](https://docs.mangrove.exchange/#powerful-applications-of-smart-offers)**:**

* **Bounty:** every single failed offer is compensated with a bounty; Keeper bots can make money, and Takers don't lose any.
* **Permissionless:** everyone can interact with the core protocol without having to ask permission nor risking to be censored.
* **Non-custodial:** Oxium users retain full control over their funds - the exchange does not hold custody of their assets.


# Bounty

What if everyone makes empty promises, and the offers in the book are all meant to fail? This is where Makers **must leave a native token provision (the bounty)** in their offer. Nothing prevents them from posting offers that will always fail. So, to ensure that the offers displayed on the book are credible, it must be costly for Makers to post orders that are not meant to go through. And in that case scenario, the bounty is then given to the Taker as compensation.&#x20;

At first, **this might appear to favor Makers**. However, with advanced market-making features that allow them to accept or cancel offers, **Makers can mitigate their risk** and offer better prices. Ultimately, both Makers and Takers benefit: the risk of offer failure is essential for the effectiveness of smart offers.

Let's spend more time understanding [Makers](/start-here/what-is-oxium/makers-takers-keepers/makers), [Takers](/start-here/what-is-oxium/makers-takers-keepers/takers), and [Keepers ](/start-here/what-is-oxium/makers-takers-keepers/keepers)(yes, that last one is a new term), shall we?


# Makers, Takers, Keepers

In the Oxium ecosystem, three key participants interact to facilitate a dynamic and decentralized trading environment: [Makers](/start-here/what-is-oxium/makers-takers-keepers/makers), [Takers](/start-here/what-is-oxium/makers-takers-keepers/takers), and [Keepers](/start-here/what-is-oxium/makers-takers-keepers/keepers). Together, they form the backbone of the Oxium ecosystem, each playing a unique yet interconnected role in ensuring a seamless and effective trading experience.

Here is a simplified three-step diagram of Oxium unlocked assets and offer-is-code approach. It also introduces the three main actors on Oxium DEX.


# Makers

Makers are participants or entities within the Oxium ecosystem who are responsible for creating and listing offers on the platform. They can specify the conditions of their offers, such as the type and quantity of assets to be exchanged, the price, and any other relevant terms. For example, they promise to give a Taker some apples 🍎 if he gives them oranges 🍊 in return.

By initiating these offers, Makers enable transactions to occur within the Oxium Protocol, contributing to a vibrant market.


# Takers

**Takers** respond to the offers set up by [Makers](/start-here/what-is-oxium/makers-takers-keepers/makers). They critically assess these offers, considering factors like asset types, quantities, and prices.

The role of Takers is crucial in completing transactions within the Oxium marketplace. When a Taker agrees to the terms of an offer, they effectively seals the deal proposed by the Maker, leading to the execution of the trade.

Takers provide the necessary demand and liquidity in the marketplace, ensuring that the offers created by Makers are fulfilled. Their actions complete the cycle of trading activity within the Oxium ecosystem, making it a dynamic and interactive platform for exchanges.

Takers have the ability to buy or sell assets on Oxium, using either market or limit orders, akin to a traditional orderbook. They can execute these offers through general orders or choose to clean them individually.

This interaction between Takers and Makers completes the trading cycle in the Oxium ecosystem, enhancing its interactivity and liquidity.

The workflow for Takers involves executing the logic of all relevant smart offers upon an order's placement. Successful orders are removed from the book, and the process continues until the Taker's order is completely filled. If a Maker withdraws their offer and fails to match the liquidity, the Taker is compensated with a penalty (bounty), and Oxium proceeds to the next offer. This ensures that Takers are appropriately remunerated and that the order book remains efficient.


# Keepers

Keepers functioning as automated bots that ensure the order book remains relevant and efficient. As market conditions evolve, the order book may become congested with outdated or irrelevant orders. Keepers play a pivotal role in addressing this by continuously monitoring the order book.

Their primary responsibility is to identify offers that are failing. Once a failing offer is detected, Keepers targets them to clean them off the book. This action involves setting a gas price in such a way that the offer’s bounty offsets the gas expenditure. Essentially, Keepers act as the custodians of the Oxium ecosystem, maintaining its integrity and smooth operation.

In addition to managing failing offers, Keepers are tasked with keeping the gas price up to date. This is crucial for determining the compensation for [Takers ](/start-here/what-is-oxium/makers-takers-keepers/takers)who remove a failing offer from the list. By doing so, Keepers ensure that Takers are appropriately remunerated for their role in sustaining the efficiency and cleanliness of the order book.

Through these functions, Keepers play an indispensable role in the maintenance and operational effectiveness of the Oxium ecosystem, safeguarding its functionality and reliability.


# Why Oxium?

## **Deploy Your Own Composable Strategy**

Oxium empowers liquidity providers with unparalleled flexibility, enabling them to customize and control their strategies:

* **Customizable Offer Management**: Liquidity providers can incorporate defensive code within their offers, post unprovisioned offers, and redisplay liquidity seamlessly after their offers are taken, ensuring optimized participation in the market.
* **Full Control Over Strategy Parameters**: Oxium gives you the freedom to set precise parameters for your strategy, allowing you to align your liquidity provision with your specific risk and reward preferences.
* **Amplified Liquidity**: Maximize your trading potential by leveraging your liquidity across multiple pairs simultaneously. For example, you can place offers on both the WETH/USDC and WBTC/USDC pairs using the same USDC liquidity, efficiently broadening your market presence.
* **Multi-Liquidity Sourcing**: Your smart offers on Oxium can source liquidity from external sources, dynamically offering it to the taker. This capability enables profitable arbitrage opportunities, as your offer can bridge liquidity from various sources in real time.

## **Explore Yield Opportunities on the Earn Page**

The [**Earn** ](/dapp-guide/earn)page on Oxium’s DApp lets you explore and manage yield-generating positions within available vaults, built on Oxium's. This feature not only allows liquidity providers to earn rewards but also enables **vault managers** to design and implement innovative DeFi strategies. By harnessing Oxium’s unique liquidity provisioning, vault managers can create dynamic, adaptable strategies that respond to market conditions in real time, opening up new avenues for yield generation.&#x20;


# Who is the Oxium dApp for?

The Oxium **DApp** is designed for DeFi users seeking flexible, efficient, and innovative ways to manage liquidity and execute trades. It’s particularly suited for:

* **Liquidity Providers**: Those who want to earn yield by placing offers in multiple markets without locking up their assets. Oxium’s unique approach allows liquidity providers to source funds dynamically, maximizing capital efficiency and unlocking additional earning opportunities.
* **Traders**: From beginners to experienced DeFi traders, Oxium offers advanced trading features, including limit and amplified orders, with real-time order book data, market depth, and price charts. Traders can benefit from customized order options, like setting specific prices and durations for limit orders.
* **Yield Farmers**: For DeFi users aiming to maximize their rewards, Oxium’s unique approach to liquidity provisioning offers a powerful advantage. By allowing assets to remain unlocked, Oxium enables yield farmers to participate in multiple opportunities simultaneously, effectively compounding their earning potential across various protocols. With the flexibility to dynamically source liquidity, farmers can respond to market conditions, moving their funds to the most profitable yield-generating options without being restricted by asset lock-up.
* **Developers and Integrators**: Oxium’s protocol is designed as a foundational layer for developers and projects that want to bring decentralized trading and liquidity management capabilities to their platforms. By leveraging Oxium’s flexible, modular infrastructure, developers can integrate novel liquidity strategies, such as the amplified order feature, allowing assets to be used in multiple orders at once. This enables new and innovative DeFi applications that extend beyond traditional models, paving the way for composable and efficient decentralized financial solutions. As highlighted in our recent article, Oxium is redefining the potential of liquidity in DeFi, offering developers a toolkit for the next generation of financial applications.

In summary, Oxium is ideal for anyone in the DeFi space looking for innovative, flexible tools to optimize liquidity and trading strategies across multiple markets.


# FAQ

<details>

<summary>How to Bridge to SEI?</summary>

* Step 1: Open [Stargate](https://stargate.finance/) or [Relay](https://www.relay.link/bridge/sei?fromChainId=1\&fromCurrency=0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48\&toCurrency=0x3894085ef7ff0f0aedf52e2a2704928d1ec074f1) and Connect Your Wallet
* Step 2: Select the token/chain you want to Bridge to Sei (e.g. USDC on Ethereum)
* Step 3: Enter the Amount of Funds to Bridge (e.g. $500)
* Step 4: Initiate the Transfer and confirm in your wallet

Note: To make transactions on Sei it requires some $SEI tokens

</details>

<details>

<summary>How to add Sei Chain to my Wallet?</summary>

The majority of wallets let you "Add Network" > Choose SEI.\
In case you need to fill in RPC information we recommend using the [official Sei Docs](https://docs.sei.io/learn/rpc-providers).

</details>

<details>

<summary>Why do my transactions keep failing?​</summary>

Here are a few reasons as to why your transactions are failing on Oxium exchange:

* The amount of gas or slippage you selected is too low - we encourage you to tweak those values and find out what works best for your trades.
* The density for your Limit order is too low - if you're trying to place a Limit order with a small amount, your order will fail and will not be executed. Oxium requires that you provide a token amount greater than the amount of gas the triggered offer requires to be executed (called density).
* You can check the minimum volume required to post a limit order [here](/dapp-guide/trade/how-to-make-an-order/limit-order).

</details>

<details>

<summary>The approval amount for my limit orders seems odd - what is going on?​</summary>

**TL;DR**

* A rule of thumb for limit orders to avoid order failure due to lack of approval is to make sure you approve at least double the amount you target (or infinite approval).
* The easy way to do this is to use the "Use default" option on your wallet when executing an approval.

**Let's now clarify the difference between the "Max" and "Use default" approval values offered by your wallet.**

* "Max" will give you the maximum amount available in your wallet.
* If you have ticked the "allow infinite approval" on Oxium app, "Use default" will give you an "infinite approval" amount.
* If you have unticked the "allow infinite approval" on Oxium app, "Use default" will give you the maximum amount available in your wallet based on what you've keyed in. That amount differs **whether you are executing a market order or a limit order**.

**Example (no infinite approval)**

* Market order: if you want to buy some WETH with let's say 20 USDC, "Use default" will set the approval amount at *20 + slippage*. For a 2% slippage, the amount to approve would be 20.4 USDC.
* Limit order: if you want to buy some WETH for 20 USDC of worth with a limit order (ex: Good til time), "Use default" will set the approval amount at *40 (20 \* 2)*.
  * If you have multiple open limit orders for the same token, the approvals then need to compound.
  * Example: if you create another Good til time limit order for 20 USDC of worth, the approval amount will be 40 (previous limit order) + 40 (new limit order) = 80 USDC.

</details>

<details>

<summary>Where is my transaction history?​</summary>

Which order type are you trying to execute? There are subtle differences between the various limit orders available on our Trade page. They might appear/be processed differently. We encourage you to first read the [More on order types](/dapp-guide/trade/how-to-make-an-order/more-on-order-types) section.

</details>

<details>

<summary>Who pays the gas on Oxium?​</summary>

If the offer succeeds, the gas costs for the execution of the trade are paid by the offer taker. If the offer fails the taker is compensated for these gas costs.

</details>

<details>

<summary>What happens when an offer fails?​</summary>

Offers in the order book may fail when taken, either because the maker consciously chose to renege on the offer to trade, or because the maker contract reverted for other reasons. In that case, the taker has wasted some gas and will be compensated using the offer provision (in native token) that the maker has deposited in Oxium.

</details>

<details>

<summary>Are Oxium market orders the same as traditional market orders?​</summary>

Oxium'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 [front-run](https://www.investopedia.com/terms/f/frontrunning.asp) or [sandwiched](https://coinmarketcap.com/alexandria/article/what-are-sandwich-attacks-in-defi-and-how-can-you-avoid-them), 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 Oxium.

To protect the user, Oxium's market order therefore corresponds to a [**limit order**](https://www.investopedia.com/terms/l/limitorder.asp) in TradFi: An order to buy or sell at or below a given price. More precisely, Oxium ensures that the **average** price of the offers matched with the order does not exceed the specified price.

TL;DR: Oxium market order = TradFi limit order.

</details>


# Glossary

#### Amplified Liquidity​ <a href="#amplified-liquidity" id="amplified-liquidity"></a>

An offer on Oxium that is undercollateralized.

#### Base / Quote​ <a href="#base--quote" id="base--quote"></a>

Base token is the traded asset, quoted in Quote token.

#### **Bounty**

A portion of an offer provision that is sent to the taker to compensate a failure to deliver.

#### Cleaning Bot​ <a href="#cleaning-bot" id="cleaning-bot"></a>

An off-chain bot that keeps the order books clean by sniping failing offers.

#### Density​ <a href="#density" id="density"></a>

The ratio of tokens promised by an offer over the gas it requires to be executed.

#### Dual offer​ <a href="#dual-offer" id="dual-offer"></a>

An offer that is posted as a consequence of previous offer being taken.

#### gasLimit <a href="#gaslimit" id="gaslimit"></a>

The maximum gas requirement the taker will tolerate for an offer.

#### gasprice <a href="#gasprice" id="gasprice"></a>

An estimate of the price of a gas unit in native token amount.

#### gasreq

An upper bound of the gas units that an offer requires when called by Oxium.

#### Gives&#x20;

The volume of tokens an offer promises in exchange of the full volume of required (or wanted) tokens.

#### Hook

Internal functions in the building blocks of the Strat Lib, which may be overridden to change the default behavior of an offer logic.

#### Inbound​ <a href="#inbound" id="inbound"></a>

The token type that an offer taker must send.

#### Keeper Bot​ <a href="#keeper-bot" id="keeper-bot"></a>

An off-chain bot that helps keep Oxium functioning optimally.

#### Last Look​ <a href="#last-look" id="last-look"></a>

Feature of an offer logic that verifies whether trade execution should be cancelled.

#### Maker Contract​ <a href="#maker-contract" id="maker-contract"></a>

A maker contract is a smart contract that is bound to a smart offer posted on Oxium.

#### Maker Partial Fill​ <a href="#maker-partial-fill" id="maker-partial-fill"></a>

When an incoming order partially takes the volume given by an offer.

#### makerExecute​ <a href="#makerexecute" id="makerexecute"></a>

Callback function of an offer logic that is called by Oxium prior to trade settlement.

#### makerPosthook​ <a href="#makerposthook" id="makerposthook"></a>

The callback function of an offer logic that is called by Oxium immediately after trade settlement.

#### Offer ID​ <a href="#offer-id" id="offer-id"></a>

The identifier of an offer in a given offer list.

#### Offer List​ <a href="#offer-list" id="offer-list"></a>

A list of offers on the same token pair, ranked from best price to worst price.

#### Offer Logic​ <a href="#offer-logic" id="offer-logic"></a>

The part of a maker contract that is executed as a consequence of a call by Oxium when processing a market order.

#### Offer Owner​ <a href="#offer-owner" id="offer-owner"></a>

An account that is allowed to post, update or retract a specific offer posted by a maker contract.

#### On-the-fly Offer​ <a href="#on-the-fly-offer" id="on-the-fly-offer"></a>

An offer posted by an EOA, in contrast with a smart offer, which is posted by a smart contract.

#### Outbound​ <a href="#outbound" id="outbound"></a>

The token type that an offer taker will receive.

#### Price

Amount of quote tokens per base token that an offer demands or a taker is willing to pay

#### Provision&#x20;

An amount of native tokens that is attached to a live offer on Oxium and that is used to compensate a fail-to-deliver.

#### Ratio

The ratio 'wants/gives' between the amount an offer 'gives' and the amount it 'wants'.

#### Reactive Liquidity​ <a href="#reactive-liquidity" id="reactive-liquidity"></a>

Liquidity providers can post offers that are not fully provisioned. It is enough that their code brings the promised liquidity at match-time. In the meantime, it can be put to work.

#### Renege​ <a href="#renege" id="renege"></a>

Makers can renege on the offer to trade by incorporating defensive code in the maker contract (e.g., because the market conditions changed).

#### Reserve identifier​ <a href="#reserve-identifier" id="reserve-identifier"></a>

An immutable address identifying the fund owner when using a router

#### Router

A smart contract building block provided by the Strat Lib that is used by an offer logic to manage liquidity in a modular fashion.

#### Smart Offer​ <a href="#smart-offer" id="smart-offer"></a>

An offer that is bound to a smart contract, as opposed to an on-the-fly offer.

#### Taker Fee​ <a href="#taker-fee" id="taker-fee"></a>

A portion of the tokens promised to the taker that are sent to the Oxium protocol's vault.

#### Tick​ <a href="#tick" id="tick"></a>

A 'price point' corresponding to the ratio 1.0001^tick

#### tickSpacing​ <a href="#tickspacing" id="tickspacing"></a>

Controls the granularity of available price points in an offer list.

#### Wants​ <a href="#wants" id="wants"></a>

The volume of tokens an offer wants in exchange of the full volume of promised (or given) tokens.


# Swap

Swap tokens quickly and seamlessly - execute market orders with ease, while getting the best available price without the hassle of advanced configurations.

🔗 <https://app.oxium.xyz/swap>

<figure><img src="/files/aVsKgcdlLJxO5OuMUO5M" alt=""><figcaption></figcaption></figure>

## Step by Step Manual:

#### **Step 1: Connect Your Wallet**

Click the **"Connect Wallet"** button at the bottom of the swap interface. This will open a pop-up for selecting and authorizing your wallet, allowing it to interact with Oxium’s DApp on the chosen network.

**Disconnecting Your Wallet**: To disconnect your wallet, click on your wallet address in the top right corner. This will bring up a small pop-up with options to **Copy Address** and **Disconnect**. Click **Disconnect** to securely log out your wallet from the DApp.

<figure><img src="/files/H5BfSsJaAJyUKoz6HXdy" alt=""><figcaption></figcaption></figure>

#### **Step 2: Select Tokens for Swapping**

* With your wallet connected and network set, proceed with choosing the tokens for the swap.
* **Sell** and **Buy Sections**: The swap interface is divided into two main sections:
  * **Sell**: The token you’re offering in the swap.
  * **Buy**: The token you’ll receive in exchange.

1. **Token Selection**: Click the dropdown next to each token icon to select the token type. The available options may vary depending on the selected network.
2. **Enter Amount**:
   * **Sell Amount**: Enter the amount of the token you want to swap in the **Sell** field. An equivalent USD value is displayed below for reference.
   * **Buy Amount**: After entering the sell amount, the buy amount will auto-calculate based on the current market rate.

If you wish to reverse the **Sell** and **Buy** tokens, you can click **Swap Direction** button (↔) between the Sell and Buy sections to reverse the tokens and quickly switch the trade direction. This will instantly switch the tokens, making the **Buy** token the **Sell** token, and vice versa, without needing to re-enter amounts.

**Note**: If the swap amount exceeds your balance, an **"Insufficient Balance"** message will appear. Make sure you have enough tokens to proceed.

#### **Step 3: Set Slippage Tolerance**

This controls the maximum price variation you’re willing to accept for the trade.

* **Available Options**: Choose from 0.1%, 0.5%, 1%, or set a **custom percentage**.
* **Use Case**: A lower tolerance limits price variation but may cause failed transactions if prices move. Higher tolerance increases the success rate but allows for more price fluctuation.

<figure><img src="/files/uv5zP1XXwqKDYREuaKRo" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Jaj8fI8uoLLggO5Fag9n" alt=""><figcaption></figcaption></figure>

#### **Step 4: Confirm Swap Details**

* Double-check all details, including token selections, amounts, and slippage tolerance.

#### **Step 5: Execute the Swap**

1. **Swap Button**: When ready, click the **"Swap"** button.
2. **Wallet Confirmation**: Approve the transaction in your connected wallet, including any gas fees required by the network.

#### **Additional Interface Elements**

**Network and Account Information**: Located in the top right corner, this area shows both your network and wallet address. You can switch networks or wallet anytime by using these buttons.


# Trade

The **Trade** page in Oxium’s DApp provides a streamlined interface for trading tokens using three types of orders: **market** and **limit**. This page also includes real-time order books, trade history, and charting tools for tracking price movements and depth, enabling users to make informed trading decisions.

## **Types of Orders on** Oxium **DEX**

On Oxium DEX, there are three types of orders available:

1. **Market Order**: This type allows you to buy or sell a token at the current market price. Market orders are executed immediately, providing a quick and efficient trading option.
2. **Limit Order**: With a limit order, you set a specific buy or sell price for a token. The order will only execute when the market reaches the designated price, allowing you to control the trade’s entry or exit point based on your target price.

> **Note**: Before placing your first order, you will need to **approve** Oxium to spend tokens on your behalf. This one-time authorization allows Oxium to execute trades using your specified funds.

***

## **Accessing the Trade Page**

In the Oxium DApp sidebar, click the **"Trade"** icon (two candlestick icons). This will open the trading interface, showing market information, order types, and trading options.

### **Market Data Overview**

* **Price**: Displays the current price of the selected pair.
* **24h Change**: Shows the price change percentage over the last 24 hours.
* **24h High/Low**: Indicates the highest and lowest prices within the past 24 hours.
* **24h Volume**: Shows the total trading volume for the pair in the past 24 hours.

### **Charting Options**

* **Depth Chart**: This chart visually represents the buy and sell orders on the order book, giving insights into market depth and potential liquidity at different price points.
* **Price Chart**: The price chart (often integrated with TradingView) provides price movements over time. You can add indicators, adjust timeframes, and customize views to analyze historical trends and price action for the trading pair.

## Fees​

Makers on Oxium have no fees to pay, all fees are paid by the takers! Below is a table of the fees on different markets available on Oxium.

| Market                             | Fee (Taker)                                                |
| ---------------------------------- | ---------------------------------------------------------- |
| Stable Pairs ( USDC/USDT )         | <mark style="background-color:green;">1bps \| 0.01%</mark> |
| Volatile Asset Pairs ( wSEI/USDC ) | 2bps \| 0.02%                                              |


# How to make an order

Due to the way Oxium works, there is a minimum volume that you need to be aware of when you are placing your order.

## How to make an Order

In the following pages you can see the way to make various types of orders on Oxium:

| Type         | Description                                                                                 |
| ------------ | ------------------------------------------------------------------------------------------- |
| Market Order | Buy or sell a token at the current market price, executed immediately                       |
| Limit Order  | Set a specific buy/sell price for a token, executed only when the market reaches that price |


# Market Order

A **Market Order** is the simplest and quickest way to trade on Oxium. It allows you to buy or sell a token at the current market price and is executed immediately.

**Step 1: Access the Trade Page**

In the Oxium DApp sidebar, click the **Trade** icon (two candlestick icons) to open the trading interface.

<figure><img src="/files/h0rpByKVBzlimKFsHE1Z" alt=""><figcaption></figcaption></figure>

**Step 2: Select Trading Pair**

Choose the trading pair you wish to trade (e.g., **WSEI/USDC**) from the dropdown at the top of the page.

<figure><img src="/files/zFv1GPlb0dneZtTZhvab" alt=""><figcaption></figcaption></figure>

**Step 3: Enter Trade Details**

* **Send Amount**: Input the amount of the token you want to buy or sell. Use shortcuts like **25%**, **50%**, **75%**, or **Max** to quickly select a portion of your balance.
* **Receive Amount**: This will auto-calculate based on the current market price.

<figure><img src="/files/iTTmV54lTHfxNsUOBA5T" alt=""><figcaption></figcaption></figure>

**Step 4: Set Slippage Tolerance**

Define an acceptable slippage tolerance (e.g., 0.5%) to manage potential price variations during execution.

**Step 5: Review Fees**

The system displays the transaction fee for the market order.

**Step 6: Place the Market Order**

* Click **Buy** or **Sell** to execute the market order instantly.
* **Confirm the transaction** in your wallet.

Your order will execute at the best available price, and your tokens will be transferred immediately upon confirmation.


# Limit Order

A **Limit Order** allows you to specify a price at which you want to buy or sell a token. The order will only execute if the market reaches your specified price, giving you more control over the trade.

**Step 1: Access the Trade Page**

In the Oxium DApp sidebar, click the **Trade** icon to open the trading interface.

**Step 2: Select Trading Pair**

Choose the trading pair you wish to trade from the dropdown at the top (e.g., **WETH/USDC**).

**Step 4: Choose Order Type**

Select Buy or Sell, then select **Limit** under the **Buy** or **Sell** tab on the right side of the interface.

**Step 5: Enter Trade Details**

* **Set Limit Price**: Enter the specific price at which you want to buy or sell the token.
* **Send Amount**: Input the amount of the token you want to trade. You can use shortcuts like **25%**, **50%**, **75%**, or **Max** based on your wallet balance.
* **Total**: This field shows the total amount in the quote currency (e.g., USDC) calculated from the limit price and amount entered.
* [**Minimum Volume**](/dapp-guide/trade/minimum-volume): The minimum required trade volume will be displayed.

**Step 6: Liquidity Sourcing**

Leave this as **Wallet** if you want this limit order to execute only from your wallet funds. Look at Amplified Orders' page if you want to surce liquidity from elsewhere.

<figure><img src="/files/GmlDA99gJuNBNYvB25SR" alt=""><figcaption></figcaption></figure>

**Step 7:** [**Set Time in Force**](/dapp-guide/trade/how-to-make-an-order/more-on-order-types)

* **GTC (Good Till Canceled)**: The order remains open until it is either fully executed or canceled by the user.
* **PO (Post Only)**: The order will only be added to the order book and will not match with an existing order immediately. This is ideal for users who want to avoid immediate execution and instead provide liquidity to the book.
* **IOC (Immediate or Cancel)**: The order will attempt to execute immediately for as much volume as possible. Any portion that cannot be filled instantly will be canceled.
* **FOK (Fill or Kill)**: The order will only execute if it can be filled completely at the specified price. If the full volume cannot be matched, the entire order is canceled.

Additionally, you can specify a **Time in Force duration** to further customize the order’s validity:

* After choosing your preferred **Time in Force** option, set a specific time duration in **days**, **hours**, or **minutes**. This allows you to specify, for example, "28 Days" or "6 Hours" for your order to remain active within those parameters.

**Step 8: Place the Limit Order**

* Click **Buy** or **Sell** to place the limit order.
* **Confirm the transaction** in your wallet to finalize the order.

Your limit order will now appear in **Open Orders** and will only execute if the market reaches your specified price.[<br>](https://docs.mangrove.exchange/general/web-app/trade/how-to-make-an-order/minimum-volume)


# Amplified Order

An **Amplified Order** on Oxium is an enhanced limit order that utilizes the **Liquidity Sourcing** option. This allows you to place limit orders across multiple markets with the same funds, leveraging Oxium’s principle of unlocked liquidity for efficient capital use.

When setting up a [**Limit Order**](/dapp-guide/trade/how-to-make-an-order/limit-order) on the Trade page, you can configure the **Liquidity Sourcing** options to enable an **Amplified Order**. This allows you to make the most of Oxium’s unlocked liquidity features.

1. **Choose Order Type**: Select **Limit** under the Buy or Sell tab on the right-side panel.
2. **Enter Limit Price and Amount**: Set the specific price and amount for your limit order.
3. **Configure Liquidity Sourcing**:

**Send from**:

This option allows you to choose the specific wallet or source from which the liquidity for the limit order will be drawn.

**Receive to**:

This option defines where the proceeds from the trade will go once the order is executed.

For **Amplified Orders**, setting up **Liquidity Sourcing** with specific **Send from** and **Receive to** wallets enables:

* **Multi-Wallet Management**: Users can choose to fund the order from one wallet and receive the output in another, adding flexibility in asset management.
* **Amplified Liquidity**: By using Oxium’s unlocked liquidity, your funds in one wallet can simultaneously support multiple orders across markets, maximizing liquidity efficiency.[<br>](https://docs.mangrove.exchange/general/web-app/trade/how-to-track-open-orders)


# More on order types

This section provides an overview of the various order types available on Oxium:

* Market order
* Immediate or Cancel (IOC)
* Good 'til time (GTT)
* Fill or kill (FOK)

### Market order[​](https://docs.mangrove.exchange/general/web-app/trade/more-on-order-types#market-order) <a href="#market-order" id="market-order"></a>

A market order is an order type used to buy or sell at the current market price.

* It is executed immediately, prioritizing speed over the specified price.
* The execution price of a market order may vary due to market fluctuations and order book liquidity.
* Unlike limit orders, market orders do not have a specific price parameter and **are subject to slippage**, where the executed price may differ from the expected price.

Example

You place an market order to buy 1 WETH, with a 3% slippage (i.e. you are willing to accept up to 3% of price slippage on your order). Your order could either be executed:

* In full at 1,800 USDC (desired price).
* In full at a price between 1,800 USDC and 1,854 USDC (with a slippage of 3%).
* Partially, depending on the liquidity available on the offer on the order book.
  * Ex: 0.5 WETH at 1,800 USDC + 0.25 WETH at 1,818 USDC (1% slippage) + 0.25 WETH at 1,854 USDC (3% slippage)

### Immediate or Cancel (IOC)[​](https://docs.mangrove.exchange/general/web-app/trade/more-on-order-types#immediate-or-cancel-ioc) <a href="#immediate-or-cancel-ioc" id="immediate-or-cancel-ioc"></a>

While it may seem similar to a market order, there is a fundamental difference.

* With an IOC order, you set a specific limit price at which you want the order to be executed.
* The order will either be immediately filled at that exact price, fully or partially, or canceled entirely. It's about ensuring that your order is executed at your desired price, or not executed at all.
* The IOC order **does not allow for slippage**, meaning it won't be filled at a different price than what you specified (unlike a market order).

Example

You place an IOC order to buy 1 WETH at a max price limit of 1,800 USDC. Your order could either be:

* Fully taken immediately, i.e. you get your 1 WETH at the desired price.
* Partially taken immediately, i.e. you get 0.8 WETH at the desired price, and the rest is "canceled" (there is no resting order asking for the remainder).
* Canceled if there is no match on the order book.

### Good 'til time (GTT)[​](https://docs.mangrove.exchange/general/web-app/trade/more-on-order-types#good-til-time-gtt) <a href="#good-til-time-gtt" id="good-til-time-gtt"></a>

It allows you to set an expiry date for your limit order (ex: active for 3 days, then canceled if not filled). A GTT order that was created, but that has not yet been filled will always show as "Filled" in the UI - it is a normal behavior.<br>

Let us explain:

* When placing a GTT order, Oxium will attempt to fill it entirely at the desired price.
* **Instant order** = the first execution of the order:
  * If it is a match and the fill is in full, it will be recorded in the UI as is.
  * If it can't be matched just yet, a fill at quantity "0" will be recorded in the UI for the instant order, and a **resting order** will be created.
* More on the fill at quantity "0":
  * That allows you to track in the UI that the order was successfully executed, even if no actual quantity was **yet** bought or sold.
  * It is crucial - without this, there would be no visual trace of what happened to the order you just placed (if not taken).
  * Your resting order is then waiting to be filled. There could potentially be multiple fills for that same order. Typically, there will be one fill for the initial order (0 or any other amount taken), and additional fills up until the resting order is fully taken.
* This mechanism ensures that even if there are partial fills or subsequent trades on the resting order, each execution is recorded separately.

Example

You place an GTT order to buy 1 WETH at a max price limit of 1,800 USDC, with a time limit of 3 days. Your order could be processed in several ways:

* **Instant full fill**: Your order is fully taken, immediately.
  * That means you obtain the target 1 WETH at the desired price.
  * A fill of the transaction will be recorded in the UI.
* **Instant partial fill + Resting Order**:
  * If your order is not entirely filled, a fill with the quantity that has been partially executed will be recorded in the UI.
  * Then, a new order will be created to capture the remaining quantity at the requested price. This order will be resting on the order book, waiting to be fully or partially taken, until the expiry date.
  * Each subsequent transaction that matches your resting order will be logged as a new fill until the order is fully executed or expired
* **No instant fill + Resting Order**:
  * If there is no matching order available on the order book at the time of placement, a "resting" order is posted in the book, waiting to be taken, either fully or partially.
  * Each transaction will log a new fill until the order is fully taken or expired.
* **Order Cancellation**: If there is no match for your order on the order book by the end of the specified time period (3 days in this case), the order will be automatically canceled.

### Fill or Kill (FOK)[​](https://docs.mangrove.exchange/general/web-app/trade/more-on-order-types#fill-or-kill-fok) <a href="#fill-or-kill-fok" id="fill-or-kill-fok"></a>

The KOF order is an "all or nothing" instant order. It is similar to the IOC order in the sense that it executes immediately, but it does not allow for partial filling.

Example

You place an FOK order to buy 1 WETH at a max price limit of 1,800 USDC. Your order could either be:

* Fully taken immediately, i.e. you get your 1 WETH at the desired price.
* Canceled if there is no match on the order book.


# Approvals

## Infinite approval[​](https://docs.mangrove.exchange/general/web-app/trade/approve-buy#infinite-approval) <a href="#infinite-approval" id="infinite-approval"></a>

Before your order can succeed, you will have to approve Oxium to transfer the funds.

1. After choosing your order parameters, you will have to click the "Buy" or "Sell" button.
2. It will trigger the approval process, starting with a pop-up. Click on "Proceed" then "Approve".
3. Your wallet will open - you can leave the suggested amount for an "infinite approval".

   caution

   Clicking "Max" will give you the maximum amount available in your wallet. This means you will have to re-approve each time you make an order.
4. Click next, review the transaction and click "Approve" on your wallet.
5. Wait for the transaction to be processed, and that's it - you're ready to trade!

On the following pages, you will find more details on how to execute different order types

## About Approvals[​](https://docs.mangrove.exchange/general/web-app/trade/approve-buy#about-approvals) <a href="#about-approvals" id="about-approvals"></a>

You can read some more about approvals in the FAQ section.

Here are a few things you should consider when it comes to approvals:

1. An approval is valid only for a specific order type of a specific market.

   > 💡 For example, if you approved a BUY market order for the WSEI/USDC market, this approval is not valid for SELL market orders for that same market. You have to approve again.
2. Approvals accumulate together.

   > 💡 For example, if you approve buy market order for WSEI/USDC market with a 1000 USDC and perform a market order for 100 USDC, you have 900 USDC in approved balance. If you perform the same action again ("Approve & Buy"), you'll have 1800 USDC of approved balance.
3. If your pre-approved amount is used up, your order will fail. An easy way around this is to perform an infinite approval.

## Revoke token approvals[​](https://docs.mangrove.exchange/general/web-app/trade/approve-buy#revoke-token-approvals) <a href="#revoke-token-approvals" id="revoke-token-approvals"></a>

To remove a dApp access to your wallet's tokens, you can revoke approvals previously granted. An easy way to do it would be to use [Revoke](https://revoke.cash/), for example. This will however risk your orders failing if you have open orders, so be sure you don't need the approvals.


# Minimum Volume

Due to the density on each market, there is a minimum token value requirement when placing limit orders (except for IOC orders). You can read more about why your transactions might be failing in the FAQ.

This value will change based on the market and the source of liquidity you select, so please check the volume below in the app to make sure before you place your order!


# How to Track and Manage Orders

Oxium’s Trade page dashboard is designed to help you efficiently manage and track all of your active, filled, and historical orders for each trading pair. Here’s a breakdown of how to monitor and interact with your orders.

## **Trades Tab**

The **Trades** tab shows recent transactions for the selected trading pair. This log of recent trades helps you understand market activity and price trends. It includes:

* **Size**: The amount of the asset traded.
* **Price**: The price at which the trade occurred.
* **Date**: The timestamp of each trade.

This tab provides a quick way to gauge market trends and see how frequently trades are happening at different price points.

## **Open Orders Tab**

The **Open Orders** tab is where you’ll find all your active limit orders that haven’t been filled or canceled yet. This tab is essential for tracking orders that are waiting for specific market conditions. Here’s what you’ll see:

* **Market**: The trading pair associated with the order, such as WETH/USDC.
* **Side**: Indicates whether it’s a Buy or Sell order.
* **Type**: Specifies the type of order, typically Limit or Market.
* **Filled/Amount**: Shows how much of the order has been filled versus the total order amount.
* **Price**: The set price for the order to execute.
* **Time in Force**: Indicates the order’s duration condition (e.g., GTC - Good Till Canceled, FOK - Fill or Kill).
* **Action**: An option to cancel the order directly from this tab if needed.

This tab is particularly useful for monitoring your ongoing trades and adjusting or canceling them as necessary.

## Managing Orders from the Open Orders Tab

From the **Open Orders**, you can quickly manage your orders: Modify or cancel them.

* **Modify**: Click **Modify** (the pen) to open the **Order Details** window, where you can adjust:
  * **Limit Price**: Change the price at which you want the order to execute.
  * **Amounts**: Adjust the amounts for **Send from Wallet** or **Receive to Wallet** to increase or decrease the funds allocated to this order.
* **Cancel**: If you no longer want the order to remain open, click **Cancel** (the cross) to remove it from the Open Orders list and cancel your order.

## **Orders History Tab**

The **Orders History** tab provides a comprehensive log of all your completed, expired, or canceled orders. Here, you can review past trades and actions. The fields in this tab include:

* **Market**: The trading pair involved in the order.
* **Side**: Shows whether it was a Buy or Sell.
* **Type**: Indicates the order type, such as Market or Limit.
* **Received/Sent**: Details the amounts of assets traded or received.
* **Price**: The price at which the trade was executed.
* **Date**: The date and time the order was filled or canceled.
* **Status**: Displays the final status of the order, such as Filled, Expired, or Canceled.
* **Explorer**: A link to the blockchain explorer for each transaction, enabling you to verify and track transactions on-chain.


# Earn

The **Earn** page on Oxium’s DApp lets you explore and manage yield-generating positions within available vaults, built on Oxium's flexible liquidity engine. These vaults leverage Oxium’s unique liquidity provisioning to offer optimized yield strategies, allowing you to earn rewards while maintaining liquidity flexibility. With Oxium’s composable infrastructure, yield opportunities are more dynamic and adaptable to market conditions, giving liquidity providers enhanced control over their earnings. You can deposit tokens to earn yields, view your active positions, and monitor key metrics for each vault.

#### **Step 1: Accessing the Earn Page**

In the Oxium DApp sidebar, click the **"Earn"** icon (the piggy bank icon). This will take you to the Earn page, where you can view all available vaults and your active positions.

<figure><img src="/files/nvWzlSPZnqbLGCOl490F" alt=""><figcaption></figcaption></figure>

**Step 2: Viewing Vaults and Strategies**

The Earn page is divided into two sections:

* **My Positions**: Displays any active positions you currently hold in different vaults.
* **Vaults**: Shows all available vaults, including their associated **market pairs** (e.g., WSEI-USDC), **strategies** (such as Kandel YEI), and **vault managers** (e.g., Redacted Labs). Key metrics, such as Total Value Locked (TVL) and annual percentage yield (APY), are also shown if available.

1. **Vault Market**: Each vault lists the token pair it supports, such as **WSEI-USDC**.
2. **Strategy and Manager**: Each vault is managed by a specific strategy (like **Kandel**) and a vault manager (such as **Redacted Labs**).
3. **APY and TVL**: View potential returns (APY) and the total funds locked in the vault (TVL).
   * **Filter and Search Options**: Use the **Search Vault** bar to find a specific vault by name or market. You can also use the **Filter** button to narrow down the list based on different criteria.

<figure><img src="/files/2yOA4TIha5InZg68ETu4" alt=""><figcaption></figcaption></figure>

**Step 3: Selecting a Vault and Viewing Details**

1. **Select a Vault**: Click on a vault from the list to view more detailed information. This will open the **Vault Details** page, providing deeper insights into the vault’s performance and requirements.
2. **Vault Details Overview**:
   * **TVL and APY**: Shows the total value locked in the vault and its projected annual yield.
   * **Performance Fee**: This is the percentage fee taken by the vault manager from the profits generated.
   * **Strategy and Manager**: Details on the strategy used in the vault and the entity managing it.
   * **Deposit and Withdrawal Options**: The page provides sections for **Deposit** and **Withdraw**, allowing you to manage your funds within the vault.
3. **Vault Description and Charts**: Each vault includes a description (currently placeholder text in some cases) and a **performance chart** displaying metrics like APY and TVL trends over time. Charts labeled "Vault charts coming soon!" indicate that historical data is not yet available.

#### **Step 4: Depositing Funds into a Vault**

1. **Deposit Section**: On the right side of the Vault Details page, you’ll find the **Deposit** section.
2. **Select Deposit Amount**:
   * You can deposit tokens like WSEI or USDC by selecting the desired amount. Use the percentage shortcuts (25%, 50%, 75%, Max) to quickly choose how much of your balance you want to deposit.
3. **Confirm Deposit**: Once you’ve selected the amount, click the **Deposit** button. Confirm the transaction in your wallet to finalize the deposit.

   **Note**: Ensure you have enough tokens in your wallet for the selected deposit, as well as enough to cover any network fees.

<figure><img src="/files/WbY0GfQeWHBxrpsK3OHT" alt=""><figcaption></figcaption></figure>

**Step 5: Withdrawing Funds from a Vault**

1. **Withdraw Tab**: Next to the Deposit tab, you’ll see the **Withdraw** tab. Click here if you wish to remove funds from the vault.
2. **Select Withdrawal Amount**: Choose the percentage of your funds in the vault you’d like to withdraw (25%, 50%, 75%, Max).
3. **Confirm Withdrawal**: Click the **Withdraw** button and confirm the transaction in your wallet to complete the withdrawal process.

   **Note**: Be aware of any withdrawal fees or delays that might apply depending on the vault’s strategy.

#### **Step 6: Monitoring Your Position and Rewards**

1. **My Position**: Under **My Position**, you can track your current balances in the vault, including each token (e.g., WSEI and USDC), the minted amount of any vault-specific tokens, and other details.
2. **Rewards**: Below My Position, you’ll see the **Rewards** section, which shows any rewards you’ve accrued from the vault. Click **Claim Rewards** to transfer any available rewards to your wallet.


# Perpetuals

To get started with Perps Trading on Oxium, head over to the dApp.

## 1. Enable Trading

<figure><img src="/files/CXbWpE7ICcTAiu6wF43N" alt=""><figcaption></figcaption></figure>

* Connect your wallet
* Click "Enable Trading"

This will automatically create your Perpetuals account for you.

***

## 2. Deposit

<figure><img src="/files/et7kzBikM2KhFuHx3pTl" alt=""><figcaption></figcaption></figure>

Time to fund your Perpetuals Wallet.

* Click "Deposit"
* Select the amount you want to use for Perps Trading
* Confirm

Your Perpetuals Account is now funded and you're ready to trade.

***

## Market Order

<figure><img src="/files/a8PAUrCIm2D9A5Ho2Tyx" alt=""><figcaption></figcaption></figure>

Execute *immediately* at best available market price.\
By default, swaps are executed as market orders.

**Parameters:**

* Trading pair (e.g. ETH/USDC)
* Long or Short
* Leverage; from 1x up to 100x
* Quantity; the amount of tokens you want to buy

Note: \
Oxium currently offers cross-margin mode. As a trader, you can deposit USDC collateral and it will be shared across all open positions to calculate the margin ratio.

***

## Limit Order

<figure><img src="/files/A2NipVbbZ2bS6kLOHTsA" alt=""><figcaption></figcaption></figure>

Limit Orders allow you to place orders and execute Trades at your desired price, instead of swapping immediately at the current Market Price.\
This allows for efficient and precise swaps at your desired price with automated execution.

Note: \
Oxium currently offers cross-margin mode. As a trader, you can deposit USDC collateral, and it will be shared across all open positions to calculate the margin ratio.

***

## Open Orders, Positions & Order History

<figure><img src="/files/etGrJkYq3IzSBrVMB3AO" alt=""><figcaption></figcaption></figure>

You can see all your Open Orders, current Positions and your previous Order History all in one Tab, and manage them from here.


# Rewards

The **Rewards** page on Oxium’s DApp is where users can monitor their reward progress across different activities, view their rank in the reward program, and claim any available rewards.&#x20;

***

#### **Step 1: Accessing the Rewards Page**

In the Oxium DApp sidebar, click the **"Rewards"** icon (the 'hand bearing a coin' icon). This will take you to the Rewards page, which displays your current rewards, rank, and other details.

#### **Step 2: Understanding the Reward Epoch and Program Details**

1. **Epoch Information**: At the top of the Rewards page, you’ll see the current **Epoch** number and details about the reward cycle. The epoch represents a specific time period over which rewards are calculated.
   * **Ends In** and **Current p** ([Reward rate](broken://pages/tc979j49PmaLpJ2ynL6R)): These fields may indicate the time remaining for the epoch and the current performance level if they are active, helping you track the reward cycle’s progress.
2. **Total Epoch Reward**: The total MGV reward amount available for the current epoch is displayed, broken down into specific reward categories:
   * **Taker Rewards**: Rewards for users who engage in trading activity.
   * **Maker Rewards**: Rewards for liquidity providers.
   * **Kandel Rewards**: Rewards specific to the Kandel strategy (if applicable).

<figure><img src="/files/RyoDPgjnCcfwypfkQ3hN" alt=""><figcaption></figcaption></figure>

#### **Step 3: Tracking Your Points and Rank in Season Program**

1. **Season 1 Points Program**: Below the epoch section, the **Season 1 Points Program** table shows the leaderboard and ranks of users based on their accumulated points. This includes:

   * **Rank**: Your ranking among other participants based on total points.
   * **Address**: The wallet addresses of participants. If you’re logged in, your address will show as "You" in the list.
   * **LP Points**: Points earned from liquidity provision.
   * **Trading Points**: Points from trading activities.
   * **Referral Points**: Points earned by referring others to Oxium.
   * **Community Points**: Points from community engagement.
   * **Total Points**: The sum of all points from the above activities.

   Use this table to view your ranking in the [MS1 Program](broken://pages/03sYZBARrDlklcukw2HU) and, soon, in the [new MGV Incentives' program](broken://pages/UJ1QSVT7GOxZYOHZX9O7) to see how you compare to other participants.

#### **Step 4: Checking Your Available, Claimed, and Total Rewards**

1. **Available Rewards**: On the right side of the page, your **Available Rewards** section shows the amount of MGV tokens you can currently claim. These rewards are updated periodically based on your activity and point accumulation.
2. **Claimed Rewards**: This shows the amount of MGV tokens you’ve already claimed during the current season or epoch.
3. **Total Rewards**: The total amount of MGV rewards you’ve earned, including both claimed and unclaimed tokens.

#### **Step 5: Claiming Your Rewards**

1. **Claim Rewards Button**: If you have available rewards, the **Claim Rewards** button will be active. Click this button to initiate the claiming process.
2. **Wallet Confirmation**: Confirm the transaction in your connected wallet to finalize the claim and transfer the MGV rewards to your wallet.

   **Note**: Ensure you have enough funds to cover any transaction fees on the network.


# Kandel


# Bridge

The **Bridge** feature on Oxium’s DApp, powered by Synapse, enables users to seamlessly transfer tokens across blockchain networks. This functionality is accessible on the **More** page, under the **Bridge** tab, allowing users to move their assets between networks without leaving the Oxium platform.

#### **Step 1: Accessing the Bridge Feature**

1. **Navigate to the More Page**: In the Oxium DApp sidebar, click the **"More"** icon (three dots icon) at the bottom of the sidebar.
2. **Select the Bridge Quick Option** or on the More page, locate the **Bridge** tab at the top. This will open the bridge interface, where you can begin setting up your cross-chain transfer.

<figure><img src="/files/YaDQnYSeEgeqWYBaSpMq" alt=""><figcaption></figcaption></figure>

#### **Step 2: Choosing the Source and Destination Networks**

1. **Select Source Network**: In the bridge interface, use the **Source Network** dropdown (the top section) to select the blockchain network you’re transferring tokens **from** (e.g., **Arbitrum**).
2. **Select Destination Network**: Similarly, use the **Destination Network** dropdown (the bottom section) to select the network you’re transferring tokens **to** (e.g., **Blast**).

   **Note**: Only supported networks will be displayed, and both networks must support the token you wish to transfer.

#### **Step 3: Selecting the Token and Entering the Amount**

1. **Select Source Token**: Click on the **Token** dropdown within the Source Network section to choose the token you want to transfer. The interface will display only tokens that are available for bridging between the chosen networks.
2. **Enter Amount**: Input the amount of the token you wish to transfer. Ensure that you have enough balance in your wallet for the selected amount, as well as additional funds to cover any transaction fees.

   **Note**: Minimum and maximum transfer limits may apply based on the networks and token chosen.

<figure><img src="/files/N5R4X12ffWMfGMD4ZUMh" alt=""><figcaption></figcaption></figure>

#### **Step 4: Confirm and Send the Transaction**

1. **Review Details**: Double-check the network, token, and amount details to ensure accuracy. Transferring assets across networks involves fees and may not be reversible, so confirming the details is crucial.
2. **Send**: Once all details are verified, click the **Send** button to initiate the transfer.

   **Wallet Confirmation**: You’ll need to confirm the transaction in your wallet, including any gas fees associated with the source network.

#### **Step 5: Switching Networks (If Necessary)**

1. **Network Switch Prompt**: If the transfer requires you to interact with a different network, a prompt may appear advising you to switch to the destination network for further actions.
2. **Network Switching**: You can easily switch networks by clicking the **Network Selection** dropdown in the top right corner of the DApp interface. Select the destination network to continue interacting with your transferred assets.

   **Note**: A warning message at the bottom of the interface may remind you to switch networks to fully access your transferred funds.

#### **Tips for Using the Bridge**

* **Powered by Synapse**: Oxium’s bridge functionality is supported by Synapse, a trusted protocol for cross-chain transfers. This integration ensures secure and efficient asset transfers.
* **Token Availability**: Check that your selected token is supported on both the source and destination networks to avoid transfer issues.
* **Transaction Fees**: Remember to account for transaction fees on the source network, which will be deducted from your wallet balance.


# Wrap

The **Wrap** feature on Oxium allows you to convert ETH into wETH (Wrapped ETH), which is essential for trading on many decentralized platforms that operate using ERC-20 tokens. Wrapped ETH has the same value as regular ETH but can be used in ERC-20 compatible environments.

#### **Step 1: Accessing the Wrap Feature**

1. **Navigate to the More Page**: In the Oxium DApp sidebar, click the **"More"** icon (three dots icon) at the bottom of the sidebar.
2. **Select the Wrap Quick Option** or on the More page, locate the **Wrap** tab at the top. This will open the bridge interface, where you can begin setting up your cross-chain transfer.

<figure><img src="/files/W1x0zaAbcOidJomA0Gp1" alt=""><figcaption></figcaption></figure>

**Step 2: Wrapping Your ETH**

1. **Enter Amount**: In the **Amount to wrap** field, type the amount of ETH you want to convert into wETH. The interface will display your **current ETH balance** in the bottom right to guide you on how much you have available.
2. **Wrap ETH**: Once you enter the amount, the **Wrap ETH** button will become active. Click this button to initiate the wrapping transaction. You may need to confirm the transaction in your connected wallet (e.g., MetaMask) to complete the wrapping process.
3. **Confirmation**: After the transaction is confirmed on the blockchain, your ETH will be converted into wETH, ready for use in ERC-20 compatible DeFi applications.

<figure><img src="/files/VnUwpAxJSpI7r0ZRtSfT" alt=""><figcaption></figcaption></figure>

**Why Wrap ETH?**

Wrapped ETH is crucial for participating in various DeFi protocols, as it makes your ETH compatible with ERC-20 standards, allowing you to use it in trades, liquidity pools, and other yield-generating strategies on Oxium and other platforms.


# Tokenomics

<figure><img src="/files/yDXaPelrs0SPoBBP9AqZ" alt=""><figcaption></figcaption></figure>

Token Symbol: OXI&#x20;

CA: 0x8EE050F6af49a6B7fd8557d0E75219D66f5F6094

Max Supply: 1,000,000,000

| Allocation                                 | Terms                                                                                                                                                                                                        |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 48% Ecosystem Growth                       | <p>→ 43% User Incentives (Airdrop).<br>— Early Supporters and users who helped bootstrap the product. 8% unlocked at TGE.<br>— 35% for post-TGE incentives and growth.<br><br>→ 5% Grants & Partnerships</p> |
| 10% Protocol Development                   | → 33% at TGE, 67% by a 24-month linear unlock                                                                                                                                                                |
| 7% Oxium Reserve (Treasury/Foundation)     | → 3 month cliff, 36-month vesting                                                                                                                                                                            |
| 8% Liquidity/Exchanges/MM                  | → 100% unlocked at TGE                                                                                                                                                                                       |
| 15% Early Backers (Strategic Participants) | → 3 year vesting, 1 year cliff followed by a 24-month linear unlock                                                                                                                                          |
| 12% Core Contributors (Team)               | → 3 year vesting, 1 year cliff followed by a 24-month linear unlock                                                                                                                                          |


# Rewards Program

<figure><img src="/files/o6b0GikxY1blx2QhkbPT" alt=""><figcaption></figcaption></figure>

## Oxium Airdrop Guide

Climb your leaderboard rank to maximize your airdrop allocation during Oxium's Airdrop program.

🎯 **Earn Points**

* Trading
* Providing Liquidity
* Events & Competitions

⇢ Spot and Perps activity (1:1 weight)\
⇢ Every trade via Oxium's pools counts and compounds your rewards.

⚡ **Multiplier (Boost)**

* Increase your tier level to pump your earnings
* The progress bar helps you to navigate to the next level

⇢ The higher your tier, the stronger your earnings.

🧩 **Referral Rewards:**

* Invite other users to join with your referral link
* Get 10% of all the points of your invitees (PVP!)

⇢ Build your own referral network and climb the ranks together.

***

The edge belongs to those who act first. It's time to get started, anon.

🔗  [*https://app.oxium.xyz/points* ](https://app.oxium.xyz/points)

{% hint style="info" %}
The reward system is designed to stay fair and resistant to exploitation; the exact calculation formula is not publicly disclosed.\
Oxium reserves the right to adapt or modify the program at any time without prior notice.
{% endhint %}


# Perps Trading Competition

Join Oxium's Perpetuals Trading Competition and compete for $5,000 in $OXI!

🏆 Prize Pool: $5000 in $OXI\
🤝 Rewards are distributed pro rata based on points in the competition leaderboard

📅 Start: Nov 20, 3PM UTC \
📅  End: Dec 3, 3PM UTC

Climb the Competition Leaderboard to win!

Get started, join the competition now:\
<https://app.oxium.xyz/points>&#x20;

> Points are based on Perps Volume and Fees during the competition period. (\* excluding liquidation fees)

<figure><img src="/files/bcf3kbKxLDLaL95CbRUl" alt=""><figcaption></figcaption></figure>


# DEV DOC


# Contracts


# Getting started

The tutorials all rely on the [preparation](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/tutorials/preparation.md) step to be done.


# Guides


# Cleaning offers

Getting paid to clean Mangrove offer lists.

## Cleaning an offer

Offers on Mangrove may fail. This may be done [on purpose](/mangrove-core/explanations/taker-compensation), or be the result of unexpected conditions. Either way, callers are remunerated for their action by receiving a portion of the [bounty](https://github.com/giry-dev/mangrove-docs/blob/main/offer-maker/offer-provision.md) attached to the failing offer.

## Cleaning bots

Mangrove has been designed such that keeping offer lists clean of failing offers is incentive-compatible. Anyone can run a bot which repeatedly does the following:

1. Receive events from Mangrove to maintain an up-to-date view of the books.
2. Locally runs offers at regular intervals.
3. Detects failing offers and sends a transaction to make the offer fail on-chain, with a gas price set such that the offer's bounty compensates for the spent gas.

Mangrove provides a [cleaner contract ](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/how-to-guides/broken-reference/README.md)to help you. This contract provides the same interface as [snipes](/mangrove-core/technical-references/taking-and-making-offers/taker-order#offer-sniping) but will revert if any offer in the `targets` array successfully executes.

{% hint style="info" %}
**Example scenario**

1. Your bot has 900 DAI tokens, has given Mangrove an allowance to spend its DAI, and has given the cleaner contract an [allowance](/mangrove-core/technical-references/taking-and-making-offers/taker-order/delegate-takers) to use its DAI on Mangrove.
2. You detect that offer #708, which `wants` 800DAI and `gives` 800 USDC on the USDT-DAI offer list, fails on your local fork of mainnet, so you call the cleaner contract with `targets` [set to](/mangrove-core/technical-references/taking-and-making-offers/taker-order#offer-sniping) `[[708,type(uint96).max,0,type(uint).max]]`, and `fillWants` set to `false`.
3. Mangrove will use your DAI to execute offer #708 and revert after noticing that the offer fails. It will then transfer the offer bounty to you.
4. If the offer does not fail, the cleaner contract will revert.
   {% endhint %}

### Delegation

Cleaning can also use Mangrove's [delegation mechanism](/mangrove-core/technical-references/taking-and-making-offers/taker-order/delegate-takers), which means you only need Mangrove to have an allowance on any address that that has enough *inbound* tokens of the [offer list](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/how-to-guides/broken-reference/README.md) you are targeting. The cleaner contract will use those funds to execute the cleaning.

{% hint style="info" %}
**Example scenario**

1. The address `funder.eth` has 900 DAI tokens and given Mangrove an allowance to spend its DAI. Offer #708 is still failing.
2. You call the cleaner contract with the same `targets` as above, and `taker` set to `funder.eth`.
3. Mangrove will use `funder.eth`'s DAI to execute offer #708 and revert after noticing that the offer fails. It will then transfer the offer bounty to you.
4. If the offer succeeds, Mangrove will notice that you had no allowance to use `funder.eth`'s DAI on Mangrove and revert (if you did have a high enough allowance, and the sniping succeeds, the cleaner contract will revert anyway).
   {% endhint %}


# How to create a Direct contract

This section will go through a few different ways of how a Direct contract could be implemented. If you don't know what a Direct contract is, we recommend reading both [MangroveOffer](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/mangrover-offer.md) and [Direct](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/Direct.md) before continuing.

## Simple Direct implementation

When creating a Direct contract, the first thing you need is to import the necessary contracts needed for the constructor. Next is creating a constructor that calls the constructor of Direct. We set the gas requirement to 30.000, since we are not doing much in the posthook, it does not need anymore than that.

In the constructor we check if the deployer of the contract is the same as `msg.sender`, if not, it means that the sender is deploying the contract on behalf of another address and wants that address to be admin of the contract.

```solidity
pragma solidity ^0.8.10;

pragma abicoder v2;

import {Direct, AbstractRouter, IMangrove, IERC20} from "src/strategies/offer_maker/abstract/Direct.sol";
import {IMakerLogic} from "src/strategies/interfaces/IMakerLogic.sol";

contract OfferMaker is Direct {

  constructor(IMangrove mgv, AbstractRouter router_, address deployer) Direct(mgv, router_, 30_000) {
    // stores total gas requirement of this strat (depends on router gas requirements)
    // if contract is deployed with static address, then one must set admin to something else than msg.sender
    if (deployer != msg.sender) {
      setAdmin(deployer);
    }
  }
...
```

Technically Direct does not require anything else. But since the `_newOffer` function of Direct is an internal function, deploying the contract as-is, would not allow anyone to post an offer. Because of this we want to add one thing. We want to implement the `IMakerLogic`, which only says that the contract has to have a `newOffer` function with the correct parameters. You could choose to not use this interface, but it is a nice help, that enforces that the offer maker gives all the relevant information for posting a new offer. Using `IMakerLogic` also makes it compatible with the Mangrove SDK, which expects the `IMakerLogic` ABI. Since we only want the admin of the contract to be able to post offers, we add the modifier `onlyAdmin` to the function. This is a modifier Direct can use, because it is a `AccessControlled` contract.

When this is added, then the contract is ready to be [deployed](/mangrove-core/how-to-guides/howtodeploy). The contract can now post new offers, update offers and retract offers, using all the default behavior from a Direct contract.

The full code can be found in [here](https://github.com/mangrovedao/mangrove-core/blob/master/src/strategies/offer_maker/OfferMaker.sol).

```solidity
...

  function newOffer(
    IERC20 outbound_tkn,
    IERC20 inbound_tkn,
    uint wants,
    uint gives,
    uint gasreq,
    uint gasprice,
    uint pivotId
  ) public payable override onlyAdmin returns (uint offerId) {
    offerId = _newOffer(
      OfferArgs({
        outbound_tkn: outbound_tkn,
        inbound_tkn: inbound_tkn,
        wants: wants,
        gives: gives,
        gasreq: gasreq,
        gasprice: gasprice,
        pivotId: pivotId,
        fund: msg.value,
        noRevert: false,
        caller: msg.sender
      })
    );
  }
}
```

## Posting ghost liquidity with Direct

One option when using Direct/MangroveOffer is to not only post one offer but two or more. E.g. lets say you want to sell some WETH, but you do not care if you get USDC or DAI in return. That means you could post 2 equivalent offers, one WETH/USDC and one WETH/DAI. And when one of the offers was taken, you would like to retract the other offer. This means that you don't actually have enough WETH for both offers, but it doesn't matter since we're retracting the offer, as soon as it is taken. Doing this, makes the "retracted offer" a "Ghost" offer.

As before we start by creating a constructor, since we now want to post 2 offers, we need some information about what kind of offers the contract should post. The contract needs to know the `BASE` token, and what 2 kinds of stable coins to post (`STABLE1` & `STABLE2`). These are saved in public immutable variables. Besides knowing what kind of tokens that should be used for the offers, the contract needs to know the ids of the offers. This is needed to be able to retract the offers in posthook. We again call the Direct contract, but this time we set the gas requirement to 100.000, because our posthook will require more gas.

In the constructor for Ghost, we create a SimpleRouter and sets it as the router for the contract. It also binds the contract address to the router, allowing the contract to use the router and sets the admin of the router as the given admin. Direct does not require a router, but we use one in this example to show how to use one. The last thing is to set the admin of the contract, to the admin given to the constructor.

```solidity
pragma solidity ^0.8.10;

pragma abicoder v2;

import {Direct, IMangrove, IERC20 } from "src/strategies/offer_maker/abstract/Direct.sol";
import {SimpleRouter, AbstractRouter} from "src/strategies/routers/SimpleRouter.sol";
import {MgvLib, MgvStructs} from "src/MgvLib.sol";

contract Ghost is Direct {
  IERC20 public immutable BASE;
  IERC20 public immutable STABLE1;
  IERC20 public immutable STABLE2;

  uint offerId1; // id of the offer on stable 1
  uint offerId2; // id of the offer on stable 2

  constructor(IMangrove mgv, IERC20 base, IERC20 stable1, IERC20 stable2, address admin)
    Direct(mgv, NO_ROUTER, 100_000)
  {
    // SimpleRouter takes promised liquidity from admin's address (wallet)
    STABLE1 = stable1;
    STABLE2 = stable2;
    BASE = base;
    AbstractRouter router_ = new SimpleRouter();
    setRouter(router_);
    // adding `this` to the allowed makers of `router_` to pull/push liquidity
    // Note: `reserve(admin)` needs to approve `this.router()` for base token transfer
    router_.bind(address(this));
    router_.setAdmin(admin);
    setAdmin(admin);
  }
}
```

As before we need to create a way for the offer maker to post an offer. Before we used IMakerLogic, because it helped us using the correct parameters. But for ghost we already know some of the parameters beforehand, since we gave them in the constructor. We know the inbound and the outbound of both offers. Besides this we don't want the offer maker to specify the gas price and gas requirement, but just use the standard implementations. Because of this, we don't use IMakerLogic for this contract. If the gas price is left at zero, then Mangrove will use its own gas price. And for the gas requirement, we can use the function ´offerGasreq()´ which returns the gas requirement for the contract plus the gas requirement for the router. Because of this we only have to give the amount of `gives` which is the base token, amount of stable1 and stable2 (`wants1` & `wants2`) and the pivots for the to offers (`pivot1` & `pivot2`). As before, we only want the admin of the contract to able to post offers, so we add the modifier `onlyAdmin`.

This contract will only be able to handle 1 pair of offers, because of this we have to check if the 2 offers are already active when we try to post new offers. Mangrove offers a way to do this, by calling `MGV.isLive(offer)` and we can get the offer by calling `MGV.offers(outbound,inbound,offerId)`. This way we can require that both offers are inactive.

An offer is inactive if `gives` of the offer is zero. This means that there are different ways an offer can become inactive. One way is that the offer has never been posted before, but another way could be that the offer had been posted and the fully taken or retracted. If an offer is fully taken or retracted, then the offer still exist, but it is just inactive. The reason for this is, that Mangrove can reuse the offer, instead of posting a completely new offer. Updating an offer is cheaper in gas, than posting a new one. Because of this we need to handle if we should post new offers or update the offers.

We first setup all the arguments that is required for posting or updating an offer. The first offer uses everything relevant for offer1 and the second offer uses everything relevant for offer2. But one difference is that we choose to fund everything through the first offer and nothing through the second offer. Because Direct can only be used by one offer maker, then there is no bookkeeping on how much was funded foreach offer, since all offers a poster by the same offer maker.

To know if an offer already exist or not, we have to get more details from the offers. We do this using `MGV.offerDetails(outbound,inbound, offerId)`. This gives you a packed version of the details. From the this the maker of the offer can be retrieved. If the maker of the offer is empty, it means that the offer doesn't exist.

We now have all the necessary information to know if we should post a new offer or updated one. We then create a function `postOrUpdateOffer` that checks whether the maker is empty and then either posts a new offer or updates the existing one. If it is post a new offer, it will return the new offer id else it will return the old offer id. We use this function for both offers, save the offer ids and return the ids.

Our contract can now post new offers and update them if they are inactive.

```solidity
  function newGhostOffers(
    // this function posts two asks
    uint gives,
    uint wants1,
    uint wants2,
    uint pivot1,
    uint pivot2
  ) external payable onlyAdmin returns (uint, uint) {

    MgvStructs.OfferPacked offer1 = MGV.offers(address(BASE), address(STABLE1), offerId1);
    MgvStructs.OfferPacked offer2 = MGV.offers(address(BASE), address(STABLE2), offerId2);

    require(!MGV.isLive(offer1), "Ghost/offer1AlreadyActive");
    require(!MGV.isLive(offer2), "Ghost/offer2AlreadyActive");

    OfferArgs memory offerArgs1 = OfferArgs({
      outbound_tkn: BASE,
      inbound_tkn: STABLE1,
      wants: wants1,
      gives: gives,
      gasreq: offerGasreq(),
      gasprice: 0,
      pivotId: pivot1,
      fund: msg.value,
      noRevert: false,
      owner: msg.sender
    });

    OfferArgs memory offerArgs2 = OfferArgs({
      outbound_tkn: BASE,
      inbound_tkn: STABLE2,
      wants: wants2,
      gives: gives,
      gasreq: offerGasreq(),
      gasprice: 0,
      pivotId: pivot2,
      fund: 0, // no need to fund this second call for provision since the above call should be enough
      noRevert: false,
      owner: msg.sender
    });

    MgvStructs.OfferDetailPacked offerDetails1 = MGV.offerDetails(address(BASE), address(STABLE1), offerId1);
    MgvStructs.OfferDetailPacked offerDetails2 = MGV.offerDetails(address(BASE), address(STABLE2), offerId2);

    offerId1 = postOrUpdateOffer(offerArgs1, offerDetails1, offerId1);
    offerId2 = postOrUpdateOffer(offerArgs2, offerDetails2, offerId2);
    return (offerId1, offerId2);
  }

  function postOrUpdateOffer(OfferArgs memory offerArgs, MgvStructs.OfferDetailPacked offerDetails, uint offerId)
    internal
    returns (uint)
  {
    if (offerDetails.maker() == address(0)) {
      return _newOffer(offerArgs);
    } else {
      _updateOffer(offerArgs, offerId);
      return offerId;
    }
  }
```

Since we now can post new offers, these offer will get taken at some point. And if one of the offers was taken, we wanted to retract the other offer, since we no longer have the funds for that offer. To do this we use the hook `posthookSuccess`. This hook gets called if the offer was successfully taken.

The first thing we want to do is use Directs own implementation of `posthookSuccess`. This makes sure to repost the offer if it was only partially taken. Next we need to figure out which of the two offers was taken. In `SingleOrder`we can get what the inbound token was for the taken offer. Using this we can figure out if it was `STABLE1` or `STABLE2`, and thereby also the offer id.

Next we need to know whether the Directs `posthookSuccess` reposted the offer or not. Posthooks returns values that the offer maker can use, to know what the hook did and if the was a success. In this case, if the posthook returns `posthook/reposted` it means that the posthook successfully reposted the offer. Knowing that the offers was reposted, we now know that the other offer also needs to be updated, to use the correct gives and wants.

To do this we need information about the remaining `gives` of the offer, so we use `residualGives`, which calculates the remaining `gives`. And we again use `MGV.offers()` and `MGV.offerDetails` to get information about the other offer. With this information we now know what the old `wants` was for the offer and the old and new `gives` for the offer. Using this we can calculate what the new `wants` should be.

With this we can now use Directs own `updateOffer` (you should always use the contracts own newOffer, updateOffer or retractOffer, and never call Mangrove directly, since Direct/Forwarder/MangroveOffer might do some extra bookkeeping). We use the same gas requirement as the old offer, since it still requires the same amount of gas. We use a pivot id right next to the old, since this offer basically the same price as the old one. If we use zero as pivot id, it might be very gas costly the find the right position for the offer. When the offer is updated, we return a value that indicates that this hook successfully reposted both offers.

We can now handle if the offer was partially taken and the other offer needed to be updated. But we still need to handle if the offer was fully taken or the posthook failed. In the case where the offer was fully taken, we want only want to retract the other offer, but if the posthook failed, we want to retract both offers. If `posthookSuccess` failed, then we don't know why and the safest is to retract both offers. We can use the returned value from `posthookSuccess` to check if the offer was fully taken (`posthook/filled`) or failed (any other value). When we retract the offers, we don't want to deprovision. Since deprovisioning is gas costly, it is better to leave the funds, this way the provision can be used to post a new offer, without having to fully fund the new offer. Lastly we return a value that indicates that both offers have been retracted.

The `posthookSuccess`is now done and we can handle the different scenarios that might be triggered.

```solidity
function __posthookSuccess__(MgvLib.SingleOrder calldata order, bytes32 makerData)
    internal
    override
    returns (bytes32)
  {
    bytes32 repost_status = super.__posthookSuccess__(order, makerData);
    (IERC20 alt_stable, uint alt_offerId) =
      IERC20(order.inbound_tkn) == STABLE1 ? (STABLE2, offerId2) : (STABLE1, offerId1);

    if (repost_status == "posthook/reposted") {
      uint new_alt_gives = __residualGives__(order); // in base units
      MgvStructs.OfferPacked alt_offer = MGV.offers(order.outbound_tkn, address(alt_stable), alt_offerId);
      MgvStructs.OfferDetailPacked alt_detail = MGV.offerDetails(order.outbound_tkn, address(alt_stable), alt_offerId);

      uint old_alt_wants = alt_offer.wants();
      uint old_alt_gives = order.offer.gives();
      uint new_alt_wants;
      unchecked {
        new_alt_wants = (old_alt_wants * new_alt_gives) / old_alt_gives;
      }
      // the call below might throw
      updateOffer({
        outbound_tkn: IERC20(order.outbound_tkn),
        inbound_tkn: IERC20(alt_stable),
        gives: new_alt_gives,
        wants: new_alt_wants,
        offerId: alt_offerId,
        gasreq: alt_detail.gasreq(),
        pivotId: alt_offer.next(),
        gasprice: 0
      });
      return "posthook/bothOfferReposted";
    } else {
      // repost failed or offer was entirely taken
      if (repost_status != "posthook/filled") {
        retractOffer({
          outbound_tkn: IERC20(order.outbound_tkn),
          inbound_tkn: IERC20(order.inbound_tkn),
          offerId: order.offerId,
          deprovision: false
        });
      }
      retractOffer({
        outbound_tkn: IERC20(order.outbound_tkn),
        inbound_tkn: IERC20(alt_stable),
        offerId: alt_offerId,
        deprovision: false
      });
      return "posthook/bothRetracted";
    }
  }
```

When writing posthooks, you want to consider all outcomes. The first outcome was that the offer was successfully, but i might be that the offer failed when it was taken. This now means that the offer that was unsuccessfully taken, is now inactive, but the other offer, would probably also fail, if the first offer failed. For this reason we want to write a `posthookFallback` that makes sure to retract the other offer.

Just as we did in the `posthookSuccess`, we find the inbound token and offer id, by looking at the inbound token of the offer that failed. This way we now know which offer we want to retract. When retracting the offer, we again choose to not deprovision, for the same reason as in `posthookSuccess`. Lastly we return a value that indicates that both offers failed.

The `posthookFallback` is now done and we can handle if the offer was unsuccessfully taken.

```solidity
  function __posthookFallback__(MgvLib.SingleOrder calldata order, MgvLib.OrderResult calldata)
    internal
    override
    returns (bytes32)
  {
    // if we reach this code, trade has failed for lack of base token
    (IERC20 alt_stable, uint alt_offerId) =
      IERC20(order.inbound_tkn) == STABLE1 ? (STABLE2, offerId2) : (STABLE1, offerId1);
    retractOffer({
      outbound_tkn: IERC20(order.outbound_tkn),
      inbound_tkn: IERC20(alt_stable),
      offerId: alt_offerId,
      deprovision: false
    });
    return "posthook/bothFailing";
  }
```

The contract is almost done. One last thing that we should offer to the offer maker, is to offer a way to get the provision back. This could simply be because the offer maker wants the pull their offers or that the offers had been retracted doing `posthookSuccess` or `posthookFallback` but not deprovisioned (as explained earlier). Since Direct has its own implementation of retracting a offer, the offer maker would technically be able to retract them themselves, but that would require that the offer maker had stored the offer ids themselves, otherwise they would not know what offers to retract. One way of fixing this would be to make the offer ids of the Ghost contract public, this way the offer maker would be able to retrieve the offer ids themselves and then retract the offers, but another way would be to create a function that would retract both offers. In this example we choose to make a retract function that retracts both offers.

Since we know everything about the two offers, retracting them is simple calling Directs own retractOffer function on both offers. The offer maker might just want to retract the offers, without deprovisioning them, because of this we add a parameter to the function, that tells if the offers should be deprovisioned.

The offer maker can now post new offer, where all posthooks are handled and they can retract their offers again. The contract is now done. The next thing would be to test that the contract works as planned. This can be found in this [section](/mangrove-core/how-to-guides/howtotest).

The full code for the contract can be found [here](https://github.com/mangrovedao/mangrove-core/blob/master/src/toy_strategies/offer_maker/Ghost.sol)

```solidity
  function retractOffers(bool deprovision) public {
    retractOffer({outbound_tkn: BASE, inbound_tkn: STABLE1, offerId: offerId1, deprovision: deprovision});
    retractOffer({outbound_tkn: BASE, inbound_tkn: STABLE2, offerId: offerId2, deprovision: deprovision});
  }
```


# How to test your contract

You have now created your contract and would like to test it. Mangrove offers a helper contract, that can help setup everything needed for writing a test using the Mangrove core protocol.

When we write test we are going to be using the framework [Foundry](https://book.getfoundry.sh/). Foundry is a smart contract development toolchain.

When explaining "how to test" we are going to use the Ghost contract, created in [How to create a Direct contract](/mangrove-core/how-to-guides/directhowto).

When creating your test, remember to use the naming convention `<name>.t.sol`, this way Foundry knows what files are test. The first thing to do is to import the relevant contracts. We are going to use `MangroveTest` which is a helper to setup the Mangrove protocol. This way you do not need to fork a existing chain, it can just deploy the Mangrove protocol for you before running your tests. It has many other helpers. We import `Polygon` which is a helper to fork the polygon chain, we do this because we want to use the real address for WETH, USDC and DAI. This is not necessary, one could just create some test tokens an use them. We import the Ghost contract, because that is the contract we want to test. The last thing is `MgvStructs`, this helps with getting information about offers, which we need later in the test.

The console import is not needed, but can be very useful, if you want to log something during your test. Debugging solidity code is not that easy, so using console logs is sometimes faster.

Then we create a contract called GhostTest that inherence from MangroveTest. Making the contract a MangroveTest makes it possible to use all its helper functions. There is a few variable we know we are going to need, in order to test Ghost, we need 3 tokens, the fork the test should run on, a taker address and the Ghost contract.

The receive function is defined in order for the test contract to be able to receive funds. In this test we are going to use the test contract as a offer maker, this means that it should be able to receive funds. A contract i solidity that does not have the receive function defined, will not be able to receive any funds.

Before we run any tests, we want to create a setUp function that gets called before the actual test gets called. In Foundry creating a function called setUp will automatically make it run before the tests. In this case MangroveTest already has a setUp function, because of this we override it, since we only want to do part of the default setup.

In the setup function we start by creating a fork from the polygon chain and run its setup function. Next we need to setup Mangrove using the helper function from MangroveTest. We then get the 3 tokens from the polygon chain, all the addresses can be found in the `polygon.json` file where some standard addresses are saved.

The Ghost contract is using two markets, it is there for necessary to setup the 2 markets, in this case we are using DAI/WETH and USDC/WETH market. The last thing is creating the taker address, giving it some native tokens (to pay for gas), some DAI and USDC (to be able to take the offers) and approving Mangrove to take the funds. I order to approve Mangrove the taker has to call the approve function on each token, giving the address for Mangrove. Here we are using 3 helper functions `startPrank(<address>)`, `stopPrank(<address>` and `$`. The start and stop prank, are cheatcodes offered by Foundry, they make it possible to impersonate an address as if it was that address calling. This is makes it possible for us to call as the taker and approve Mangrove. This is only possible because we are in a test, using Foundry and not on any real chain, otherwise this would not be possible. The last helper function is `$`, this MangroveTest offer a shorthand for writing `address()` and casting the contract to its address.

The setup is done, at we are now ready to write the first test.

```solidity
import {MangroveTest} from "mgv_test/lib/MangroveTest.sol";
import {PolygonFork, PinnedPolygonFork} from "mgv_test/lib/forks/Polygon.sol";
import {Ghost, IMangrove, IERC20} from "src/toy_strategies/offer_maker/Ghost.sol";
import {MgvStructs} from "src/MgvLib.sol";
import {MgvReader} from "src/periphery/MgvReader.sol";

import {console} from "lib/forge-std-vendored/src/console.sol";

contract GhostTest is MangroveTest {
  IERC20 weth;
  IERC20 dai;
  IERC20 usdc;

  PolygonFork fork;

  address payable taker;
  Ghost strat;

  receive() external payable virtual {} // Needed if the contract should receive funds

  function setUp() public override {
    // use the pinned Polygon fork
    fork = new PinnedPolygonFork(); // use polygon fork to use dai, usdc and weth addresses
    fork.setUp();

    // use convenience helpers to setup Mangrove
    mgv = setupMangrove();

    // setup tokens, markets and approve them
    dai = IERC20(fork.get("DAI"));
    weth = IERC20(fork.get("WETH"));
    usdc = IERC20(fork.get("USDC"));

    setupMarket(dai, weth);
    setupMarket(usdc, weth);

    // setup separate taker and give some native token (for gas) + USDC and DAI
    taker = freshAddress("taker");
    deal(taker, 10_000_000);

    deal($(usdc), taker, cash(usdc, 10_000));
    deal($(dai), taker, cash(dai, 10_000));

    // approve DAI and USDC on Mangrove for taker
    vm.startPrank(taker);
    dai.approve($(mgv), type(uint).max);
    usdc.approve($(mgv), type(uint).max);
    vm.stopPrank();
  }
...
```

When creating test using Foundry, you have to name the function that runs the test `test<the name>`. This way Foundry knows what functions are tests. I our first test we want to test that when the offer is fully taken, we therefore call the test `test_success_fill`.

The first thing we need to do in our test is to deploy the Ghost contract on our local chain. Since we know that this is going to be necessary for all the test, we write how to deploy the test on the local chain in its own function.

Deploying a contract locally is just calling its constructor of the contract. We are setting address of the testing contract(`$(this)`), as admin of the Ghost contract, this way we can use the testing contract as maker. When the contract is deployed, we then need to activate it. We know which tokens we are going to use, so we first create an array with the 3 tokens, next we call Ghost to check if any of the tokens have the correct approvals. Since we haven't activated Ghost, we then expect it to revert with a specific message. Foundry has a cheatcode to catch excepted reverts called `expectRevert(<message>)`. This way we can call the checklist and see if the get the expected revert. The last thing we do in our deploy function, is activating Ghost for the tokens we need.

```solidity
  function test_success_fill() public {
    deployStrat();

    execTraderStratWithFillSuccess();
  }

  function deployStrat() public {
    strat = new Ghost({
      mgv: IMangrove($(mgv)),
      base: weth,
      stable1: usdc, 
      stable2: dai,
      admin: $(this) 
      });

    IERC20[] memory tokens = new IERC20[](3);
    tokens[0] = dai;
    tokens[1] = usdc;
    tokens[2] = weth;

    vm.expectRevert("mgvOffer/LogicMustApproveMangrove");
    strat.checkList(tokens);

    // and now activate them
    strat.activate(tokens);
  }
```

We now have a function that can deploy a new Ghost contract on our local chain. Next is writing the actual test. In the first test we want to create a new offer using Ghost, sniping one of the offer and then checking that the maker and taker got what they were promised and that both offers now are inactive.

First we save what amounts we want to use for the 2 offers. For the amount of WETH, we use the solidity shorthand `ether`. This is a way of multiplying a number with 10^18, which is the number of decimals ether has and because we are using WETH, it as the same amount of decimals. For both DAI and USDC we use the function `cash(token, amount)`. This is a helper function by MangroveTest, it makes sure to multiply the amount with the correct amount of decimals that the token is using. This way we now have the correct amounts of all tokens, using the correct decimals for each token.

Next we need to approve the router of Ghost the use the WETH of the tester contract. This is needed because we are using the tester contract as the reserve for Ghost. We then need to give the tester contract som WETH in order to be able to complete the offers. Foundry has a cheatcode to give an address an amount of a token. This function is called `deal(address_of_token, address_to_receive_token, amount)`. We again use weth in order to use the correct amount of decimals.

```solidity
  function execTraderStratWithFillSuccess() public {
    uint makerGivesAmount = 0.15 ether;
    uint makerWantsAmountDAI = cash(dai, 300);
    uint makerWantsAmountUSDC = cash(usdc, 300);

    weth.approve($(strat.router()), type(uint).max);

    deal($(weth), $(this), cash(weth, 10));

    (uint offerId1, uint offerId2) = postAndFundOffers(makerGivesAmount, makerWantsAmountDAI, makerWantsAmountUSDC);

    (uint takerGot, uint takerGave,) = takeOffer(makerGivesAmount, makerWantsAmountDAI, dai, offerId1);

    // assert that
    assertEq(takerGot, minusFee($(dai), $(weth), makerGivesAmount), "taker got wrong amount");
    assertEq(takerGave, makerWantsAmountDAI, "taker gave wrong amount");

    // assert that neither offer posted by Ghost are live (= have been retracted)
    MgvStructs.OfferPacked offer_on_dai = mgv.offers($(weth), $(dai), offerId1);
    MgvStructs.OfferPacked offer_on_usdc = mgv.offers($(weth), $(usdc), offerId2);
    assertTrue(!mgv.isLive(offer_on_dai), "weth->dai offer should have been retracted");
    assertTrue(!mgv.isLive(offer_on_usdc), "weth->usdc offer should have been retracted");
  }
```

We are now ready to post the offers using Ghost and take one of the offers. Posting new offers and taken an offer, is something all the test are going to do, so we implement a function for each thing. This way we make it easier to write the next test.

When posting offers using ghost, we need to fund it, in order to cover gas and provision, giving 1 ether is more than enough to cover the gas. For the pivot ids, we just give 0, since we know that there are no other offers on those markets.

When taking an offer, we need to know what offer to take. Because of this we need the inbound token, in order to snipe the correct offer. We again use a cheatcode by Foundry `prank(address)`, this works like `startPrank`but only for the next call, where `startPrank` works for all calls, until `stopPrank` is called. When using `prank`one should be aware of nested calls, e.g. had we used a call to figure out the pivot1 and just called it inline like this `pivot1: strat.getPivot1()` then it would be that called that gets pranked and not the snipe call.

```solidity
  function postAndFundOffers(uint makerGivesAmount, uint makerWantsAmountDAI, uint makerWantsAmountUSDC)
    public
    returns (uint offerId1, uint offerId2)
  {
    (offerId1, offerId2) = strat.newGhostOffers{value: 1 ether}({
      gives: makerGivesAmount, // WETH
      wants1: makerWantsAmountUSDC, // USDC
      wants2: makerWantsAmountDAI, // DAI
      pivot1: 0,
      pivot2: 0
    });
  }

  function takeOffer(uint makerGivesAmount, uint makerWantsAmount, IERC20 makerWantsToken, uint offerId)
    public
    returns (uint takerGot, uint takerGave, uint bounty)
  {
    // try to snipe one of the offers (using the separate taker account)
    vm.prank(taker);
    (, takerGot, takerGave, bounty,) = mgv.snipes({
      outbound_tkn: $(weth),
      inbound_tkn: $(makerWantsToken),
      targets: wrap_dynamic([offerId, makerGivesAmount, makerWantsAmount, type(uint).max]),
      fillWants: true
    });
  }
```

After having posted and taken one of the offers, we can now check whether everything happen as excepted. We use `assertEq` and ´assertTrue´ which are Foundry methods for asserting. The first thing we want to check, is whether the taker got the expected amount of WETH minus the fees taken by Mangrove. MangroveTest has a function ´minusFee(address\_outbound,address\_inbound, price)´, that will calculate the fee for a given market and price. The next thing is if the taker gave the correct amount of DAI.

Having tested that the taker got and gave the correct amounts, we then want to check whether the offers are no longer live on Mangrove. To do this we use Mangrove to get the packed offers and then using Mangroves `isLive` function to check if an offer is live. In this case we except that both offers are inactive.

```solidity
...
    (uint offerId1, uint offerId2) = postAndFundOffers(makerGivesAmount, makerWantsAmountDAI, makerWantsAmountUSDC);

    (uint takerGot, uint takerGave,) = takeOffer(makerGivesAmount, makerWantsAmountDAI, dai, offerId1);

    // assert that
    assertEq(takerGot, minusFee($(dai), $(weth), makerGivesAmount), "taker got wrong amount");
    assertEq(takerGave, makerWantsAmountDAI, "taker gave wrong amount");

    // assert that neither offer posted by Ghost are live (= have been retracted)
    MgvStructs.OfferPacked offer_on_dai = mgv.offers($(weth), $(dai), offerId1);
    MgvStructs.OfferPacked offer_on_usdc = mgv.offers($(weth), $(usdc), offerId2);
    assertTrue(!mgv.isLive(offer_on_dai), "weth->dai offer should have been retracted");
    assertTrue(!mgv.isLive(offer_on_usdc), "weth->usdc offer should have been retracted");
...
```

We have now written our first test. In Foundry you can run all your tests by running `forge test`, if you want to run only for one specific contract you can add `--match-contract <name_of_contract>` and if you only want to run one test on that contract, you can add `--match-test <name_of_test>`. In our case we would run `forge test --match-contract GhostTest --match-test test_success_fill`. You can get full stacktraces by uses `-vvv`, you can read more about how `--verbose` works on [Foundry](https://book.getfoundry.sh/)'s own website.

Writing your next test is now a lot easier since have create all the helper functions. E.g. writing a test for a on only being partially taken, would look like this:

```solidity
  function test_success_partialFill() public {
    deployStrat();

    execTraderStratWithPartialFillSuccess();
  }

  function execTraderStratWithPartialFillSuccess() public {
    uint makerGivesAmount = 0.15 ether;
    uint makerWantsAmountDAI = cash(dai, 300);
    uint makerWantsAmountUSDC = cash(usdc, 300);

    weth.approve($(strat.router()), type(uint).max);

    deal($(weth), $(this), cash(weth, 5));

    // post offers with Ghost liquidity
    (uint offerId1, uint offerId2) = postAndFundOffers(makerGivesAmount, makerWantsAmountDAI, makerWantsAmountUSDC);

    //only take half of the offer
    (uint takerGot, uint takerGave,) = takeOffer(makerGivesAmount / 2, makerWantsAmountDAI / 2, dai, offerId1);

    // assert that
    assertEq(takerGot, minusFee($(dai), $(weth), makerGivesAmount / 2), "taker got wrong amount");
    assertEq(takerGave, makerWantsAmountDAI / 2, "taker gave wrong amount");

    // assert that neither offer posted by Ghost are live (= have been retracted)
    MgvStructs.OfferPacked offer_on_dai = mgv.offers($(weth), $(dai), offerId1);
    MgvStructs.OfferPacked offer_on_usdc = mgv.offers($(weth), $(usdc), offerId2);
    assertTrue(mgv.isLive(offer_on_dai), "weth->dai offer should not have been retracted");
    assertTrue(mgv.isLive(offer_on_usdc), "weth->usdc offer should not have been retracted");
  }
```

A full test of the contract can be found [here](https://github.com/mangrovedao/mangrove-core/blob/master/test/toy_strategies/Ghost.t.sol).

When you have create all your tests, you may want to deploy your contract to a real chain. Read more about how to deploy [here](/mangrove-core/how-to-guides/howtodeploy).


# How to deploy your contract

After you have created and tested your contract, you might want to deploy it on chain. Deploying a contract is easy with the use of [Foundry](https://book.getfoundry.sh/) and a helper from our Deployer contract.

We start by creating a contract that inherits from Deployer, when creating your script, remember to use the naming convention, `<name>.s.sol`, this way Foundry knows it is a script file. The Deployer contract is meant as an ease of life the user, when they want to deploy a contract. It keeps track of what chain you want to deploy on and saving the addresses for the deployed contracts. If you want to know more of how it works, you can read about it here.

For this guide we will not go into to much detail, the important part is that the deployer keeps track of the chain you want to deploy on. In this example we are going to deploy the contract Ghost, that we created in the [How to create a Direct contract](/mangrove-core/how-to-guides/directhowto).

When creating a script you always need a `run()` function, this is the function that Foundry is going to call when running the script. In this script we need to know who the admin of the contract is. Since you never want to write address directly in your code/script, we use [dotenv](https://www.npmjs.com/package/dotenv), to hide all our secrets in a `.env` file. This way we can use the Foundry cheatcode `envAddress(<name>)` to access the secret addresses we need. In this case the admin address is a public address, so we could write it directly in the code, but if you want to deploy the script again with a different address, it is better to keep the address in a different file. Next we get the addresses for WETH, USDC and DAI, we get the addresses by using `fork.get(<name>)`, this only works because we have a json file with addresses for these tokens `polygon.json` and we know we are going to deploy on a polygon chain. If you want to deploy to a different chain, you would have to have a similar json file with the addresses for that chain.

```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
import {Ghost, AbstractRouter, IERC20, IMangrove} from "mgv_src/toy_strategies/offer_maker/Ghost.sol";
import {Deployer} from "./lib/Deployer.sol";

/*  Deploys a Ghost instance
    First test:
 ADMIN=$MUMBAI_PUBLIC_KEY forge script --fork-url mumbai GhostDeployer -vvv
    Then broadcast and verify:
 ADMIN=$MUMBAI_PUBLIC_KEY WRITE_DEPLOY=true forge script --fork-url mumbai GhostDeployer -vvv --broadcast --verify
    Remember to activate it using Activate
*/
contract GhostDeployer is Deployer {
  function run() public {
    innerRun({
      admin: vm.envAddress("ADMIN"),
      base: fork.get("WETH"),
      stable1: fork.get("USDC"),
      stable2: fork.get("DAI")
    });
  }
...
```

Next we create an `innerRun` function, that does the actual deployment. We get the current Mangrove instance on chain, again by using `fork.get()`. When you deploy a new contract it is always good to consider that you maybe already have a instance of the contract deployed. In this case we would like to see if we have an address for "Ghost" saved already and if so we would like to withdraw everything from Mangrove and retract all offers. This way we know that Ghost no longer has any funds or offers and we can just leave it. The reason we do `try fork.get("Ghost")` is that, if it can't find any address for Ghost, then it will throw an exception. When writing your deployment script using Foundry, there is one command that is essential, which is `broadcast()`. Everything done in the script is just simulation, expect if you use broadcast right before a call, then that specific call is broadcasted to the actual chain. This way you can do many calls, to e.g. figure out the admin of a contract, without you actually having to use any gas on it. And only broadcast the actual thing you want done on chain.

The broadcast used here is actually a helper function that our Deployer contract has. What it does, is it goes out to find your `.env` and looks for a private key with the lookup value of `<nameOfChain>_PRIVATE_KEY`, e.g. if you want to deploy on Mumbai, it looks for a value called `MUMBAI_PRIVATE_KEY`. This is the private key of the address you would like to use for the broadcast. This means that you need this key in your `.env` in order to be able to actually deploy the contract.

As explained we want to withdraw from Mangrove if the Ghost contract has any free native tokens on Mangrove. We first check by using `mgv.balanceOf(<address>)`, notice that we don't use the command broadcast before this call, since we don't want to actually do it on chain. If the balance is positive, the we try to withdraw the funds from Mangrove, notice we use broadcast, because we want this called to be on chain. Be aware that when withdrawing from Mangrove using ghost, then it has to be the admin of the contract that preforms the call. This means, that in this case, the address in the `.env` file has to be the admin of the Ghost contract, otherwise this will not be allowed. After having withdrawn the free tokens form Mangrove, we now retract the offers and deprovisioning them, this returns any provision left on the offers, back to the admin. We do some console logging to check the balances of the admin contract after doing all this. This way it is easy to see if the expected amounts was withdrawn. All this could have been put in its own function, that handles closing a Ghost contract.

```solidity
...
  /**
   * @param admin address of the admin on Ghost after deployment
   * @param base address of the base on Ghost after deployment
   * @param stable1 address of the first stable coin on Ghost after deployment
   * @param stable2 address of the second stable coin on Ghost after deployment
   */
  function innerRun(address admin, address base, address stable1, address stable2) public {
    IMangrove mgv = IMangrove(fork.get("Mangrove"));

    try fork.get("Ghost") returns (address payable old_ghost_address) {
      Ghost old_ghost = Ghost(old_ghost_address);
      uint bal = mgv.balanceOf(old_ghost_address);
      if (bal > 0) {
        broadcast();
        old_ghost.withdrawFromMangrove(bal, payable(admin));
      }
      uint old_balance = old_ghost.admin().balance;
      broadcast();
      old_ghost.retractOffers(true);
      uint new_balance = old_ghost.admin().balance;
      console.log("Retrieved ", new_balance - old_balance + bal, "WEIs from old deployment", address(old_ghost));
    } catch {
      console.log("No existing Ghost in ToyENS");
    }
...
```

After having closed down the old Ghost contract, we now what to deploy a new one. This is very easy, we again use broadcast, when we create the Ghost contract and the Ghost contract is now deployed. After having deployed your contract, you should always think about if there are extra things need, in order to make the contract work. I our case there are multiple things we would like to do after deployment. First we save the new address for the Ghost contract using `fork.set(<address>)`. We then do a simple smoke test, to se if Ghost is actually deployed, we just try to see if Mangrove matches the one we used to deploy it.

Next we do `outputDeployment()`, this is a helper function created by the Deployer contract. This is meant as a simple way to update the json file, containing the addresses. If the flag `WRITE_DEPLOY` is set to true, the default value is false, it writes a new addresses.json file in the deployment folder. You can set the flag in the `.env` or when you run the script.

After having saved all the new addresses, we then need to activate the Ghost contract, so that it is able to trade on the tokens we use to created it. We create an array with the 3 tokens and call activate on the Ghost contract. This is again done with broadcast. The last thing we need is, as admin, to approve the router of Ghost to use the base token. Be aware that we get the router before doing the broadcast, this is because, if you inline it like this `IERC20(base).approve(address(ghost.router()), type(uint).max)`, where we both approve and get the router on the same line, then it would be the call that gets the router, that gets broadcasted. Since it is only the first call after broadcast that will get broadcasted.

Everything is now approve correctly and we check that by calling the checklist function on Ghost. Notice we use `prank`, because we want to call the function, as if we were calling from the ghost contract. We don't use broadcast here, because we do not need the call to be on chain. Had we done the call without `prank` or `broadcast` we would be calling as the `this` which is the script contract, the checklist we then check if the script had the right approvals, but that is not what we wanted to check.

```solidity
...
    console.log("Deploying Ghost...");
    broadcast();
    Ghost ghost = new Ghost(mgv, IERC20(base), IERC20(stable1), IERC20(stable2), admin );
    fork.set("Ghost", address(ghost));
    require(ghost.MGV() == mgv, "Smoke test failed.");
    outputDeployment();
    console.log("Deployed!", address(ghost));
    console.log("Activating Ghost");
    IERC20[] memory tokens = new IERC20[](3);
    tokens[0] = IERC20(base);
    tokens[1] = IERC20(stable1);
    tokens[2] = IERC20(stable2);
    broadcast();
    ghost.activate(tokens);
    AbstractRouter router = ghost.router();
    broadcast();
    IERC20(base).approve(address(router), type(uint).max);
    IERC20[] memory tokens2 = new IERC20[](1);
    tokens2[0] = IERC20(base);
    vm.prank(ghost.admin());
    ghost.checkList(tokens2);
  }
```

The full version of the deployer contract can be found [here](https://github.com/mangrovedao/mangrove-core/blob/master/script/toy/GhostDeployer.s.sol).

The deployment script is now ready, so lets try and deploy it to a local fork of mumbai. The first thing you need to do, is to start an anvil node, running on a fork of mumbai. This can be done like this `anvil --port 8545 --fork-url $MUMBAI_NODE_URL --silent`. Notice at the `MUMBAI_NODE_URL` is fetch of the `.env`file. If you don't have URL, polygon offers one [here](https://wiki.polygon.technology/docs/develop/network-details/network/). When running this the `.env` file might not have been sourced, so you might need to run `source .env`in order for it to find the `MUMBAI_NODE_URL`. The silent flag is not necessary, it is simply a way of starting the node without writing the setup for the fork. This can include secrets that you may not want to share.

When your anvil node is up and running, we can now do the actual deployment. Now at first want to try a deploy Ghost without broadcasting it, this way we can test if it works. This is done my running this in a different terminal, than where the anvil is running. `ADMIN=$MUMBAI_PUBLIC_KEY forge script --fork-url http://127.0.0.1:8545 GhostDeployer -vvv` (Remember that you might have to source your `.env` again in the new terminal). The first thing we do is setting the ADMIN to be the `MUMBAI_PUBLIC_KEY` that you wrote in your `.env` file. This will be the address that the Ghost contract will be deployed with. Next we say that we are using a fork url, that is a localhost of <http://127.0.0.1:8545>. We then write the name of our script and choose to use the verbosity level of `-vvv`. When running this you should see, in the terminal that runs the anvil node, a bunch of view functions being called, like `eth_xxxxx`, but no actual transactions.

If the script successfully ran, then you know that your script works. Not that you know that your script works, we run it again, but this time with the flag `--broadcast`, `ADMIN=$MUMBAI_PUBLIC_KEY forge script --fork-url http://127.0.0.1:8545 GhostDeployer -vvv --broadcast`. This runs the script again, but this time it actually broadcast the transactions you wanted. In the anvil terminal, you will again see the many view functions, but there should now also be actual transactions.

Your contract is now deployed on the chain you specified. In this case we used a local fork of mumbai, but you can easily do the same on a live chain.


# Technical references


# Taking and making offers

Offers on Mangrove leave of [Offer Lists](/mangrove-core/technical-references/taking-and-making-offers/market). Offers can be taken using market orders or snipped individually. Creating offers requires interacting with an onchain [logic](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract#offer-logic) (a smart contract) able to [post](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer#posting-a-new-offer), [update](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer#updating-an-existing-offer) and [execute](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) offers.


# Offer Lists

Introducing Mangrove's Offer Lists a low level representation of (half) an order book.

## General structure

{% hint style="info" %}
The offer list is the basic Mangrove data structure. It contains offers (created by offer makers) that promise an **outbound token**, and request an **inbound token** in return (offer takers execute these offers by providing the **inbound token**, and receive **outbound tokens** in return).

For example in a DAI-wETH offer list, DAI is the outbound token (i.e. sent or given by the offer) and wETH the inbound token (i.e. received or wanted by the offer).

Relationship to markets: a full market will always feature two offer lists. For instance, a wETH/DAI **market** has one DAI-wETH offer list (where wETH is requested and DAI is offered), and a wETH-DAI offer list (where DAI is requested and wETH is offered).\
\
[Mangrove's API ](/mangrove-core/explanations/around-the-mangrove/mangrove-api)offers Market abstractions that allows liquidity providers and takers to interact with Mangrove using standard **base &** **quote** denominations.
{% endhint %}

Here's a sample DAI-wETH offer list with two offers. Only the main characteristics of the offers are shown (see the [offer data structure](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-data-structures#mgvlib-offer)).

{% hint style="warning" %}
**Decimals**

We display human-readable values in the examples, but Mangrove stores raw token values and never uses the `decimals` field of a token.
{% endhint %}

| Rank | Offer ID | Wants (wETH) | Gives (DAI) | Gas required | Maker Contract | Offer Gas Price |
| ---- | -------- | ------------ | ----------- | ------------ | -------------- | --------------- |
| #1   | 77       | 1            | 2 925.26    | 250,000      | 0x5678def      | 150             |
| #2   | 42       | 0.3          | 871.764     | 300,000      | 0x1234abc      | 200             |

## Some terminology

### Offer rank

Offers are ordered from best to worst. Offers are compared based on *price*, and then on *gas required* (see below) if they have the same price.

{% hint style="info" %}
**Example**

The price of offer #42 is 0.0003441298 wETH per DAI while the price of offer #77 is 0.00034185 wETH per DAI. Offer #77 is therefore the best offer (lowest price) of this offer list, and is ranked first.
{% endhint %}

### Offer ID

The identifier of the offer in the offer list.

{% hint style="danger" %}
**Important**

Two offers may have the same ID as long as they belong to different offer lists. For instance, there may be an offer #42 on the wETH-DAI offer list with different volumes, gas required, maker contract, etc. than offer #42 in the DAI-wETH offer list shown above.
{% endhint %}

### Wants, gives and entailed price

Taken together, the **wants** and **gives** values define 1) a max volume, 2) a price. The **entailed price** is p=**wants**/**gives**, and an offer promises delivery of up to **gives** outbound tokens at a price of p tokens delivered per inbound token received.

{% hint style="info" %}
**Examples**

* Offer #42 *wants* 0.3 wETH to deliver its promised 871.764 DAI.
* If offer #77 is executed and receives 0.5 wETH, it must send back 1462.63 DAI.
  {% endhint %}

### Gas required

The maximum amount of gas the [Maker Contract](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) managing the offer will be allowed to spend if called by the Mangrove.

{% hint style="info" %}
**Example**

Offer #77 may consume up to 250K gas units.
{% endhint %}

### Maker Contract

The address of the [offer logic](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract#offer-logic) managing the offer. The `makerExecute` function of this contract will be called when one of its offers is executed.

### Gas Price

Gas price that was used to compute the [offer provision](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision). If the offer fails to deliver the promised **outbound tokens**, it will be charged in ETH based on this gasprice.

## Offer list configuration

Several [configuration](/mangrove-core/technical-references/governance-parameters/mangrove-configuration) parameters determine how new offers are inserted. Some are [global](https://docs.oxium.xyz/mangrove-core/technical-references/taking-and-making-offers/pages/pF6T9izqF21UiijXXJft#mgvlib.global) to Mangrove, some are [offer list specifics.](https://docs.oxium.xyz/mangrove-core/technical-references/taking-and-making-offers/pages/pF6T9izqF21UiijXXJft#mgvlib.local) See [Governance](/mangrove-core/technical-references/governance-parameters) section for details.


# Views on offers

Mangrove getters for offers and offer lists.

## Public getters

### `best(address outbound, address inbound)`

{% hint style="info" %}
Returns the offer identifier that occupies the best [rank](/mangrove-core/technical-references/taking-and-making-offers/market#offer-rank) in the `(outbound, inbound)`[offer list](/mangrove-core/technical-references/taking-and-making-offers/market).

* highest outbound volume
* least gas required
* oldest time of insertion on the list
  {% endhint %}

{% tabs %}
{% tab title="Solidity" %}
{% code title="bestOffer.sol" %}

```solidity
import "src/IMangrove.sol";

// context of the call
IMangrove mgv;
address outbound_tkn;
address inbound_tkn;

uint best = mgv.best(outbound_tkn, inbound_tkn); 
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}
{% code title="bestOffer.js" %}

```javascript
const { ethers } = require("ethers");
// context
let outboundTkn; // address of outbound token ERC20
let inboundTkn; // address of inbound token ERC20
let MGV_address;
let MGV_abi; // Mangrove contract's abi

const mgv = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

// getting best offer of the (outTkn,inbTk) market
const best = await mgv.best(outboundTkn, inboundTkn); 
```

{% endcode %}
{% endtab %}
{% endtabs %}

### `offers(address, address) / offerDetails(address, address, uint)`

{% hint style="info" %}
The data pertaining to a particular offer is contained in the `OfferUnpacked` and `OfferDetailUnpacked` structs, which are stored as packed custom types called, respectively, `OfferPacked` and `OfferDetailUnpacked.` For on-chain calls, Mangrove provides unpacking functions to extract a particular field out of a packed structure. For off-chain calls, Mangrove also provide direct getter for the unpacked structures.&#x20;
{% endhint %}

{% tabs %}
{% tab title="Solidity" %}
{% code title="getOfferData.sol" %}

```solidity
import "src/IMangrove.sol";
import {MgvStructs} "src/MgvLib.sol";

// context of the call
address MGV;
address outTkn; 
address inbTkn;
uint offerId; // the id of the offer one wishes to get the data of

// if one wishes to get the totally unpacked data (gas costly!):
(MgvStructs.OfferUnpacked memory offer, MgvStructs.OfferDetailUnpacked memory offerDetail) = Mangrove(MGV)
.offerInfo(outTkn,inbTkn,offerId);

// if one wishes to access a few particular fields, say `wants`, `gives` and `gasreq` parameters of the offer: 
// 1. getting packed (outTkn, inbTkn) Offer List data
MgvStructs.OfferPacked memory offer32 = Mangrove(MGV)
.offers(outTkn, inbTkn, offerId);
MgvStructs.OfferDetailPacked memory offerDetail32 = Mangrove(MGV)
.offerDetails(outTkn, inbTkn, offerId);

// for all fields f of OfferUnpacked
// offer.f == offer32.f()
// for all fields f of OfferDetailUnpacked
// offerDetail.f == offerDetail32.f()

```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}
{% code title="getOfferData.js" %}

```javascript
const { ethers } = require("ethers");
// context
let outTkn; // address of outbound token ERC20
let inbTkn; // address of inbound token ERC20
let MGV_address; // address of Mangrove
let MGV_abi; // Mangrove contract's abi

const Mangrove = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

// getting offer data in an abi compatible format
const [offer, offerDetail] = await Mangrove.offerInfo(outTkn,inbTkn,offerId);

// now one can access any field, say wants, gives and gasprice of the offer:
const wants = offer.wants;
const gives = offer.gives;
const gasreq = offerDetail.gasreq;
```

{% endcode %}
{% endtab %}
{% endtabs %}

### `isLive(address, address, uint)`

{% hint style="info" %}
An offer is **live** in a given [Offer Lists](/mangrove-core/technical-references/taking-and-making-offers/market) if it can be matched during a [market order](/mangrove-core/technical-references/taking-and-making-offers/taker-order). One can  verify whether `offerId` identifies a **live** offer in a (`outboundToken`,`inboundToken`) Offer List of Mangrove using this view function.
{% endhint %}

{% tabs %}
{% tab title="Solidity" %}
{% code title="isLive.sol" %}

```solidity
import "src/IMangrove.sol";

// context of the call
IMangrove mgv;
address outTkn;
address inbTkn;
address offerId;

// checking whether offerId is live in the (outTkn, inbTkn) order book.
bool isLive = mgv.isLive(outTkn,inbTkn,offerId);
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}
{% code title="isLive.js" %}

```javascript
const { ethers } = require("ethers");
// context
let outTkn; // address of outbound token ERC20
let inbTkn; // address of inbound token ERC20
let offerId; // offer id
let MGV_address; // address of Mangrove
let MGV_abi; // Mangrove contract's abi

const Mangrove = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

// checking whether offerId is live on (outTkn, inbTkn) Offer List.
const isLive = await Mangrove.isLive(outTkn,outTkn,offerId);
```

{% endcode %}
{% endtab %}
{% endtabs %}

## Custom types

{% hint style="info" %}
Offer data is split between `OfferUnpacked` and `OfferDetailedUnPacked` for  storage read/write optimisation (as both structs can be efficiently packed on storage).
{% endhint %}

### `MgvLib.MgvStructs.OfferUnpacked`

| Type     | Field   | Comments                                                                   |
| -------- | ------- | -------------------------------------------------------------------------- |
| `uint32` | `prev`  | Predecessor offer id (better price)                                        |
| `uint32` | `next`  | Successor offer id (worst price)                                           |
| `uint96` | `gives` | What the offer gives (in *wei* units of base token of the offer's market)  |
| `uint96` | `wants` | What the offer wants (in *wei* units of quote token of the offer's market) |

### `MgvLib.OfferDetailUnpacked`

| Type      | Field           | Comments                                                                                                                                                                |
| --------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `address` | `maker`         | address of the offer's [Maker Contract](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract)                                     |
| `uint24`  | `gasreq`        | Gas required by the offer (in gas units)                                                                                                                                |
| `uint16`  | `gasprice`      | The gas price covered by the offer bounty (in *gwei* per gas units)                                                                                                     |
| `uint24`  | `offer_gasbase` | Mangrove's [gasbase](/mangrove-core/technical-references/governance-parameters/mangrove-configuration#local-parameters) at the time the offer was posted (in gas units) |

##


# Taking offers

Basic taker side functions

## Generalities

### Token allowance

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.

### Active offer lists

Every Mangrove[ offer list ](/mangrove-core/technical-references/taking-and-making-offers/market#general-structure)can be either [active or inactive](/mangrove-core/technical-references/governance-parameters/local-variables#de-activating-an-offer-list), and Mangrove itself can be either [alive or dead](/mangrove-core/technical-references/governance-parameters/global-variables#other-governance-controlled-setters). Taking offers is only possible when Mangrove is alive on offer lists that are active.

## Market order

A **Market Order** is Mangrove's simplest way of buying or selling assets. Such (taker) orders are run against a specific [offer list](/mangrove-core/technical-references/taking-and-making-offers/market#general-structure) with its associated *outbound* token (tokens that flow out of Mangrove) and *inbound* token (tokens that flow into Mangrove). The liquidity taker specifies how many *outbound* tokens she [wants](/mangrove-core/technical-references/taking-and-making-offers/market#wants-gives-and-entailed-price) and how many *inbound* tokens she [gives](/mangrove-core/technical-references/taking-and-making-offers/market#wants-gives-and-entailed-price).

When an order is processed by Mangrove's matching engine, it consumes the offers on the selected [offer list](/mangrove-core/technical-references/taking-and-making-offers/market), starting from the one which as the best [rank](/mangrove-core/technical-references/taking-and-making-offers/market#offer-rank). Execution works as follows:

1. Mangrove checks that the current offer's [entailed price](/mangrove-core/technical-references/taking-and-making-offers/market#wants-gives-and-entailed-price) is at least as good as the taker's price. Otherwise execution stops there.
2. Mangrove sends *inbound* tokens to the current offer's associated [logic](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract).
3. Mangrove then executes the offer logic.
4. If the 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.
5. The taker's *wants* and *gives* are reduced.
6. If the taker's *wants* has not been completely fulfilled, Mangrove moves back to step 1.

Any failed [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer) execution results in a [bounty](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#computing-the-provision-and-offer-bounty) being sent to the caller as compensation for the wasted gas.

{% tabs %}
{% tab title="Signature" %}

```solidity
function marketOrder(
    address outbound_tkn,
    address inbound_tkn,
    uint takerWants,
    uint takerGives,
    bool fillWants
  ) external returns (uint takerGot, uint takerGave, uint bounty, uint fee);
```

{% endtab %}

{% tab title="Events" %}

```solidity
// Since the contracts that are called during the order may be partly reentrant, more logs could be emitted by Mangrove.
// we list here only the main expected logs.

// For each succesful offer taken during the market order:
event OfferSuccess(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id, // offer Id
    address taker, // address of the market order call
    uint takerWants, // original wants of the order
    uint takerGives // original gives of the order
  );
  
// For each offer cleaned during the market order:
event OfferFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id,
    address taker,
    uint takerWants,
    uint takerGives,
    // `mgvData` is either:
    // * `"mgv/makerRevert"` if `makerExecute` call reverted
    // * `"mgv/makerTransferFail"` if `outbound_tkn` transfer from the offer logic failed after `makerExecute`
    // * `"mgv/makerReceiveFail"` if `inbound_tkn` transfer to offer logic failed (e.g. contract's address is not allowed to receive `inbound_tkn`) 
    bytes32 mgvData
  );
  
// For each offer whose posthook reverted during second callback:
// 1. Loging offer failure
event PosthookFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint offerId,
    // `posthookData` contains the first 32 bytes of the posthook revert reason
    // e.g the complete reason if posthook reverted with a string small enough.
    bytes32 posthookData
  );
  
// 2. Debiting maker from Offer Bounty
event Debit(address indexed maker, uint amount);

// Logging at the end of Market Order:
event OrderComplete(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address taker,
    uint takerGot, // net amount of outbound tokens received by taker
    uint takerGave, // total amount of inbound tokens sent by taker
    uint penalty, // the total penalty collected by msg.sender as bounty for failing offers
    uint feePaid // the fee paid by the taker
 );
```

{% endtab %}

{% tab title="Revert strings" %}

```solidity
// Gatekeeping
"mgv/dead" // Trying to take offers on a terminated Mangrove
"mgv/inactive" // Trying to take offers on an inactive offer list

// Overflow
"mgv/mOrder/takerWants/160bits" // taker wants too much of a market Order
"mgv/mOrder/takerGives/160bits" // taker gives too much in the market order

// Panic reverts
"mgv/sendPenaltyReverted" // Mangrove could not send the offer bounty to taker
"mgv/feeTransferFail" // Mangrove could not collect fees from the taker
"mgv/MgvFailToPayTaker" // Mangrove was unable to transfer outbound_tkn to taker (Taker blacklisted?)
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="marketOrder.sol" %}

```solidity
import "src/IMangrove.sol";
import {IERC20} from "src/MgvLib.sol";

// context of the call
address MGV;
address outTkn; // address offer's outbound token
address inbTkn; // address of offer's inbound token

uint outDecimals = IERC20(outTkn).decimals();
uint inbDecimals = IERC20(inbTkn).decimals();

// if Mangrove is not approved yet for inbound token transfer.
IERC20(inbTkn).approve(MGV, type(uint).max);

// a market order of 5 outbound tokens (takerWants) in exchange of 8 inbound tokens (takerGives)
(uint takerGot, uint takerGave, uint bounty, uint fee) = IMangrove(MGV)
.marketOrder({
    outbound_tkn: outTkn,
    inbound_tkn: inbTkn,
    takerWants: 5*10**outDecimals,
    takerGive: 8*10**inbDecimals,
    true
});
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}
{% code title="marketOrder.js" %}

```javascript
const { ethers } = require("ethers");
// context
// outTkn: address of outbound token ERC20
// inbTkn: address of inbound token ERC20
// ERC20_abi: ERC20 abi
// MGV_address: address of Mangrove
// MGV_abi: Mangrove contract's abi
// signer: ethers.js transaction signer 

// loading ether.js contracts
const Mangrove = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

const InboundTkn = new ethers.Contract(
    inbTkn, 
    ERC20_abi, 
    ethers.provider
    );
    
const OutboundTkn = new ethers.Contract(
    outTkn, 
    ERC20_abi, 
    ethers.provider
    );
    
// if Mangrove is not approved yet for inbound token transfer.
await InboundTkn.connect(signer).approve(MGV_address, ethers.constant.MaxUint256);

const outDecimals = await OutboundTkn.decimals();
const inbDecimals = await InboundTkn.decimals();

// putting takerGives/Wants in the correct format
const takerGives = ethers.parseUnits("8.0", outDecimals);
const takerWants = ethers.parseUnits("5.0", inbDecimals);

// Market order at a limit average price of 8 outbound tokens given for 5 inbound tokens received
const tx = await Mangrove.connect(signer).marketOrder(
    outTkn,
    inbTkn,
    takerWants,
    takerGives,
    true
    );
await tx.wait();
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Inputs

* `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` raw amount of outbound token the taker wants. Must fit on 160 bits.
* `takerGives` raw amount of *inbound* token the taker gives. Must fit on 160 bits.
* `fillWants`
  * If `true`, the market order will stop as soon as `takerWants` *outbound* tokens have been bought. It is conceptually similar to a *buy order*.
  * If `false`, the market order will continue until `takerGives` *inbound* tokens have been spent. It is conceptually similar to *sell order*.
  * Note that market orders can stop for other reasons, such as the price being too high.

### Outputs

* `takerGot` is the net amount of *outbound* tokens the taker has received (i.e after applying the offer list [fee](/mangrove-core/technical-references/governance-parameters/local-variables#taker-fees) if any).
* `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
* `fee` is the amount of `outbound_tkn` that was sent to Mangrove's vault in payment of the potential [fee](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/taker-order/broken-reference/README.md) associated to the `(outbound_tkn, inbound_tkn)`[offer list](/mangrove-core/technical-references/taking-and-making-offers/market#general-structure).&#x20;

{% hint style="success" %}
**Specification**

At the end of a Market Order the following is guaranteed to hold:

* The taker will not spend more than `takerGives`.
* The average price paid `takerGave/(`takerGot + fee`)` will be maximally close to `takerGives/takerWants:`for each offer taken, the amount paid will be $$\leq$$ the expected amount + 1.
  {% endhint %}

| ID | wants (USDC) | gives (DAI) |
| -- | ------------ | ----------- |
| 2  | 0.98         | 1           |
| 1  | 9.9          | 10          |

{% hint style="info" %}
**Example**

Consider the DAI-USDC offer list (with no fee) above. If a taker calls `marketOrder`on this offer list with`takerWants=2` and `takerGives = 2.2` she is ready to give away up to 2.2 USDC in order to get 2 DAI.

* If `fillWants` is `true` the market order will provide 2 DAI for 1.97 USDC.
  1. 1 DAI for 0.98 USDC from offer #2
  2. 1 DAI for 0.99 from offer #1
* If `fillWants` is `false` the market order will provide 2.2078 DAI for 2 USDC.
  1. 1 DAI for 0.98 USDC from offer #1
  2. 1.2078 DAI for the remaining 1.22 USDC from offer #2
     {% endhint %}

### More on market order behaviour

Mangrove's market orders are configurable using the three parameters `takerWants`, `takerGives` and `fillWants.` Suppose one wants to buy or sell some token `B` (base), using token `Q` (quote) as payment.

* **Market buy:** A limit **buy** order for x tokens B, corresponds to a `marketOrder` on the (`B`,`Q`) offer list with `takerWants=x` (the volume one wishes to buy) and with `takerGives` such that `takerGives/x` is the limit price cap, and setting `fillWants` to `true`.
* **Market sell:** A limit **sell** order for x tokens B, corresponds to a `marketOrder` on the (`Q`, `B`) offer list with `takerGives=x` (the volume one wishes to sell) and with `takerWants` such that `takerGives/x` is the limit price cap, and setting `fillWants` to `false`.

{% hint style="warning" %}
**On order residuals**

Contrary to [GTC orders](https://www.investopedia.com/terms/g/gtc.asp) on regular [orderbook](https://www.investopedia.com/terms/o/order-book.asp) 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.
{% endhint %}

### Market order prices are volume-weighted

Consider the following A-B offer list:

| ID | Wants (B) | Gives (A) | Price (B per A) |
| -- | --------- | --------- | --------------- |
| 1  | 1         | 1         | 1               |
| 2  | 2         | 1         | 2               |
| 3  | 6         | 2         | 3               |

A regular limit order with `takerWants` set to 3 A and `takerGives` set to 6 B would consume offers until it hits an offer with a price above 2, so it would consume offers #1 and #2, but not offer #3.

In Mangrove, a "market order" with the same parameters will however consume offers #1 and #2 completely and #3 partially (for 3 Bs only), and result in the taker spending 6 (1+2+6/2) and receiving (1+1+2/2), which corresponds to a volume-weighted price of 2, complying with the Taker Order.

## Offer sniping

It is also possible to target specific offer IDs in the [offer list](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/taker-order/broken-reference/README.md). This is called **Offer Sniping**.

{% hint style="info" %}
Offer sniping can be used by off-chain bots and price aggregators to build their own optimized market order, targeting for instance offers with a higher volume or less gas requirements in order to optimize the gas cost of filling the order.
{% endhint %}

{% tabs %}
{% tab title="Signature" %}

```solidity
function snipes(
    address outbound_tkn,
    address inbound_tkn,
    uint[4][] memory targets, 
    bool fillWants
  )
    external
    returns (
      uint successes, 
      uint takerGot,
      uint takerGave,
      uint bounty,
      uint fee
    );
```

{% endtab %}

{% tab title="Events" %}

```solidity
// Since the contracts that are called during the order may be partly reentrant, more logs could be emitted by Mangrove.
// we list here only the main expected logs.

// For each offer successfully sniped:
event OfferSuccess(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id, // offer Id
    address taker, // address of the market order caller
    uint takerWants, // original wants of the order
    uint takerGives // original gives of the order
  );
  
// For each offer cleaned by the snipe:
event OfferFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id,
    address taker,
    uint takerWants,
    uint takerGives,
    // `statusCode` may only be `"mgv/makerAbort"`, `"mgv/makerRevert"`, `"mgv/makerTransferFail"` or `"mgv/makerReceiveFail"`
    bytes32 statusCode,
    // revert data sent by offer's associated account
    bytes32 makerData
  );
  
// If a sniped offer's posthook reverted during second callback:
// 1. Loging offer failure
event PosthookFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint offerId,
    bytes32 makerData
  );
 // 2. Debiting maker from Offer Bounty
event Debit(address indexed maker, uint amount);

// Logging at the end of all snipes:
event OrderComplete(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address taker,
    uint takerGot, // net amount of outbound tokens received by taker
    uint takerGave // total amount of inbound tokens sent by taker
 );
```

{% endtab %}

{% tab title="Revert strings" %}

```javascript
// Gatekeeping
"mgv/dead" // Trying to take offers on a terminated Mangrove
"mgv/inactive" // Trying to take offers on an inactive offer list

// Overflow
"mgv/snipes/takerWants/96bits" // takerWants for snipe overflows
"mgv/snipes/takerGives/96bits" // takerGives for snipe overflows

// Panic reverts
"mgv/sendPenaltyReverted" // Mangrove could not send Offer Bounty to taker
"mgv/feeTransferFail" // Mangrove could not collect fees from the taker
"mgv/MgvFailToPayTaker" // Mangrove was unable to transfer outbound_tkn to taker (Taker blacklisted?)
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="snipes.sol" %}

```solidity
import "src/IMangrove.sol";
import {IERC20} from "src/MgvLib.sol";

// context of the call
address MGV;
address outTkn; // address offer's outbound token
address inbTkn; // address of offer's inbound token
uint offer1; // first offer one wishes to snipe
uint offer2; // second offer one wishes to snipe

// if Mangrove is not approved yet for inbound token transfer.
IERC20(inbTkn).approve(MGV, type(uint).max);

// sniping the offers to check whether they fail
(uint successes, uint takerGot, uint takerGave, uint bounty, uint fee) = Mangrove(MGV).snipes(
    outTkn,
    inbTkn,
    [
        [offer1, 1 ether, 1 ether, 100000], // first snipe (price of 1 / 1 )
        [offer2, 1.5 ether, 1 ether, 50000] // second snipe (price of 1.5 / 1)
    ],
    true // fillwants
);
//we have: `successes < 2 <=> bounty > 0`
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}

<pre class="language-javascript" data-title="snipes.js"><code class="lang-javascript">const { ethers } = require("ethers");
// context
<strong>// outTkn: address of outbound token ERC20
</strong>// inbTkn: address of inbound token ERC20
// ERC20_abi: ERC20 abi
// MGV_address: address of Mangrove
// MGV_abi: Mangrove contract's abi
// signer: transaction signer 

// loading ether.js contracts
const Mangrove = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

const InboundTkn = new ethers.Contract(
    inbTkn, 
    ERC20_abi, 
    ethers.provider
    );
    
const OutboundTkn = new ethers.Contract(
    outTkn, 
    ERC20_abi, 
    ethers.provider
    );
    
// if Mangrove is not approved yet for inbound token transfer.
await InboundTkn.connect(signer).approve(MGV_address, ethers.constant.MaxUint256);

// preparing snipes data
const outDecimals = await OutboundTkn.decimals();
const inbDecimals = await InboundTkn.decimals();

const snipe1 = [ // first snipe spec
         offer1, //offer id
         ethers.parseUnits("1.5",outDecimals), //takerWants from offer1
         ethers.parseUnits("2.0",inbDecimals), //takerGives to offer1
         100000 // 100,000 gas units to execute
     ];
const snipe2 = [ // second snipe spec
         offer2, //offer id
         ethers.parseUnits("1.5",outDecimals), //takerWants from offer1
         ethers.parseUnits("2.2",inbDecimals), //takerGives to offer1
         50000
     ];
     
// triggering snipes
await Mangrove.connect(signer).snipes(
    outTkn,
    inbTkn,
    [snipe1, snipe2],
    true // fillwants
    );
</code></pre>

{% endtab %}
{% endtabs %}

### Inputs

* `outbound_tkn` *outbound* token address (received by the taker)
* `inbound_tkn` *inbound* token address (sent by the taker)
* `targets` an array of offers to take. Each element of `targets` is a `uint[4]`'s of the form `[offerId, takerWants, takerGives, gasreq_permitted]` where:
  * `offerId` is the ID of an [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer) that should be taken.
  * `takerWants` the amount of outbound tokens the taker wants from that [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer). **Must fit in a `uint96`.**
  * `takerGives` the amount of inbound tokens the taker is willing to give to that [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer). **Must fit in a `uint96`.**
  * `gasreq_permitted` is the maximum `gasreq` the taker will tolerate for that [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer). If the offer's `gasreq` is higher than `gasreq_permitted`, the offer will not be sniped.
* `fillWants` specifies whether you are acting as a buyer of **outbound tokens**, in which case you will buy at most `takerWants`, or a seller of **inbound tokens**, in which case you will buy as many tokens as possible as long as you don't spend more than `takerGives`.&#x20;

{% hint style="warning" %}
**Protection against malicious offer updates**

Offers can be updated, so if `targets` was just an array of `offerId`s, there would be no way to protect against a malicious offer update mined right before a snipe. The offer could suddenly have a worse price, or require a lot more gas.

If you only want to take offers without any checks on the offer contents, you can simply:

* Set `takerWants` to `0`,
* Set `takerGives` to `type(uint96).max`,
* Set `gasreq_permitted` to `type(uint).max`, and
* Set `fillWants` to `false`.
  {% endhint %}

### Outputs

* `successes` is the number of sniped offers that transferred the expected volume to the taker (in particular `successes < target.length` if and only if some of the sniped offers reneged on their trade and `bounty > 0`).
* `takerGot, takerGet, bounty, fee` as in `marketOrder`.

#### Example

| ID | Wants | Gives | Gas required |
| -- | ----- | ----- | ------------ |
| 13 | 10    | 10    | 80\_000      |
| 2  | 1     | 2     | 250\_000     |

{% hint style="info" %}
**Example**

Consider the above offers on the DAI-USDC offer list:

Setting `targets` to `[[13,8,10,80_000],[2,1,1.1,250_000]]` with `fillWants` set to `true` will successfully buy 8 DAI from offer #13 (for 8 USDC), and will not attempt to execute offer #2 since 1.1 > 1/2.
{% endhint %}


# Delegation

Taking offers on behalf of another address

## Approve or Permit

A **Taker** **Order** on Mangrove can be sent on behalf of a taker, in which case the delegate taker needs to be approved or permitted to draw the required inbound tokens from the taker.

{% hint style="info" %}
Approving a Delegate Taker for inbound tokens MUST be done via the standard `approve` function of the ERC20 managing the inbound token of the offer list. The approval MUST be enough to cover `takerGives` amount of inbound tokens of the `snipesFor` or `marketOrderFor` calls.
{% endhint %}

Alternatively, Mangrove allows the taker to `permit` a delegate taker to act on their behalf.

{% tabs %}
{% tab title="Function" %}

```solidity
function permit(
    address outbound_tkn,
    address inbound_tkn,
    address owner,
    address spender,
    uint value,
    uint deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;
```

{% endtab %}
{% endtabs %}

* `(outbound_tkn, inbound_tkn)` the outbound and inbound token of the offer list on which the Delegate Taker will be permitted to operate.
* `owner` the address of the taker providing the inbound tokens for the Delegate Taker.
* `spender` the address of the Delegate Taker.
* `value` the maximal amount of inbound tokens the Delegate Taker is permitted to use.
* `deadline` the block number beyond which the delegator's signature can no longer be used to obtain permission.
* `(v,r,s)` the `secp256k1` [signature](https://eips.ethereum.org/EIPS/eip-2612) identifying the `owner` of the delegated funds.

## Delegated Order Taking

Once a Delegate Taker is approved or permitted by a taker, she can use the delegated Taker Orders variants `marketOrderFor` and `snipesFor` which work similarly to `marketOrder` and `snipes` but require an additional `taker` address.

{% tabs %}
{% tab title="Functions" %}

```solidity
// Delegated Market Order
function marketOrderFor(
    address outbound_tkn,
    address inbound_tkn,
    uint takerWants,
    uint takerGives,
    bool fillWants,
    address taker
  ) external returns (uint takerGot, uint takerGave);
 
// Delegated snipes
function snipesFor(
    address outbound_tkn,
    address inbound_tkn,
    uint[4][] memory targets,
    bool fillWants,
    address taker
  )
    external
    returns (
      uint successes,
      uint takerGot,
      uint takerGave
    );
    
```

{% endtab %}
{% endtabs %}


# Creating & Updating offers

How to write Mangrovian offers

### Posting a new offer

New offers should mostly be posted by [contracts](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) able to source liquidity when asked by Mangrove.&#x20;

{% hint style="info" %}
`newOffer` is payable and can be used to credit the Offer Logic's balance on Mangrove on the fly. A non zero `msg.value` will allow Mangrove to credit Offer Logic's balance prior to locking the [provision](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision) of the newly posted offer.
{% endhint %}

{% tabs %}
{% tab title="Signature" %}

```solidity
function newOffer(
    address outboundTkn,
    address inboundTkn,
    uint wants, // amount of inbound Tokens
    uint gives, // amount of outbound Tokens
    uint gasreq,
    uint gasprice,
    uint pivotId
) external payable returns (uint offerId);
```

{% endtab %}

{% tab title="Events" %}

```solidity
// logging new offer's data 
event OfferWrite(
      address outboundTkn,
      address inboundTkn,
      address maker, // account that created the offer, will be called upon execution
      uint wants,
      uint gives,
      uint gasprice, // gasprice that was used to compute the offer bounty
      uint gasreq,
      uint offerId, // id of the new offer
      uint prev // offer id of the closest best offer at the time of insertion 
    );
 // `maker` balance on Mangrove (who is `msg.sender`) is debited of `amount` WEIs to provision the offer
 event DebitWei(address maker, uint amount);
 // `maker` balance on Mangrove is credited of `amount` WEIs if `msg.value > 0`.
 event CreditWei(address maker, uint amount); 
```

{% endtab %}

{% tab title="Revert strings" %}

```javascript
// Gatekeeping
"mgv/dead" // Mangrove contract is terminated
"mgv/inactive" // Trying to post an offer in an inactive market

// Order book has reached its maximal number of orders (2**24)
"mgv/offerIdOverflow" // Unlikely as max offer id is 2**24

// Overflow
"mgv/writeOffer/gasprice/16bits"
"mgv/writeOffer/gives/96bits"
"mgv/writeOffer/wants/96bits"

// Invalid values
"mgv/writeOffer/gasreq/tooHigh" // gasreq above gasmax
"mgv/writeOffer/gives/tooLow"   // gives should be > 0
"mgv/writeOffer/density/tooLow" // wants / (gasreq + overhead) < density

// Insufficient provision
"mgv/insufficientProvision" // provision of `msg.sender` should cover offer bounty
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="newOffer.sol" %}

```solidity
import "src/IMangrove.sol";
import {IERC20, MgvStructs} "src/MgvLib.sol";

// context of the call
address MGV;
address outTkn; // address offer's outbound token
address inbTkn; // address of offer's inbound token
address admin; // admin address of this contract
uint pivotId; // offer id whose price is the closest to this new offer (observed offchain)

// Approve Mangrove for outbound token transfer if not done already
IERC20(outTkn).approve(MGV, type(uint).max);
uint outDecimals = IERC20(outTkn).decimals();
uint inbDecimals = IERC20(inbTkn).decimals();

// importing global and local (pertaining to the (outTkn, inTkn) offer list) parameters.
(MgvStructs.GlobalPacked global, MgvStructs.LocalPacked local) = IMangrove(MGV)
.config(outTkn, inTkn);

uint gasprice = global.gasprice() * 10**9; // Mangrove's gasprice is in gwei units
uint gasbase = local.offer_gasbase() ; // gas necessary to process a market order
uint gasreq = 500_000; // assuming this logic requires 30K units of gas to execute

uint provision = (gasreq + gasbase) * gasprice; // minimal provision in wei

// calling mangrove with `pivotId` for initial positioning.
// sending `provision` amount of native tokens to cover for the bounty of the offer
IMangrove(MGV).newOffer{value: provision}(
        outTkn, // reposting on the same market
        inbTkn, 
        5.0*10**inbDecimals, // maker wants 5 inbound tokens
        7.0*10**outDecimals, // maker gives 7 outbound tokens
        30_000, // maker requires 500_000 gas units to comply 
        0, // use mangrove's gasprice oracle  
        pivotId // heuristic: tries to insert this offer after pivotId
);  
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}

```typescript
const {ethers} = require("ethers");
// context 
// outTkn_address: address of outbound token ERC20
// inbTkn_address: address of inbound token ERC20
// ERC20_abi: ERC20 abi
// MGV_address: address of Mangrove
// MGV_abi: Mangrove contract's abi
// signer: ethers.js transaction signer 

// loading ether.js contracts
const Mangrove = new ethers.Contract(
    MGV_address, 
    MGV_abi, 
    ethers.provider
    );

const InboundTkn = new ethers.Contract(
    inbTkn_address, 
    ERC20_abi, 
    ethers.provider
    );
    
const OutboundTkn = new ethers.Contract(
    outTkn_address, 
    ERC20_abi, 
    ethers.provider
    );
    
// if Mangrove is not approved yet for outbound token transfer.
await OutboundTkn.connect(signer).approve(MGV_address, ethers.constant.MaxUint256);

const outDecimals = await OutboundTkn.decimals();
const inbDecimals = await InboundTkn.decimals();

// putting takerGives/Wants in the correct format
const gives:ethers.BigNumber = ethers.parseUnits("8.0", outDecimals);
const wants:ethers.BigNumber = ethers.parseUnits("5.0", inbDecimals);

const {global, local} = await Mangrove.configInfo(outTkn_address,inbTkn_address);
// Market order at a limit average price of 8 outbound tokens given for 5 inbound tokens received
tx = await Mangrove.connect(signer).newOffer(
    outTkn_address,
    inbTkn_address,
    wants,
    gives,
    0, // offer with no logic do not require additional gas to execute
    global.gasprice, // using mangrove's gasprice
    0,  // using best offer as pivot
    {value: (local.offer_gasbase.mul(global.gasprice).mul(10**9))} // putting funds on Mangrove to cover for offer bounty
    );
await tx.wait();

```

{% endtab %}
{% endtabs %}

**Inputs**

* `outbound_tkn` address of the outbound token (that the offer will provide).
* `inbound_tkn` address of the inbound token (that the offer will receive).
* `wants` amount of inbound tokens requested by the offer. **Must** fit in a `uint96`.
* `gives` amount of outbound \*\*\*\* tokens promised by the offer. **Must** fit in a `uint96` and be strictly positive. **Must** provide enough volume w\.r.t to `gasreq` and offer list's [density](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/broken-reference/README.md) parameter.
* `gasreq` amount of gas that will be given to the offer's [account](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract). **Must** fit in a `uint24` and be lower than [gasmax](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/broken-reference/README.md). Should be sufficient to cover all calls to the offer logic posting the offer ([`makerExecute`](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract#offer-execution) and [`makerPosthook`](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract#offer-post-hook)). **Must** be compatible with the offered volume `gives` and the offer list's [density](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/broken-reference/README.md) parameter.
* `gasprice` gas price override used to compute the order provision (see [offer bounties](https://github.com/giry-dev/mangrove-docs/blob/main/offer-maker/offer-provision.md)). Any value lower than Mangrove's current [gasprice](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/broken-reference/README.md) will be ignored (thus 0 means "use Mangrove's current [gasprice](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/broken-reference/README.md)"). **Must** fit in a `uint16`.
* `pivotId` where to start the insertion process in the offer list. If `pivotId` is not in the offer list at the time the transaction is processed, the new offer will be inserted starting from the offer list's [best](#getting-current-best-offer-of-a-market) offer. Should be the id of the existing live offer with the price closest to the price of the offer being posted.

**Outputs**

* `offerId` the id of the newly created offer. Note that offer ids are scoped to [offer lists](https://github.com/giry-dev/mangrove-docs/blob/main/offer-maker/broken-reference/README.md), so many offers can share the same id.

{% hint style="danger" %}
**Provisioning**

Since offers can fail, Mangrove requires each offer to be [provisioned](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision) in ETH. If an offer fails, part of that provision will be sent to the caller that executed the offer, as compensation.

Make sure that your offer is [well-provisioned](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#checking-an-account-balance) before calling `newOffer`, otherwise the call will fail. The easiest way to go is to send a comfortable amount of ETH to Mangrove from your offer-posting contract. Mangrove will remember your ETH balance and use it when necessary.
{% endhint %}

{% hint style="danger" %}
**Offer execution**

* If the offer account is a contract, it should implement the [IMaker](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) interface. At the very least, it must have a function with signature [`makerExecute(MgvLib.SingleOrder calldata order)`](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract#offer-execution) or it will systematically revert when called by Mangrove.
* `gives` and `gasreq` are subject to [density](/mangrove-core/technical-references/governance-parameters/local-variables#density) constraints on the amount of *outbound* token provided per gas spent.
* The offer account will need to give Mangrove a high enough allowance in *outbound* tokens since Mangrove will use the ERC20 standard's `transferFrom` function to source your tokens.
  {% endhint %}

### Updating an existing offer

Offers are updated through the aptly-named `updateOffer` function described below (source code is [here](https://github.com/giry-dev/mangrove/blob/552ab35500c34e831f40a68fac81c8b3e6be7f5b/packages/mangrove-solidity/contracts/MgvOfferMaking.sol#L99)).

{% tabs %}
{% tab title="Signature" %}

```solidity
function updateOffer( 
    address outboundToken, 
    address inboundToken, 
    uint wants, 
    uint gives, 
    uint gasreq, 
    uint gasprice, 
    uint pivotId, 
    uint offerId
) external;
```

{% endtab %}

{% tab title="Events" %}

```solidity
event OfferWrite(
      address outboundToken,
      address inboundToken,
      address maker, // account that created the offer, will be called upon execution
      uint wants,
      uint gives,
      uint gasprice, // gasprice that was used to compute the offer bounty
      uint gasreq,
      uint offerId, // id of the updated offer
      uint prev // offer id of the closest best offer at the time of update
    );
// if old offer bounty is insufficient to cover the update, 
// `maker` is debited of `amount` WEIs to complement the bounty
 event DebitWei(address maker, uint amount);
 
// if old offer bounty is greater than the actual bounty, 
// `maker` is credited of the corresponding `amount`.
event CreditWei(address maker, uint amount);

 
```

{% endtab %}

{% tab title="Revert strings" %}

```javascript
// Gatekeeping
"mgv/dead" // Mangrove contract is terminated
"mgv/inactive" // Trying to update an offer in an inactive market

// Type error in the arguments
"mgv/writeOffer/gasprice/16bits"
"mgv/writeOffer/gives/96bits"
"mgv/writeOffer/wants/96bits"

// Invalid values
"mgv/writeOffer/gasreq/tooHigh" // gasreq above gasmax
"mgv/writeOffer/gives/tooLow"   // gives should be > 0
"mgv/writeOffer/density/tooLow" // wants / (gasreq + overhead) < density

// Invalid caller
"mgv/updateOffer/unauthorized" // caller must be the account that created the offer

// Insufficient provision
"mgv/insufficientProvision" // provision of caller no longer covers the offer bounty
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="updateOffer.sol" %}

```solidity
import "src/IMangrove.sol";
import {MgvStructs} form "src/MgvLib.sol";

// context of the call
// MGV: address of Mangrove's deployment 
// outTkn, inbTkn: addresses of the offer list in which the updated offer is
// offerId: offer identifier in the (outTkn, inbTkn) offer list

MgvStruct.OfferPacked memory offer32 = IMangrove(MGV).offers(outTkn, inbTkn, offerId);
MgvStruct.OfferPacked memory offerDetail32 = IMangrove(MGV).offerDetails(outTkn, inbTkn, offerId);

IMangrove(MGV).updateOffer(
   outTkn, 
   inbTkn, 
   offer32.wants(), // do not update what the offer wants
   offer32.gives() * 0.9, // decrease what offer gives by 10%
   offerDetail32.gasreq(), // keep offer's current gasreq 
   offerDetail32.gasprice(), // keep offer's current gasprice
   offer32.next(), // heuristic: use next offer as pivot since offerId might be off the book
   offerId // id of the offer to be updated
);
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Inputs

* `offerId` is the offer id of the offer to be updated.
* For the other parameters, see [above](#posting-a-new-reactive-offer).

#### Outputs

None.

{% hint style="info" %}
**Offer updater**

An offer can only be updated if `msg.sender` is the [account](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) that created the offer.
{% endhint %}

{% hint style="warning" %}
**Reusing offers**

After being executed or [retracted](#retracting-an-offer), an offer is moved out of the offer list. It can still be updated and reinserted in the offer list. We recommend updating offers instead of creating new ones, as it costs much less gas.
{% endhint %}

### Retracting an offer

An offer can be withdrawn from the order book via the `retractOffer` function described below.

{% tabs %}
{% tab title="Signature" %}

```solidity
function retractOffer(
    address outboundToken,
    address inboundToken,
    uint offerId,
    bool deprovision
  ) external;
```

{% endtab %}

{% tab title="Events" %}

```solidity
// emitted on all successful retractions
event OfferRetract(
    address outboundToken, // address of the outbound token ERC of the offer
    address inboundToken, // address of the inbound token ERC of the offer
    uint offerId // the id of the offer that has been removed from the offer list
    );

// emitted if offer is deprovisioned
event Credit(
    address maker, // account being credited
    uint amount // amount (in wei) being credited to the account
); 
```

{% endtab %}

{% tab title="Revert strings" %}

```javascript
"mgv/retractOffer/unauthorized" // only the offer's Maker Contract may call.
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="retractOffer.sol" %}

```solidity
import "./Mangrove.sol";

// context of the call
address MGV;
address outTkn; // address of market's base token
address inbTkn; // address of market's quote token
address admin; // admin address of this contract
...
...
// external function to update an offer
// assuming this contract has enough provision on Mangrove to repost the offer if need be 
function myRetractOffer(uint offerId) external {
        require(msg.sender == admin, "Invalid caller");
        // calling mangrove with offerId as pivot (assuming price update will not change much the position of the offer)
        Mangrove(MGV).retractOffer(
                outTkn, // reposting on the same market
                inbTkn, 
                offerId, // id of the offer to be updated
                false // do not deprovision offer, saves gas if one wishes to repost the offer later
        );
}
...
...
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Inputs

* `offerId` is the offer id of the offer to be updated.
* `deprovision` if true, will free the offer's ETH provision so that you can [withdraw](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#withdrawing) them. Otherwise, will leave the provision in the offer.
* For the other parameters, see [above](#posting-a-new-reactive-offer).

#### Outputs

None.


# Executing offers

How to write offer execution logic

### Offer Logic

The logic associated with an offer **must** be implemented through a `makerExecute` callback function. (See [data structures](https://docs.oxium.xyz/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/pages/jtjaAoHXnMbNCd7Dqkyd#mgvlib.singleorder) for `SingleOrder` type).

{% tabs %}
{% tab title="Signature" %}

```solidity
function makerExecute(MgvLib.SingleOrder calldata order)
external returns (bytes32 makerData);
```

{% endtab %}

{% tab title="Offer logic" %}
{% code title="MakerContract-0.sol" %}

```solidity
import {IERC20, IMaker, SingleOrder} "src/MgvLib.sol";

contract MyOffer is IMaker {
    address MGV; // address of Mangrove
    address reserve; // token reserve for inbound tokens
    
    // an example of offer execution that simply verifies that `this` contract has enough outbound tokens to satisfy the taker Order.
    function makerExecute(SingleOrder calldata order) 
    external returns (bytes32 makerData){
        // revert below (in case of insufficient funds) to signal mangrove we renege on trade
        // reverting as soon as early to minimize bounty
        require(
           IERC20(order.outbound_tkn).balanceOf(address(this)) >= order.wants),
           "MyOffer/NotEnoughFunds";
        );
        // do not perform any state changing call if caller is not Mangrove!
        require(msg.sender == MGV, "MyOffer/OnlyMangroveCanCallMe");
        // `order.gives` has been transfered by Mangrove to `this` balance
        // sending incoming tokens to reserve
        IERC20(order.inbound_tkn).transfer(reserve, order.gives);
        // this string will be passed to `makerPosthook`
        return "MyOffer/tradeSuccess";
    }
}
    
    
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Inputs

* `order` is a [data structure](/mangrove-core/technical-references/governance-parameters) containing a recap of the [taker order](https://docs.oxium.xyz/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/pages/jtjaAoHXnMbNCd7Dqkyd#mgvlib.singleorder) and Mangrove's current configuration state. The protocol guarantees that `order.gives/order.wants` will match the price of the offer that is being executed up to a small precision.&#x20;

#### Outputs

* `makerData` is an arbitrary `bytes32` that will be passed to `makerPosthoook` in the `makerData` field.

{% hint style="danger" %}
**Security concerns**

Your contract should ensure that only Mangrove can call `makerExecute` to avoid unwanted state change.&#x20;
{% endhint %}

{% hint style="success" %}
**How to succeed**

To successfully execute, the logic **must** not revert during the call to `makerExecute` and have at least `wants` *outbound* tokens available for Mangrove to transfer by the end of the function's execution.

**How to renege on trade**

The proper way to renege on an offer is to make the execution of `makerExecute` throw with a reason that can be cast to a `bytes32`. Having a balance of *outbound* tokens that is lower than `order.wants` will also make trade fail, but with a higher incurred gas cost and thus a higher [bounty](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#provision-and-offer-bounty).
{% endhint %}

{% hint style="warning" %}
**Better fail early!**

The [bounty](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#computing-the-provision-and-offer-bounty) taken from the offer maker's provision is [proportional](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#computing-the-provision-and-offer-bounty) to the gas consumed by `makerExecute`. To minimize costs, try to fail as early as possible.
{% endhint %}

{% hint style="danger" %}
**Mangrove is guarded against reentrancy during `makerExecute`**

The offer list for the *outbound* / *inbound* token pair is temporarily locked during calls to `makerExecute`. Its offers cannot be modified in any way. The offer logic must use `makerPosthook` to repost/update its offers, since the offer list will unlocked by then.
{% endhint %}

### Offer post-hook

The logic associated with an offer may include a `makerPosthook` callback function. Its intended use is to update offers in the [offer list](/mangrove-core/technical-references/taking-and-making-offers/market) containing the [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer) that was just executed.

{% tabs %}
{% tab title="Signature" %}

```solidity
function makerPosthook(
    MgvLib.SingleOrder calldata order,
    MgvLib.OrderResult calldata result
  ) external;
```

{% endtab %}

{% tab title="Offer logic" %}
{% code title="MakerContract-1.sol" %}

```solidity
import {IERC20, IMaker, SingleOrder, OrderResult, MgvStructs} from "src/MgvLib.sol";

abstract contract MakerContract is IMaker {
    // context 
    address MGV; // address of the Mangrove contract
    
    // Example of post-hook
    // if taker order was a success, try to repost residual offer at the same price
    function makerPosthook(
        SingleOrder calldata order,
        OrderResult calldata result
    ) external {
        require (msg.sender == MGV, "posthook/invalid_caller");
        if (result.mgvData == "mgv/tradeSuccess") {
            // retrieving offer data
            // the following call to updateOffer will revert if:
            // * `this` MakerContract doesn't have enough provision on Mangrove for the offer
            // * the residual/(GASREQ+offer_gasbase) is below Mangrove's minimal density
            // NB : a reverting posthook does not revert the offer execution
            Mangrove(MGV).updateOffer(
                order.outbound_tkn, // same offer List
                order.inbound_tkn,
                order.offer.wants() - order.gives, // what the offer wanted, minus what the taker order gave 
                order.offer.gives() - order.wants, // what the offer was giving, minus what the taker took
                order.offerDetail.gasreq(), // keeping with the same gasreq
                order.offer.next(), // using next offer as pivot
                order.offerId // reposting the offer that was consumed
            );
        }
    }
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Inputs

* `order` same as in `makerExecute`.
* `result` A [struct](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-data-structures#mgvlib-orderresult) containing:
  * the return value of `makerExecute`
  * additional data sent by Mangrove, more info [available here](https://docs.oxium.xyz/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/pages/jtjaAoHXnMbNCd7Dqkyd#mgvlib.orderresult).

#### Outputs

None.

{% hint style="danger" %}
**Security concerns**

Your contract should ensure that only Mangrove can call `makerPosthook` to avoid unwanted state change.
{% endhint %}

{% hint style="warning" %}
**Gas management**

`MakerPosthook` is given the executed offer's `gasreq` minus the gas used by `makerExecute`.&#x20;

**Updating offers during posthook**

During the execution of a posthook, the executed offer's list is unlocked. This feature can be used to repost an [offer](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer) (even the one that was just executed), possibly at a different price.
{% endhint %}

{% hint style="warning" %}
**Reverting**

Reverting during `makerPosthook` does not renege on trade, which is settled at the end of `makerExecute`.
{% endhint %}


# Offer provisions

How taker compensation for failing offers works.

## Summary

When an offer fails, the caller has wasted some gas. To compensate the caller, Mangrove gives them a *bounty* in native tokens. Offers must provision enough ethers to maximize the chances that Mangrove can compensate the caller. In more details:

* Every offer logic that posted an offer has a balance in ethers held by Mangrove. Funds can be freely added to or withdrawn from the balance.
* Whenever the logic creates or updates an offer, its balance is adjusted so that enough native tokens are locked as the offer's provision.
  * If the offer is retracted that provision is credited back to the logic's account balance.
  * If the offer is executed and fails, part or all of the provision is sent as compensation, to the caller. We call that the bounty. The rest of the provision is credited back to the offer logic's account balance.

## Balance funding & withdrawal

### Funding an offer

There are three ways an offer logic can credit its balance on Mangrove. (1) The logic may either call the `fund` function, or (2) make a call to the fallback function with some value, or (3) pay on the fly when a [new offer is posted](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer#posting-a-new-offer).&#x20;

{% tabs %}
{% tab title="Signature" %}

```solidity
function fund(address maker) public payable;
```

{% endtab %}

{% tab title="Events" %}

```solidity
// Offer Maker at address `maker` has been credited of `amount` wei
event Credit(address maker, uint amount);
```

{% endtab %}

{% tab title="Revert string" %}

```solidity
"mgv/dead" // Mangrove contract is no longer live
```

{% endtab %}

{% tab title="Solidity" %}
{% code title="fund.sol" %}

```solidity
import "src/IMangrove.sol";
//context 
IMangrove mgv; // Mangrove contract address
address maker_contract; // address of the maker contract one is willing to provision
// funding maker_contract
mgv.fund{value: 0.1 ether}(maker_contract);

// if funding oneself one can use the overload:
mgv.fund{value: 0.1 ether}();
// which is equivalent to `msg.fund{value:0.1 ether}(address(this))

// to avoid erreoneous transfer of native tokens to Mangrove, the fallback function will also credit `msg.sender`:
(bool noRevert,) = address(mgv).call{value: amount}("");
require(noRevert, "transfer failed");
```

{% endcode %}
{% endtab %}

{% tab title="ethers.js" %}
{% code title="fund.js" %}

```javascript
const { ethers } = require("ethers");
//context
let MGV; // address of Mangrove
let MGV_abi; // Mangrove contract's abi
let maker_contract_address; // address of the Maker Contract

const Mangrove = new ethers.Contract(
    MGV, 
    MGV_abi, 
    ethers.provider
    );

let overrides = { value: ethers.parseUnits("0.1", 18) };
// provisioning Mangrove on behalf of MakerContract
await Mangrove["fund(address)"](maker_contract_address, overrides);
```

{% endcode %}
{% endtab %}
{% endtabs %}

#### Inputs

* `maker` the offer logic's balance on Mangrove to credit

{% hint style="danger" %}
**Do not use `send` or `transfer` to credit Mangrove**&#x20;

Upon receiving funds, Mangrove will credit the amount sent to `maker` (or `msg.sender` if the `receive` function was called). This involves writing to storage, which consumes more gas than the amount given by `send` and `transfer`.
{% endhint %}

### Checking an account balance

```solidity
function balanceOf(address who) external view returns (uint balance);
```

#### Inputs

* `who` The account of which you want to read the balance.

#### Outputs

* `balance` The available balance of `who`.

### Withdrawing

At any time, your available balance can be withdrawn. It may be less than what you deposited: your balance adjusts every time you create/update an offer.

{% tabs %}
{% tab title="Signature" %}

```solidity
function withdraw(uint amount) external returns (bool noRevert);
```

{% endtab %}

{% tab title="Events" %}

```solidity
event Debit(address maker, uint amount);
```

{% endtab %}

{% tab title="Revert strings" %}

```solidity
// Trying to withdraw unavailable funds
"mgv/insufficientProvision"
```

{% endtab %}

{% tab title="Solidity" %}

```solidity
import "src/IMangrove.sol";
//context 
IMangrove mgv; // Mangrove contract

uint wei_balance = mgv.balanceOf(address(this));
require(mgv.withdraw(wei_balance), "Mangrove failed to transfer funds");
```

{% endtab %}
{% endtabs %}

#### Inputs

* `amount` the amount of ethers (in wei) one wishes to withdraw from Mangrove's provisions.

#### Outputs

* `noRevert` whether the ether transfer was successful.

{% hint style="danger" %}
**Important points**

* The account credited will be `msg.sender`.
* `amount` must be $$\leq$$ your available balance (available with `balanceOf`)
  {% endhint %}

## Balance adjustment when creating/updating offers

Whenever an offer is created or updated, Mangrove applies to following formula to get the offer's required provision in wei:

$$\textrm{provision} = \max(\textrm{gasprice}*{\textrm{mgv}},\textrm{gasprice}*{\textrm{ofr}}) \times (\textrm{gasreq} + \textrm{gasbase}\_{\textrm{mgv}}) \times 10^9$$​

* $$\textrm{gasprice}\_{\textrm{mgv}}$$ is the `gasprice` [global governance parameter](/mangrove-core/technical-references/governance-parameters/global-variables#gas-price-and-oracle) (in gwei per gas units)
* $$\textrm{gasprice}\_{\textrm{ofr}}$$ is the `gasprice` argument of the function being called ([`newOffer`](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer#posting-a-new-offer) or [`updateOffer`](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer#updating-an-existing-offer)) also in gwei per gas units.
* $$\textrm{gasreq}$$ is the `gasreq` argument of the function being called (in gas units).
* $$\textrm{gasbase}\_{\rm mgv}$$is the `offer_gasbase` [local governance parameter](/mangrove-core/technical-references/governance-parameters/local-variables#offer-gas-base).

Mangrove will adjust the balance of the caller to ensure that $$\textrm{provision}$$ wei are available as bounty if the offer fails. If the offer was *already* provisioned, the adjustment may be small, and the balance may actually increase -- for instance, if the `gasprice` dropped recently.

{% hint style="info" %}
**Incentivized book cleaning**

Provisions are calculated so that, within reasonable gas estimates, taking a failing offer should be profitable for the taker.
{% endhint %}

{% hint style="success" %}
**Gas optimization**

If you frequently update your offers, we recommend using a consistent, high `gasprice` argument, above the actual expected gas prices. Not changing `gasprice` when you call `updateOffer` will make the call cheaper (you save one `SSTORE`).
{% endhint %}

## Provision and offer bounty

{% tabs %}
{% tab title="Solidity snippet" %}
{% code title="getProvision.sol" %}

```solidity
import "src/IMangrove.sol";
import {MgvStructs} from "src/MgvLib.sol";
//context 
IMangrove mgv;
address outbound_tkn;
address inbound_tkn;
uint offer_gasreq;
(MgvStructs.GlobalPacked global32, MgvStructs.LocalPacked local32) = mgv.config(outbound_tkn, inbound_tkn);

// computing minimal provision to cover an offer requiring `offer_gasreq` gas units 
uint provision = (offer_gasreq + local32.offer_gasbase()) * global32.gasprice() * 10 ** 9;
```

{% endcode %}
{% endtab %}

{% tab title="with ethers.js" %}
{% code title="getProvision.js" %}

```javascript
const { ethers } = require("ethers");
let outTkn; // address of outbound token ERC20
let inbTkn; // address of inbound token ERC20
let MGV_reader_address; // address of Mangrove reader
let MGV_reader_abi; // Mangrove Reader contract's abi

const MangroveReader = new ethers.Contract(
    MGV_reader_address, 
    MGV_reader_abi, 
    ethers.provider
    );

const ofr_gasreq = ethers.parseUnits("1",5); //100,000 gas units
const bounty = await MangroveReader.getProvision(outTkn, inbTkn, ofr_gasreq,0);
```

{% endcode %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Applied bounty**

Suppose an offer requires $$g\_{\mathsf{ofr}}$$​ gas units to execute. As explained above, Mangrove will require the logic posting the offer to provision $$\beta$$ WEI. Suppo se the offer is executed during a Taker Order and fails after $$g\_{\mathsf{used}}$$gas units ($$g\_\mathsf{used}\<g\_\mathsf{ofr}$$). The portion of the bounty that will be transferred to the Offer Taker's account is $$\dot G\*(\dot g\_0/n+\dot g\_1+g\_\mathsf{used})$$ where $$\dot G$$​, $$\dot g\_0$$, $$n$$ and $$\dot g\_1$$are respectively the [`global.gasprice`](broken://pages/-MdTUgm7qH0wqjDc_Y0c#global-parameters), [`local.overhead_gasbase`](broken://pages/-MdTUgm7qH0wqjDc_Y0c#offer-list-specific-governance-parameters), the number of offers executed during the take order, and the [`local.offer_gasbase`](broken://pages/-MdTUgm7qH0wqjDc_Y0c#offer-list-specific-governance-parameters) values *at the time the offer is taken* (which may differ from their values at the time the offer was posted, as a consequence of some parameter changes by the governance).
{% endhint %}


# Public data structures

Mangrove communicates with Offer Logics with public data structures described in this section.

## MgvLib.SingleOrder

<table><thead><tr><th width="326.3333333333333">Type</th><th width="161">Field</th><th>Comments</th></tr></thead><tbody><tr><td><code>address</code></td><td><code>outbound_tkn</code></td><td>outbound token address of the market order</td></tr><tr><td><code>address</code></td><td><code>inbound_tkn</code></td><td>inbound token address of the market order</td></tr><tr><td><code>uint</code></td><td><code>offerId</code></td><td>Id of the offer that is matched by the order</td></tr><tr><td><code>MgvStructs.OfferPacked</code></td><td><code>offer</code></td><td>Offer data of the current state of the offer on the offer list</td></tr><tr><td><code>uint</code></td><td><code>wants</code></td><td>amount of outbound tokens that are required by the order (in max precision units of <code>outbound_tkn</code> ERC20).</td></tr><tr><td><code>uint</code></td><td><code>gives</code></td><td>amount of inbound tokens that are given by the taker (in max precision units of <code>inbound_tkn</code> ERC20).</td></tr><tr><td><code>MgvStructs.OfferDetailPacked</code></td><td><code>offerDetail</code></td><td>packing of the matched offer details</td></tr><tr><td><code>MgvStructs.GlobalPacked</code></td><td><code>global</code></td><td>packing of the global parameters of the Mangrove that apply to this order</td></tr><tr><td><code>MgvStructs.LocalPacked</code></td><td><code>local</code></td><td>packing of the market parameters that apply to this order</td></tr></tbody></table>

## MgvLib.OrderResult

<table><thead><tr><th width="145">Type</th><th width="133.33333333333331">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>bytes32</code></td><td><code>makerData</code></td><td>The returned or reverted value of <code>makerExecute</code>, truncated to fit a <code>bytes32</code> word.</td></tr><tr><td><code>bytes32</code></td><td><code>mgvData</code></td><td><p>Information gathered by Mangrove concerning the offer execution. If the offer was a success it is equal to:</p><ul><li><code>"mgv/tradeSuccess"</code>: offer execution succeeded.</li></ul><p>If the offer failed (Offer Bounty will be taken from Maker Contract), it will be equal to one the following messages:</p><ul><li><code>"mgv/makerRevert"</code>: offer execution reverted.</li><li><code>"mgv/makerTransferFail"</code>: Mangrove could not transfer <code>order.outbound_tkn</code> tokens from <a href="/pages/-Me0Gx3iLLRX-isZO7ec">Offer Logic</a> to itself (e.g. contract has insufficient balance).</li><li><code>"mgv/makerReceiveFail"</code>: Mangrove could not transfer <code>order.inbound_tkn</code> tokens to <a href="/pages/-Me0Gx3iLLRX-isZO7ec">Offer Logic</a> (e.g. contract is blacklisted).</li></ul></td></tr></tbody></table>


# Governance parameters

Mangrove's Governance is a user or a contract, which has permission to set Protocol wide and Offer List specific configuration parameters.

{% hint style="info" %}
[Global](/mangrove-core/technical-references/governance-parameters/global-variables) governance parameters apply to all interactions with Mangrove. [Local](/mangrove-core/technical-references/governance-parameters/local-variables) governance parameters are (`outbound, inbound`) [Offer List](https://github.com/giry-dev/mangrove-docs/blob/main/meta-topics/broken-reference/README.md) specific. Both global and local parameters are under the control of Mangrove's governance.
{% endhint %}


# Global variables

Protocol wide governance parameters.

### Gas price and oracle

{% hint style="info" %}
**Gas price** (given is GWEI units) is a key parameter of Mangrove that [determines the remuneration](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#offer-bounty-computation) of takers for removing a failing offer from a list. In order to make sure takers are consistently over-compensated for the gas used, it should be kept well above average `tx.gasprice`.
{% endhint %}

**Gas price** can be read from an outside Monitoring Contract. When the governance wishes to do so, it **must** enable this feature by letting the monitor (if any) act as a gas price oracle. This can be done using the governance restricted function `setUseOracle` of Mangrove.

If monitoring the gas price is not enabled, or if the value returned by the monitor is ill formed, Mangrove will use its global [`gasprice`](https://docs.oxium.xyz/mangrove-core/technical-references/governance-parameters/pages/pF6T9izqF21UiijXXJft#mgvlib.global) parameter as fallback.&#x20;

{% tabs %}
{% tab title="Signatures" %}

```solidity
// Governance lets the monitor determine gasprice
function setUseOracle(bool useOracle) public;

// Governance sets the fallback gasprice value (in GWEI)
function setGasprice(uint gasprice) public;

// Governance sets a new monitor
function setMonitor(address monitor) public;
```

{% endtab %}

{% tab title="Events" %}

```solidity
event SetGasprice(uint gasprice); // emitted when gas price is updated
event SetMonitor(address monitor); // emitted when a new monitor is set
event SetUseOracle(bool value); // logs `true` if Mangrove is set to use an external monitor to read gasprice. Logs `false` otherwise
```

{% endtab %}
{% endtabs %}

{% hint style="danger" %}
**Important point**

If allowing the monitor to act as a gas price Oracle, Governance **must** have previously deployed a Monitor Contract and set its address in Mangrove's configuration.
{% endhint %}

### Other governance controlled setters

{% tabs %}
{% tab title="Signature" %}

```solidity
// Governance sets maximum allowed gas per offer
function setGasmax(uint gasmax) public;
// Changing governance address
function setGovernance(address value);
// Changing treasury address
function setVault(address value);
// (de)activates sending trade notification to governance contract (e.g. for rewards programs)
function setNotify(bool value);
// set maximum gas amount an offer may require to execute
function setGasmax(uint value);
// permanently puts mangrove into a killed state (Mangrove rejects all taker and maker orders, only retracting offer is possible)
function kill();

```

{% endtab %}
{% endtabs %}


# Local variables

Offer List specific governance parameters

### Taker fees

### Density

### (De)activating an Offer List

### Offer gas base


# Data structures and views

Global governance parameters and Offer List specific parameters.

Ground truth for configuration can be found in the code [documentation](https://giry-dev.github.io/mangrove/MgvDoc.html). All configuration options are under the control of [governance](broken://pages/XE4bmJcEBSvKboIfnbAE).

## MgvLib.MgvStructs.GlobalUnpacked

| Name        | Type      | Description                                                                                                                                                              |
| ----------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `gasprice`  | `uint16`  | Internal gas price estimate, in gwei/gas. Used to calculate the provision required for writing offers.                                                                   |
| `monitor`   | `address` | If enabled, acts as a gas price oracle for Mangrove and/or receives notifications when an offer is executed.                                                             |
| `useOracle` | `bool`    | If true, monitor will be used as a gas price oracle. Otherwise the internal gas price global parameter will be used.                                                     |
| `notify`    | `bool`    | If true, monitor will be called every time an offer has been executed.                                                                                                   |
| `gasmax`    | `uint24`  | Maximum gas an offer can require.                                                                                                                                        |
| `dead`      | `bool`    | If true, this Mangrove instance is dead and the only possible interactions are retracting offers and getting provisions back. Once true, it cannot be set back to false. |

## MgvLib.MgvStructs.LocalUnpacked

For every pair of addresses, there is a set of local parameters. Note that the parameters for the A/B pair might be different from the B/A pair parameters.

| Name                | Type     | Description                                                                     |
| ------------------- | -------- | ------------------------------------------------------------------------------- |
| `active`            | `bool`   | If inactive, offers on this pair can only be retracted.                         |
| `fee`               | `uint16` | Fee in basis points, at most 500.                                               |
| `density`           | `uint32` | Minimum amount of token an offer must promise per gas required.                 |
| `overhead_ gasbase` | `uint24` | Constant gas overhead associated with taking an any number of offers in 1 call. |
| `offer_gasbase`     | `uint24` | Gas overhead associated with taking one offer.                                  |

## Views

{% hint style="info" %}
The data structures containing Mangrove's global and local [configuration parameters](/mangrove-core/technical-references/governance-parameters/mangrove-configuration) are accessible via the public view function `configInfo(address outbound, address inbound)` function.
{% endhint %}

{% hint style="info" %}
For read/write efficiency, Mangrove provides access to configuration parameters in a packed manner via the getter `config(address outbound, address inbound).`
{% endhint %}

{% tabs %}
{% tab title="Solidity" %}
{% code title="config.sol" %}

```solidity
import "src/IMangrove.sol";

// context of the call
address MGV;
address outTkn;
address inbTkn;

// getting Mangrove's global configuration parameters and those that pertain to the `(outTkn, inTkn)` offer list
// in an ABI compatible format (gas costly, use for offchain static calls)
(MgvStructs.GlobalUnpacked global, MgvStructs.LocalUnpacked local) = IMangrove(MGV)
.configInfo(outTkn, inTkn);

// getting packed config data (gas efficient)
(MgvStructs.GlobalPacked global32, MgvStructs.LocalPacked local32) = IMangrove(MGV)
.config(outTkn, inTkn);

// for all fields f of `GlobalUnpacked global` 
// one may unpack a specific element of `GlobalPacked global32` using the following scheme:
global.f == global32.f()

// for all fields f of `LocalUnpacked local` 
// a similar scheme applies to `LocalPacked local32`:
local.f == local32.f()

```

{% endcode %}
{% endtab %}
{% endtabs %}


# Deployment addresses

## Polygon Testnet - Mumbai

### Mangrove

```
0xF3e339d8a0B989114412fa157Cc846ebaf4BCbd8
```

### MgvReader

```
0xfAB31d37f8DF5bff07Bb3c16B33416eCd4Aab76F
```

### MgvCleaner

```
0xEb05Ace3574B0a6f4696c5CcD09e730d6d5ED3b0
```

### MgvOracle

```
0xd38c02425da847584eeDA72387DAAA2E8f3b90c8
```

### MangroveOrder

```
0x1fA0d582B8aA298f634cdCDCCcB7972E913b2D8f
```

### MangroveOrderEnriched

```
0x7Ae7a1502084bB10DCb5fFfE7835D84c76aA65d7
```

### ERC20 addresses

* DAI: `0x9A753f0F7886C9fbF63cF59D0D4423C5eFaCE95B`
* USDC: `0x9aa7fEc87CA69695Dd1f879567CcF49F3ba417E2`
* WETH: `0xd575d4047f8c667e064a4ad433d04e25187f40bb`

### Previous versions

#### v5

* Mangrove: `0xa34b6ADdf822177258Cbd0A9c3a80600C1028Ca8`
* MgvReader: `0x72c7f3144ccb0D76D2c7B8D4f996F0f7D0511358`
* MgvCleaner: `0x8d8daA2Ee56712b25f0c616AC374Fe98B84A99Be`
* MgvOracle: `0xb5Fa732eb1a6BA0E3000E5eda48fc84A0dC55cb9`

#### v4

* Mangrove: `0x6f531931A7EaefB95307CcD93a348e4C27F62DCF`
* MgvReader: `0x2f9bb88571E9B27e8291B1a9dBD376C755C87d49`
* MgvCleaner: `0x44deC8A22DAea93D3F2519702954000B459B4F1B`
* MgvOracle: `0x6735091776a7dEf7058b2ec8Bea721F7cc503f50`

#### v3

* Mangrove: `0xD27139C60ED051b65c3AEe193BCABFfa1067D243`
* MgvReader: `0xa1e2f6EEe41799d44e365135F70fD23b0d0505D6`
* MgvCleaner: `0x9C0AC5b8F47c912b33Bdd0a21273A673e2A47D32`
* MgvOracle: `0xA7F318d18d163E4677A4eAc2ffd820bA0c605EB7`

#### v2

* Mangrove: `0x493Bd4Ae961B3C50e1a1C86CC0D433aDa66870D0`
* MgvReader: `0x69dE7df175444cd44667DdfA74FbEb5095C3dB34`
* MgvCleaner: `0xad53eB62d210DeeB30854e1b73dD4Ee88E612cc9`
* MgvOracle: `0xb4C0B66F158C314FfBDF1b64d9B517B8aaB46773`

#### v1

* Mangrove: `0xE44FfC50ED6673d6A1C385B76152E1551a6c14a3`
* MgvReader: `0xc00d2da52195b123d3c994aaf2eb1e8da8999d4f`
* MgvCleaner: `none`
* MgvOracle: `none`


# Protocol

The Solidity code for the core contracts can be found on [GitHub](https://github.com/mangrovedao/mangrove-core). There is also [annotated code](https://code.mangrove.exchange) available generated from code comments.


# API documentation


# Background


# Taking available liquidity

How to tap into the Mangrove's liquidity

![A market order consumes the offers starting from the best price, making sure that the limit price set by the taker is always satisfied.](/files/CSWwsfZKiz5mtptKPNTD) ![A taker may snipe a custom set of offers, targeting those that have the lowest required gas for instance.](/files/yEm4GaD9ogFPXKkk5com)

### Taking offers

The main way to consume liquidity on Mangrove is through a market order, a configurable type of order that executes offers from best to worst. The [Taking offers](/mangrove-core/technical-references/taking-and-making-offers/taker-order) section details how market orders work, and covers [offer sniping](/mangrove-core/technical-references/taking-and-making-offers/taker-order#offer-sniping) as well, wherein one can target individual offers.

### Cleaning offers

Offers on Mangrove can fail. Liquidity-taking functions can also be used to trigger failing offers and take them out of Mangrove. The [Cleaning offers](/mangrove-core/how-to-guides/cleaning-an-offer) section details how to safely trigger failing offers and make a profit doing so.

### Delegation

An allowance mechanism lets you separate the address that provides the funds and the address that originates the buy/sell transactions. The [Delegation](/mangrove-core/technical-references/taking-and-making-offers/taker-order/delegate-takers) section details how to let other addresses use your funds.


# Making liquidity available

A walkthrough guide to deploying a reactive offer on the Mangrove

An offer on Mangrove usually points to a contract containing the [offer logic](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) and specifies what it is ready to deliver and its price. Offer are stored in [offer lists](/mangrove-core/technical-references/taking-and-making-offers/market).

![When a reactive Offer is matched, the contract implementing its logic is called by Mangrove](/files/1HvPr1aLNo0FwkTbG4zx)

### Creating & Updating offers

Any Ethereum account can offer liquidity on Mangrove. New offers are created through a `newOffer` function, and updated through `updateOffer`. The [Creating & Updating offers](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer) section details how to use those Mangrove functions. Mangrove has a standard implemantation off [offer logic](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/maker-contract) called [MangroveOffer](/mangrove-core/explanations/offer-maker/mangrove-offer), that automatically reposts the residual of your offer, if the offer was not fully taken.

### Executing offers

After an offer has been created or updated, it can be executed by anyone. Upon execution, the offer's logic has an opportunity to source the liquidity it has promised. The Executing offers section details how to structure your contract code in order to respond when its offers are executed.

### Offer bounties

Since offers on Mangrove can fail, an ETH bounty is given to those who trigger failing offers, as compensation for the gas spent. This bounty is extracted from the offer's account deposit at Mangrove. The [Offer bounties](#offer-bounties) section details how bounties work and how they are calculated.


# MangroveOffer

Mangrove has a standard implementation of IOfferLogic called MangroveOffer. This implementation is an abstract contract, that reposts the residual of the offer, if the offer was not fully taken. This is done using the hooks exposed by MangroveOffer. These hooks are separated into 3 categories. The first hooks are called doing `makerExecute`. This means that you will be able to hook into the flow of how and if Mangrove is transferring the funds from the MangroveOffer contract to the **reserve** and from the **reserve** to the MangroveOffer contract.

The **reserve** is where the outbound tokens will be fetched, and where the inbound tokens will be deposited. A reserve is associated to each offer maker. By default the reserve of an offer maker is the offer maker's address. Advanced routers may use complex protocols, such as AAVE, as reserve. It is possible to change the default reserve of an offer maker. It is possible to change the reserve for a offer maker, but to do so, the hook `checkReserveApproval` has to be implemented. See[Direct](/mangrove-core/explanations/offer-maker/direct) or [Forwarder](/mangrove-core/explanations/offer-maker/forwarder).

When an offer is taken, Mangrove transfers the funds from the taker to Mangrove and from Mangrove to the contract that posted the offer. It is not possible to hook in before or in between these 2 transfers. When these 2 transfers are done, MangroveOffer, has 3 hooks. **lastlook**, **put** and **get**. They are called in this order.

**Lastlook** is meant for having a lastlook before the funds are transferred to the taker. It then returns a value that `makerPosthook` can use, to get information of how e.g. the markets looked, when `makerExecute` was executed. This can be useful since, `makerPosthook` may be call several orders later. See [Executing offers](https://github.com/giry-dev/mangrove-docs/blob/main/offer-maker/executing-offers.md) for more information.

**Put** is meant as an option for the maker to transfer the given funds from the contract to e.g. the reserve. This could be useful if you don't want to leave the funds on the contract.

**Get** is meant as an option for the maker to transfer the funds, promised to taker the, from e.g. the reserve to the MangroveOffer contract. This could be useful if you don't want to have the promised funds laying on the contract.

**Put** and **Get** are both hooks, that makes it possible to make transfers Just in time, when offer is taken. All three hooks in `makerExecute` do nothing by default.

The next hooks are called doing `makerPosthook`. This i called after the offer is taken. `makerPosthook` has 2 hooks **posthookSuccess** and **posthookFallback**. When an offer is taken, it either succeeds in transferring the makers funds to the taker or it fails.

**PosthookSuccess**: If it succeeds in transferring the funds from maker to taker, then the transaction was a success. `makerPosthook` then calls this hook. In this hook MangroveOffer has a default implementation, that reposts the taken offer, if the offer was only partially taken. It does this, by using 2 other hooks, called **residualGives** and **residualWants**. These hooks are used to calculate the new gives and wants for the reposted offer. MangroveOffers default implementation is to return the residual gives and wants of the taker offer. The reason for these being hooks, are that if the maker wants to repost the offer, with new gives and wants, even if the offer was fully taken. Then it will be possible to implement versions of **residualGives** and **residualWants** that returns the new gives and wants that the maker wants to use for the reposted offer. If **residualGives** return zero, then the offer will never be reposted.

**PosthookFallback**: If the offer fails to transfer the takers funds to the maker, then the transaction will revert. But if it fails trying to transfer the funds from the maker to the taker, then the taker will get a bounty. In this situation `makerPosthook` will emit a failed transfer and call the hook **posthookFallback**. MangroveOffers default implementation is empty. An example of what **posthookFallback** could be used for is, it could make sense to deprovision the offer, or even retract other offers on the book, that the maker now know will fail.

Besides having hooks while the offer is taken and after. MangroveOffer also has 2 other hooks, called **Activate** and **Checklist**. Before an offer can be taken on Mangrove, Mangrove needs to have the correct approvals to transfer the tokens from the MangroveOffer contract to Mangrove. And if the contract is using a Router it also needs to approve the router to transfer the tokens from the contract. Both these hooks are helpers to setup the correct approvals.

**Checklist** is a hook that is meant for checking if a token as the correct approvals. MangroveOffer always starts by checking if Mangrove and maybe the router has correct approvals. After this check, the hook gets called. An example of how to use this hook, would be if you are using a router that tries to lend the funds. This probably needs additional approvals, this hook should then check if those approvals are made.

**Activate** is a hook that is meant for giving correct approvals for a token. MangroveOffer has a default implementation of the hook, that approves Mangrove and maybe the router, and then calls additional approvals on the router. An example of how to use this hook would be to, use the default implementation and also do additional approvals, e.g. if an extra address is used for transfers, then this address probably needs to be approved.

**Approvals:** Here is list of all approval needed for MangroveOffer contract:

* MangroveOffer contract must approve Mangrove to transfer outbound tokens. (Done by activate)
* Mangrove contract must approve its router (if any) to transfer inbound tokens. (Done by activate)

Besides the MangroveOffer contract giving approvals, the offer makers reserve needs to give this approval:

* The offer makers reserve of the MangroveOffer contract must approve the router for outbound token transfer.

**CheckReserveApproval** is a hook that should check whether the reserve has approved the maker to use it. This is needed so that a maker don't use the reserve without the approval of the owner of the reserve. If this was allowed, it would be possible to set your reserve to the same as someone with a large amount of tokens and steal there tokens, when offers a taken. MangroveOffer has no default implementation. The hook is used, when the a maker tries to set their reserve.

A **Router** is a contract that can handle more comprehensive transfers. E.g. if you want to lend the money, when the offer is taken, then a router would be able to handle this. A more comprehensive description of Routers can be found here LINK.

Mangrove has 2 default implementations of MangroveOffer, they can be found here, [Direct](/mangrove-core/explanations/offer-maker/direct) and [Forwarder](/mangrove-core/explanations/offer-maker/forwarder).

![Flow of taking a offer made by MangroveOffer](/files/5umX3tMIDsmyCMl9vj1P)


# Direct

Direct is an abstract implementation of [MangroveOffer](/mangrove-core/explanations/offer-maker/mangrove-offer), if you don't have a good understanding of MangroveOffer we recommend reading that page first.

Direct should be seen as an implementation that only works for one user, the admin of the contract. This means most calls are guarded, so only the admin can call them. Having only one user, simplifies the uses of the contract, since there is no need to keep track of who is posting offer, updating offers or retracting offers, it is always the admin.

Direct does many of the same things as MangroveOffer with a few key differences.

**How inbound tokens are handled (from the taker):** After the funds have been transferred from the taker to the Direct contract, it chooses to leave received funds on the contract's balance, until `makerPosthook` is called. The reason for leaving the funds on the contract is that multiple offers posted by this contract may be taken in the same market order. This will result in a cumulative amount of inbound tokens being on the contract's balance. Instead of transferring them during each call to `makerExecute`, it is cheaper in gas to wait until after all offers are taken, and then transfer all the funds left on the contract to the reserve.

**How outbound tokens are handled (for the taker):** When transferring the funds from the contract to the taker, Direct first tries to check if it itself has the funds, otherwise tries to get the funds from the reserve either by using a router or by using the contract itself. This means that if the contract already has the funds, no extra transfers are needed.

**Reserve:** When setting the reserve using a Direct contract, the Direct checks whether the caller is the admin of the contract and if so, the reserve is set. Since the contract can only be used by the admin, there is no need to check anything else. Setting the reserve to the Direct contracts address will save gas, since it saves the transfers between the Direct contract and the reserve.

MangroveOffer has no implementations of how to post a new offer, update an offer or retract an offer. Direct offers default implementations for this. Posting a new offer and updating an offer, is very simply done by forwarding the call to Mangroves own methods for post a new offer and updating an offer. Retracting a offer using Direct, will also forward the call to Mangroves own retract offer method. But since the Direct contract is the actual address that posts the offers on Mangrove, then if one chooses to deprovision the offer, all provisions will be return to the Direct contract. The Direct contract therefore implements an option to transfer the provision back to the admin of the contract.

![Flow of taking a offer made by Direct](/files/paSGiQSWXRJhlHQkUOwU)


# Forwarder

Forwarder is an abstract implementation of [MangroveOffer](/mangrove-core/explanations/offer-maker/mangrove-offer), if you don't have a good understanding of MangroveOffer we recommend reading that page first. This page is going to compare the [Direct](/mangrove-core/explanations/offer-maker/direct) implementation of MangroveOffer with Forwarder, we recommend reading about [Direct](/mangrove-core/explanations/offer-maker/direct) before reading this page.

Forwarder should be seen as an implementation the can be used by multiple offer makers. This means that anyone can manage offers using the contract. Because of this, Forwarder needs to keep track of who owns which offer and what the reserve is for the caller. This is the key difference between Direct and Forwarder.

Forwarder does many of the same things as MangroveOffer and Direct with a few key differences.

**How inbound tokens are handled (from the taker):** After the funds have been transferred from the taker to the Forwarder contract, it transfers the funds to the reserve of the offer owner. The reason for this, is that it cannot leave the funds on the contract, since the inbound tokens need to be distributed to each offer owners. When the offer has been successfully taken, it has no funds on the contract itself (vs. Direct where the funds are still on the contract). It therefore has no extra actions and just uses the default implementation of MangroveOffer.

**How outbound tokens are handled (for the taker):** Since the contract cannot be used as the reserve for a Forwarder contract, this means that is also has to transfer the funds from the reserve to the Forwarder contract. This is again because multiple users can use the contract.

**Reserve:** When setting the reserve using a Forwarder contract it first checks if the maker is trying to set an empty address. This is allowed and the makers address will be used as the reserve. If the address is not empty, then it checks whether the address has approved the maker to use it as its reserve. This is different than Direct, since Forwarder has multiple makers, it has to keep track on which makers can use a reserve. The reserve needs to call the Forwarder contract to approve a maker. The reserve can also revoke the approval.

**Provision tracking:** If the offer fails, then this means that the taker was given a bounty for using gas trying to take a failing offer. But the bounty for the taker, is not necessarily the same amount as the amount that was provisioned for the offer. If there is still some provision left on the offer, Forwarder keeps track of the remaining provision, that is no longer locked to the offer. The same way it keeps track of who owns an offer it also saves how much free provision is left on the offer.

**Routing:** The Forwarder contract has to use a router, it is not possible to leave the responsibility of transferring the funds to and from the reserve to the contract itself.

Where MangroveOffer has not implementation of posting a new offer, updating offers or retracting offers and Direct has very simple implementation of the methods. Forwarder needs more logic, because it has to keep track of who posts what offer. This means Forwarder keeps an internal map, where it can look up any offer id on any market, and see who owns that offer. When posting a new offer, the offer id is returned. The poster has keep track of on what market they posted and what id was used. If they forget this, there is no way of knowing what offers on which markets, that they own. When updating or retracting an offer, the Forwarder checks whether the caller is the offer owner that the caller is trying to change. If the caller is not the owner, then the transaction reverts.

When posting a new offer, one would usually also fund Mangrove, so that it has enough funds to cover gas and possible bounty. But since it is the Forwarder contract, that is actually doing the posting of the offers and just keeping track of who owns what internally. Then funding Mangrove directly cannot be done, because Mangrove only knows that the Forwarder contract posted the offer, but has no information about who the Forwarder posted on behalf of. Because of this when posting a new offer using Forwarder, it does not require a gasprice, but uses the amount to be funded combined with the gas requirement, to calculate a gas price, that uses all of the funds. This way the offer has enough information, that when an offer is retracted or updated, it can calculated how much provision is left on the offer.

![Flow of taking a offer made by Forwarder](/files/KPX0gNhG20qqzKU8wOSA)


# Reneging on offers

Since Mangrove offers do not provision liquidity, there must be a mechanism that ensures that most of the time, the orderbook does not contain 'fake offers', that is, offers that renege on their promises.

Mangrove uses [Offer Provisions](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision) as a protection mechanism.

Consider an offer that promises 100WETH for 100DAI and requires 300k for execution. That gas will be paid for by the taker. If the 100WETH are delivered, all is well.

If they are not, the taker must be compensated for the wasted gas. This is why, when creating an offer, market makers must [provision](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision) for a potential [bounty](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#computing-the-provision-and-offer-bounty) in ETH. That [bounty](/mangrove-core/technical-references/taking-and-making-offers/reactive-offer/offer-provision#computing-the-provision-and-offer-bounty) depends on :

* The average gas price, as estimated by the Mangrove exchange itself. Let's name it `gasprice`.
* The amount of gas requested by the offer. Let's name it `gasreq`.
* A minimum gas expense determined by the Mangrove exchange. Let's name it `gas_overhead`.

To post their offer, the maker must lock `gasprice * (gasreq + gas_overhead)` WEI in the Mangrove.

* If the maker retracts their offer, the ETH will be available to the maker for withdrawal.
* If the offer is successfully executed, the ETH stays locked inside the offer.
* If the offer is executed and fails, part of the ETH goes to the taker and the rest is available to the maker for withdrawal.
  * The amount of ETH that goes to the taker depends on the gas *actually used during the execution of the offer*.

Now, a few observations about how the mechanism is implemented.

### Encouraging early renege

It is in the interest of a maker to code their contract such that, if they decide not to fill their promise, they do so as early as possible. This reduces the gas effectively spent and thus minimizes their operating costs.

### Bounties finance fast updates

During the lifecycle of a market order, makers of executed offers are called twice. Once to fulfill their promise, and once again to reinsert offers in the book. So even if an offer fails, the bounty mechanism lets the maker pay for reinserting their offer without delay. This reinsertion can use any onchain information available at the time, such as oracles.

### Don't update gasprice

A small tip: an implementation detail means that as a maker, you can save a write if you make sure that the gas price associated with your offer does not change between offer updates. The best way to do that is to radically overestimate the gasprice when calling `newOffer` and to then maintain that gasprice on every subsequent call to `updateOffer`.

### Overestimate gasprice

Internally, the Mangrove will overestimate the gasprice to give a margin of error. This increases the lockup size for makers, but protects takers and the Mangrove against a sudden gasprice increase which would leave any cleaning unprofitable.

### Keeper mechanism

Since the Mangrove internal gasprice is overestimated, the activity of 'book cleaning' is profitable. For instance, consider a failing offer which requires 10k gas at an estimated gasprice of 100 gwei. A specialized Keeper bot can come in and execute the offer (after a local dry-run to ensure the offer does fail). As long as they pay a gasprice below 100 gwei, they will come out of the transaction earning a net profit.


# Around the Mangrove


# Mangrove's ecosystem

Mangrove's main contract may be deployed with additional useful contracts.

* [Mangrove Reader](/mangrove-core/explanations/around-the-mangrove/mangroves-ecosystem/reader) contract provide easy to parse views on Mangrove's state.
* [Mangrove Monitor](/mangrove-core/explanations/around-the-mangrove/mangroves-ecosystem/monitor) may act as a gas/density oracle for Mangrove and receives taker fees (if any).
* [Mangrove Cleaner ](/mangrove-core/explanations/around-the-mangrove/mangroves-ecosystem/cleaner)an order reverter that allows one to snipe offers for their bounty (or revert if the offer was eventually successful).
* [Mangrove Order](/mangrove-core/explanations/around-the-mangrove/mangroves-ecosystem/advanced-orders) is a contract that can be used to run advanced market orders on Mangrove, such as [GTC](https://www.investopedia.com/terms/g/gtc.asp) or [IOC](https://www.investopedia.com/terms/i/immediateorcancel.asp).


# Advanced orders


# Reader

Coming soon in the doc....


# Oracle

Coming soon in the doc....


# Cleaner

Coming soon in the doc....


# Mangrove API

mangrove.js - A JavaScript API for Mangrove written in TypeScript.

mangrove.js is a JavaScript API for Mangrove. You can find the developer documentation for mangrove.js here: [jsdocs.mangrove.exchange](https://jsdocs.mangrove.exchange/).


# SDK

mangrove.js is a JavaScript API for the Mangrove exchange, the on-chain orderbook where offers are code.

{% hint style="info" %}
Wraps around [ethers.js](https://github.com/ethers-io/ethers.js). Works in the **web browser** and [Node.js](https://nodejs.org/en/).
{% endhint %}

## Getting started

You can install the API using \`npm\` package manager using:

```bash
sandbox_folder$> npm install @mangrovedao/mangrove.js
```

and you may readily connect to Mangrove with [Node.js](https://nodejs.org/en/), for instance:

{% code title="demo.node.terminal" %}

```bash
sandbox_folder$> node
Welcome to Node.js v_xxx
Type ".help" for more information.
> const { Mangrove } = require("@mangrovedao/mangrove.js");
> const { ethers } = require("ethers");
> let provider = new ethers.providers.WebSocketProvider(
    "https://polygon-mumbai.g.alchemy.com/v2/<PRIVATE_KEY>"
  );
> let myWallet = new ethers.Wallet(
    "<WALLET_PRIVATE_KEY>",
    provider
  );
> let mgvAPI = await Mangrove.connect({
    signer: myWallet
  });
> let market = await mgvAPI.market({base:"WETH", quote:"DAI"});
> console.log("pretty prints available bids from the WETH,DAI market on Mangove");
// pretty prints available bids from the WETH,DAI market on Mangove
> await market.consoleBids();
┌─────────┬────┬──────────────────────────────────────────────┬─────────────────────┬───────────────────────────┐
│ (index) │ id │                    maker                     │       volume        │           price           │
├─────────┼────┼──────────────────────────────────────────────┼─────────────────────┼───────────────────────────┤
│    0    │ 4  │ '0x54782b0c6080DBC5492BCB4Fa4BA4103845940Ad' │ 0.2355813953488372  │ 4244.81737413622919031855 │
│    1    │ 5  │ '0x54782b0c6080DBC5492BCB4Fa4BA4103845940Ad' │ 0.2355813953488372  │ 4244.81737413622919031855 │
│    2    │ 1  │ '0xcBb37575320FF499E9F69d0090b6944bc0aD7585' │ 0.23559598787030558 │ 4244.55445544554446426917 │
└─────────┴────┴──────────────────────────────────────────────┴─────────────────────┴───────────────────────────┘
```

{% endcode %}


# Getting started


# On-the-fly offer

The most simple liquidity providing strategy, no offer logic, just a Wallet.

{% hint style="info" %}
An [**On-the-fly offer** (OTF)](/start-here/glossary#on-the-fly-offer-otf) can be listed on Mangrove but is not equipped with any on-chain [logic](/mangrove-core/explanations/offer-maker#executing-offers) that executes when the offer is taken. Whenever it is matched by a [taker order](/mangrove-core/explanations/offer-taker#taking-offers), the offer sources its liquidity on an [Externally Owned Account (EOA)](/start-here/glossary#externally-owned-account-eoa).
{% endhint %}

## How to post one?

To post an OTF you need to

1. tell Mangrove you wish to post a new offer,
2. sign the resulting transaction with the wallet (EOA) that contains the promised liquidity.

Here is an example using [Mangrove's JS API](https://github.com/mangrovedao/mangrove/tree/master/packages/mangrove.js). Follow [preparation](https://github.com/giry-dev/mangrove-docs/blob/main/mangrove-core/tutorials/preparation.md) (once) and start a fresh `node` in a shell and run the following statements.

{% code title="directOffer.js" %}

```javascript
// Load the NODE_URL and PRIVATE_KEY from .env file into process.env
// This script assumes NODE_URL points to your access point and PRIVATE_KEY contains private key from which one wishes to post offers
var parsed = require("dotenv").config();
// Import the Mangrove API
const { Mangrove, ethers } = require("@mangrovedao/mangrove.js");

// Create a wallet with a provider to interact with the chain.
const provider = new ethers.providers.WebSocketProvider(
  process.env.NODE_URL
);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// Connect the API to Mangrove
const mgv = await Mangrove.connect({ signer: wallet });

// Connect mgv to a DAI, USDC market
const market = await mgv.market({ base: "DAI", quote: "USDC" });

// Check it's live, should display the best bids and asks of the DAI, USDC market
market.consoleAsks();
market.consoleBids();

// Create a simple liquidity provider on `market`, using `wallet` as a source of liquidity
const directLP = await mgv.liquidityProvider(market);

// Liquidity provider needs to approve Mangrove for transfer of base token (DAI) which
// will be transferred from the wallet to Mangrove and then to the taker when the offer is taken.
const tx = await directLP.approveAsks();
await tx.wait();

// Query mangrove to know the bounty for posting a new Ask on `market`
const provision = await directLP.computeAskProvision();

// Post a new ask (offering 105 DAI for 104 USDC) at a price of 150/104~=1.0096
// Consider looking at the consoleAsks above and increase gives such that the offer becomes visible in this list
const { id: offerId } = await directLP.newAsk({ wants: 105, gives: 104, fund: provision });

// Check the order was posted (or look at https://testnet.mangrove.exchange.
market.consoleAsks();
```

{% endcode %}


# Guides


# Sell and buy orders

Using the API to pass taker orders on a Mangrove market.

Buying with cash or selling for cash can be done via the `buy` and `sell` functions of a [Market](/mangrove-js/technical-references/api-classes-overview#market) instance. The code snippets below send limit buy (taker) orders on the market, with an allowed slippage of 2%:

```typescript
// buy limit order for 100 base tokens at an average price of 0.1 quote per base
const buyResult = mgvMarket.buy({volume:100, price:0.1, slippage:2});
// limit order with a desired quantitiy
const buyResult_ = mgvMarket.buy({wants:100, gives:1000, slippage:2});
// sell limit order (selling 10 base tokens).
const sellResult = mgvMarket.sell({volume:10, price: 0.09, slippage:2});
```

{% hint style="info" %}
`sell` and `buy` orders return a triple `{`takerGave:Big, takerGot:Big, penalty:Big`}` where:

* `takerGave` is the total amount of base (for a sell) or quote (for a buy) tokens that the taker spent for the order
* `takerGot` is the total amount of quote (for a sell) or base (for a buy) tokens that the taker received as a result of the order
* `penalty` is the amount of native tokens the taker received to compensate for the gas lost of executing failing offer during the order execution (see [offer bounty](https://docs.mangrove.exchange/basic-usage/offer-maker/offer-provision#computing-the-provision-and-offer-bounty)).
  {% endhint %}


# Posting bids and asks

Using the API to post Maker orders on a Mangrove Market.

With a [`LiquidityProvider`](/mangrove-js/technical-references/api-classes-overview#liquidityprovider) `mgvLP` on a [Market](/mangrove-js/technical-references/api-classes-overview#market) instance, it is possible to post Bids and Asks with the following commands:

```javascript
// gives unlimited approval to Mangrove to transfer Base token from liquidity provider's logic/EOA
let tx = await mgvLP.approveMangroveForBase();
await tx.wait(); // waiting for tx confirmation

// querying mangrove to know the bounty for posting a new Ask on `market`
let prov = await mgvLP.computeAskProvision();
tx = await mgvLP.fundMangrove(prov);
await tx.wait();

// posting a new Ask on Mangrove
const {id:ofrId} = await mgvLP.newAsk({volume:1000, price:0.99});
const {id:ofrId_} = await mgvLP.newBid({volume:1000, price: 1.01});
```


# Technical references


# API classes overview

{% hint style="info" %}
**Numbers**

* Numbers returned by functions are either plain javascript [`number`](https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/Number) or [`big.js`](https://github.com/MikeMcl/big.js/)instances. Some functions with names ending in `Raw` may return`ethers.BigNumbers`.
* As input, numbers can be as plain javascript `numbers`, `big.js` instances, but also a`string`.

The precision used when dividing is 20 decimal places.

**Overrides**

All API functions that produce a signed transaction can be equipped with the usual `ethers.js` overrides as optional parameters.
{% endhint %}

## Mangrove

The root class of the API. Use `Mangrove.connect` to get an instance of it. Here are a few possibilities:

```typescript
mgv = await Mangrove.connect(window.ethereum); // web browser
mgv = await Mangrove.connect('http://127.0.0.1:8545'); // HTTP provider
mgv = await Mangrove.connect(); // Uses Ethers.js fallback mainnet (for testing only)
mgv = await Mangrove.connect('rinkeby'); // Uses Ethers.js fallback (for testing only)
// Init with private key (server side)
mgv = await Mangrove.connect(
'https://mainnet.infura.io/v3/_your_project_id_', // provider
{
  privateKey: '0x_your_private_key_', // preferably with environment variable
});
// Init with HD mnemonic (server side)
mgv = await Mangrove.connect( {
  signer: myEthersWallet
});
```

You can test you are indeed connected to the deployed Mangrove by asking for the current global configuration of Mangrove:

`config = await mgv.config()`

The above `mgv` object gives you access to the `MgvToken`, `Market` and `OfferLogic` (allowing one to connect to an onchain offer logic) and `LiquidityProvider`(an abstraction layer to pass [bids](https://www.investopedia.com/terms/b/bid.asp) and [asks](https://www.investopedia.com/terms/a/ask.asp) on Mangrove) objects.

{% hint style="info" %}
`mgv.contract`gives access to the standard `ethers.js` contract and allows one to interact with the deployed `Mangrove` using low-level `ethers.js` calls. Hence, `await mgv.contract.f(...)` will produce the ethers.js call to Mangrove (signed when needed by the `signer` provided to the `connect` function).
{% endhint %}

## MgvToken

This class provides easy means to interact with a deployed contract on the standard [EIP-20](https://eips.ethereum.org/EIPS/eip-20). To obtain an instance use:

```javascript
mgvTkn = mgv.token("<tokenSymbol>"); // e.g "DAI", "WETH", "amDAI", etc.
```

with the above `MgvT` object one has access to standard calls using human readable input/outputs. For instance:

```javascript
await mgvTkn.approve("<spender>"); // gives infinite approval to spender
await mgvTkn.approve("<spender>",0.5); // gives allowance to spend 0.5 token units to spender
await mgvTkn.contract.approve("<spender>", mgvTkn.mgv.toUnits(0.5)); // ethers.js call
```

Note that Mangrove's API deals with token decimals automatically (see definitions in [`constants.ts`](https://github.com/mangrovedao/mangrove/blob/master/packages/mangrove.js/src/constants.ts)).

{% hint style="info" %}
`MgvToken.contract` gives access to the `ethers.js` contract allowing one to interact with the deployed contract using low level calls (for instance if the token has functions that are do not belong to the ERC20 standard).
{% endhint %}

## Market

The `Market` class is an abstraction layer to interact with Mangrove as a liquidity taker, using standard market [buy and sell orders](/mangrove-js/guides/sell-and-buy-orders). To obtain one instance use:

```typescript
//connect to a (base,quote) market with default options
mgvMarket = await mgv.connect({base:"<base_symbol>", quote:"<quote_symbol>"});

// connect to the market, caching the first 50 best bids and asks
mgvMarket = await mgv.connect({base:"<base_symbol>", quote:"<quote_symbol>", maxOffers: 50});
```

{% hint style="info" %}
Upon connection to a market, the API subscribes to events emanating from Mangrove in order to maintain a local cache of the order book. One may increase the size of the cache by using `mgv.connect({..., maxOffers:<size of the book>})`.
{% endhint %}

For debugging purpose, the class provides a console of the current state of bids and asks posted on Mangrove. For instance to display the bid offers on Mangrove on this market:

```typescript
// Pretty prints to console the bid offers, showing offer `id`, offer `volume` and offer `price
await mgvMarket.consoleAsks(["id", "volume", "price"]);
```

`Market` instances allow one to subscribe to markets events using:

```javascript
const f (event) => ...; // what you want to do when receiving the event 
mgvMarket.subscribe (f);
```

To unsubscribe `f` from market events simply use `mgvMarket.unsubscribe(f)`.

Market events are records of the following kinds:

* `{type: 'OfferRetract', ba:'asks'|'bids', offer:Market.Offer}` when an ask or a bid `offer` is removed from the book
* `{type: 'OfferWrite', ba:'asks'|'bids', offer:Market.Offer}` when a bid or ask `offer` is added to the book (or updated)
* `{type:'OfferFail', ba:'asks'|'bids', taker:string, 'takerWants':Big, takerGives:Big, mgvData:string, offer:Market.Offer}` when `offer` failed to deliver. Note that `mgvData` is a bytes32 string encoding of the fail reason (according to Mangrove).
* `{type: 'OfferSuccess', ba: 'asks'|'bids', taker: string, takerWants:Big, takerGives:Big, offer:Market.Offer}` when `offer` was successfully executed (possibly on a partial fill whenever `offer.gives`>`takerWants`).

and where `Market.Offer` has the following main fields:

```typescript
id: number; // the id of the executed offer
maker: string; // address of the maker (contract/wallet) in charge of the offer
gasreq: number; // gas required by the offer
volume: Big; // total volume proposed
price: Big; // price offered
```

## OfferLogic

A [reactive offer](https://docs.mangrove.exchange/data-structures/market) is managed by a smart contract which implements its [logic](#offerlogic). One may use the API to post liquidity on Mangrove via a deployed logic that complies to the [IOfferLogic](https://github.com/mangrovedao/mangrove/blob/master/packages/mangrove-solidity/contracts/Strategies/interfaces/IOfferLogic.sol) interface. To do so, one first need an `OfferLogic` instance:

```typescript
const mgvLogic = mgv.offerLogic("0x..."); // NB not an async call
```

The `mgvLogic` instance offers various function to query and set the underlying contract state, for instance:

```javascript
await mgvLogic.setAdmin("0x..."); // set new admin
await mgvLogic.redeemToken("DAI", 100); // transfer 100 DAI from contract's signer account to signer's EOA
await mgvLogic.depositToken("WETH", 0.1); // put 0.1 WETH from signer's EOA to contract's account
const bal = await mgvLogic.tokenBalance("USDC"); // returns signer's balance of USDC on the contract
const mgvLogic_ = await mgvLogic.connect(newSigner); // returns a new OfferLogic instance with a new signer
cosnt gasreq = await mgvLogic.getDefaultGasreq(); // returns the gas required (by default) for new offers of this contract
await mgvLogic.setDefaultGasreq(200000); // default gasreq setter
```

{% hint style="danger" %}
When using an offer logic that inherits from the [`MultiUser.sol`](https://github.com/mangrovedao/mangrove/blob/master/packages/mangrove-solidity/contracts/Strategies/OfferLogics/MultiUsers/MultiUser.sol) solidity class, one should always use the above `depositToken` (and `tokenBalance`) instead of sending tokens (or querying balance) directly to the contract which might result in the tokens being burnt (as only `depositToken` will increase user balance on the contract).
{% endhint %}

## LiquidityProvider

A `LiquidityProvider` instance is the object one needs to [post Bids and Asks](/mangrove-js/guides/posting-bids-and-asks) on a Mangrove market. There are two means to obtain an LiquidityProvider: either to post a [direct Offer](https://docs.mangrove.exchange/offer-making-strategies/basic-offer) or to post an Offer relying on some onchain [logic](#offerlogic).

To act as a direct liquidity provider on a some [`mgvMarket`](#market) you must obtain a `LiquidityProvider` instance from an [`mgv`](#mangrove) object using:

```javascript
const mgvDirectLP = await mgv.liquidityProvider(mgvMarket);
```

{% hint style="info" %}
The EOA providing the liquidity for ask and bid offers emanating from a direct liquidity provider is the address of the [`mgv`](#mangrove)'s signer provided at the creation of the Mangrove instance.
{% endhint %}

For more complete experience of the Mangrove capabilities, on may rather post bids and asks via an offer logic `mgvLogic`. To do so, one does:

```javascript
const mgvOnchainLP = await mgvLogic.liquidityProvider(mgvMarket);
```

Besides posting offers on Mangrove, a `LiquidityProvider` instance `mgvLP` gives access to various useful functions such as:

```javascript
const missingAskProvision = await mgvLP.computeAskProvision();
const missingBidProvision = await mgvLP.computeBidProvision();
```

which return the missing provision (in native tokens) this liquidity provider needs to deposit on Mangrove if it wishes to post a new bid or ask. When provision is missing, one may fund Mangrove using:

```javascript
const ethersTx = await mgvLP.fundMangrove(missingAskProvision);
await ethersTx.wait(); // waiting for the funding tx to be confirmed
```


# API documentation

The specification of the mangrove.js API is available in the [mangrove.js API reference documentation](https://code.mangrove.exchange/mangrove-js/). The code is available at [GitHub](https://github.com/mangrovedao/mangrove).


# Background


# API documentation


# Keeper bots

Keeper bots are an essential part of the Mangrove ecosystem that ensure a smooth experience for all

There are two types of keeper bots in the Mangrove ecosystem:

| Keeper bot            | Purpose                                                                                                                             | Operated by  |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| Cleaner bot           | Monitors the order books and cleans (=snipes) offers that will fail. This keeps the books clean and earns bounties for the keepers. | Anyone       |
| Gas price updater bot | Ensures that Mangrove uses up-to-date gas prices. This gives more accurate estimates when calculating provisions.                   | Mangrove DAO |

In this section, you'll find information on how to build and run your own bots. There's also more in-depth discussion of the role of keeper bots in the Mangrove ecosystem.


# Getting started


# Guides


# Technical references


# Bots

Examples of bots are provided in the [packages](https://github.com/mangrovedao/mangrove/tree/master/packages) folder of the GitHub repository for mangrove.js.


# Background


# Kandel Takara


# What is Kandel and Kandel Takara?

Kandel is an Automated Market Making strategy that uses on-chain order flow to repost offers instantly, without any latency. It could be considered as a market-making bot equivalent that operates solely on the blockchain. It leverages **the interaction between buyers and sellers** that creates price movement, rather than the price itself.

Within a market and price range you select, Kandel automatically posts Bids and Asks. **Its main goal is to buy low and sell high** - profits are made through accumulated spread, i.e. the difference between the Bids and Asks that are taken.

## Kandel Takara

Kandel Yei is a strategy based on Kandel, but with funds deposited on [Takara](https://app.takaralend.com/) at any given time, the leading lending protocol on Sei. This allows users to combine trading fees generated on Oxium while also benefiting from Takara’s yield.


# How does Kandel Work?

This section is a detailed explanation of how Kandel works, introducing configuration parameters and key mechanics. For the sake of simplicity, we have clearly separated the startup steps and picked round numbers.

Kandel is not intended as a "set and forget" strategy, and needs ongoing maintenance and checks.


# Step-by-step visual explanation

### Setting things up <a href="#setting-things-up" id="setting-things-up"></a>

Before launching your customized Kandel strategy, you will be asked to set specific input parameters. For more information, you can refer to the Parameters description table, as well as the Choosing parameters section.

<figure><img src="/files/cEWRJl9Jzhnq3J5NwMvG" alt=""><figcaption></figcaption></figure>

Based on the selected **price range** and either the `number of offers` or `ratio`, the price grid is constructed using a geometric progression. The `min` and `max` prices of the user inputs are the limits of the grid.

The increments are calculated using a key metric called **ratio** (of the geometric progression). Kandel starts from the `min` price, all the way up to the `max` price. By default, the ratio is \~1% (due to ticks it will not be exactly 1%).

**Note** : In this example, the user selected an ETH/USDC trading pair.

<figure><img src="/files/lHPXK69aFdLSvEgqIqGK" alt=""><figcaption></figcaption></figure>

Based on the selected amount of initial liquidity to be deposited, Kandel draws the **volume distribution** (i.e. the initial volume at each price point). In the example of a uniform volume distribution, the user's liquidity is spread evenly throughout the price grid.<br>

**Note** : For this explanation, we are conveniently using a 1 ETH allocation for each increment. If based on our parameters, our Kandel would create a price grid of 10 points, for example, then we would use 10 ETH in total (1 ETH \* 10 price points).

### Populating Bids and Asks <a href="#populating-bids-and-asks" id="populating-bids-and-asks"></a>

<figure><img src="/files/KG4zXm4nta2G5sU15rh6" alt=""><figcaption></figcaption></figure>

Afterwards, the Kandel strategy contract populates the price grid by posting offers:

* **Bids** are posted from min price to mid price (current price)
* **Asks** are on the other side of the book, from mid price to max price

### Bid is taken <a href="#bid-is-taken" id="bid-is-taken"></a>

<figure><img src="/files/apm9qBmpCQHoAgKwkqKu" alt=""><figcaption></figcaption></figure>

When a **bid** is taken, the Kandel strategy contract sends the corresponding amount of **quote tokens** (USDC) and receives a corresponding amount of **base tokens** (ETH).

### Reposting liquidity as an Ask <a href="#reposting-liquidity-as-an-ask" id="reposting-liquidity-as-an-ask"></a>

<figure><img src="/files/3wQA1ynFLtFF5JcFBD9R" alt=""><figcaption></figcaption></figure>

The received amount of **base tokens** (ETH) is used to post a dual offer at a **step size k=1 above**. This is automatically handled by Kandel, it is part of its trading behaviour.

**Note** : Since the volume objective at the relevant index is 1 ETH, all the received liquidity is used to populate corresponding **ask**. Our Kandel just received 1 ETH (previous Bid), and is using it all to repost an offer, an Ask (called dual offer).

### Ask is taken <a href="#ask-is-taken" id="ask-is-taken"></a>

<figure><img src="/files/C8CyeGZ2gwKhX88oXeOc" alt=""><figcaption></figcaption></figure>

Inversely to the **bid** example, when an ask is taken, the Kandel strategy contract sends the corresponding amount of **base tokens** (ETH) and receives a corresponding amount of **quote tokens** (USDC).

### Reposting liquidity as an Bid <a href="#reposting-liquidity-as-an-bid" id="reposting-liquidity-as-an-bid"></a>

<figure><img src="/files/aFFLX0q03aqqQhaxDDab" alt=""><figcaption></figcaption></figure>

The received amount of **quote tokens** (USDC) is used to post a dual offer **step size k=1 below**.

In our example:

* We just received 1,300 USDC for sending 1 ETH through our **ask**
* Previously, we sent 1,287 USDC and received 1 ETH through our **bid**

Therefore, 13 USDC is reinvested into the strategy. A new **bid** at k=1 steps below is reposted, and offers 1,300 USDC for 1.01 ETH.

**Calculation**

* *Profit = 1,300 USDC - 1,287 USDC = 13 USDC*
* *13 / 1300 = 0.01 = 1%*
  * i.e. we made a 1% profit on the spread
* Kandel will repost our **bid** to offer *1,287+13 USDC* for *1\*1.01 ETH*, reinvesting the 1% profit we just made

### Another Ask is taken <a href="#another-ask-is-taken" id="another-ask-is-taken"></a>

<figure><img src="/files/jyJFpgE4HqgcEBZVxcqM" alt=""><figcaption></figcaption></figure>

When another **ask** is taken, once again Kandel sends the corresponding amount of **base tokens** (ETH) and receives a corresponding amount of **quote tokens** (USDC).

### Reposting liquidity as a Bid #2 <a href="#reposting-liquidity-as-a-bid-2" id="reposting-liquidity-as-a-bid-2"></a>

<figure><img src="/files/xwPrv9t6j3IHH8jmFwnC" alt=""><figcaption></figcaption></figure>

Similarly to our previous **bid**, the received amount of **quote tokens** (USDC) is used to post a dual offer **step size k=1 below**.

Note :

If an **ask** was to be taken next, the profit from the spread would be reinvested into the strategy.


# Parameters

This section describes Kandel's parameters. For more contextual information, head over to the visual explanation.

| Parameters        | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Pair              | <p>The pair represents the chosen market on which a Kandel strategy is running (along with the technical tick spacing).</p><p><em>Example: ETH/USDC is a trading pair</em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| Price range       | <p>The price range is needed to run any market-making strategy. It consists of the lowest and highest prices in the price grid at which Kandel instance posts its bids and asks.</p><p><em>Example of a price range:</em><br><em>• Lowest price = 1000 USDC per ETH</em><br><em>• Highest price = 1500 USDC per ETH</em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| Current price     | <p>The current price of the base token that is used for constructing the price distribution.</p><p><em>Example: the price of ETH is used for the ETH/USDC pair</em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| Number of offers  | The number of offers to be published by the Kandel strategy within the selected price range.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| Ratio             | <p>The ratio defines the distance between price points which is derived using geometric progression.</p><p><em>Example:</em><br><em>• Ratio is <code>0.01</code> (due to ticks it will not be exact)</em><br><em>• Mid price is <code>1000</code></em><br><em>• Price point below mid price: <code>10000.99</code></em><br><em>• Price point above mid price: <code>10001.01</code></em>Additionally, the ratio could be derived from price points <code>PricePoint(i+1) / PricePoint(i) - 1</code>.<br><em>Example: <code>1010 / 1000 - 1 = 0.01</code></em></p>                                                                                                                                                                                                                                                                                                                                                                     |
| Step size         | <p>It is the distance between an executed bid/ask and its dual offer.</p><p>Whenever a Kandel ask is taken at a given price point, Kandel uses the amount of quote just received to place a bid at a lower price point. With a step size of 1, it will place the bid at the price point immediately below. With a step size of 2, Kandel will repost two price points below, etc. (Technical aside: if in attempting to repost say 3 steps below Kandel hits the boundaries of its range it will transport as far below as possible). The same applies symmetrically for bids.</p><p>Using a step size ≥ 2 allows one to publish a more continuous liquidity on the books, regularising the strat’s PnL, while at the same time keeping a reasonable spread between price points. Indeed, what matters to PnL is not the distance between price points, but how far money moves along the price grid each time an offer is taken.</p> |
| Initial inventory | <p>The initial inventory is the amount of base tokens and quote tokens that must be deposited into the strategy. The minimum to be deposited into the strategy depends on the selected price range and density of the selected market.</p><p><em>Example on the ETH/USDC pair:</em><br><em>• Base token is ETH</em><br><em>• Quote token is USDC</em></p>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| Bounty            | <p>It is the required amount of native tokens to be deposited into the strategy. A provision is required to post an offer, in order to pay a potential bounty. The bounty is only a subset, smaller in value than the provision.</p><p>The provision covers the whole price grid, hence:<br>• <em>Kandel provision = Provision per offer x Number of offers</em></p><p>Example: if the selected pair is on the Polygon network, the bounty would be an amount of MATIC tokens.\*</p>                                                                                                                                                                                                                                                                                                                                                                                                                                                  |


# Choosing Kandel parameters

This section goal is to help you develop an intuition to choose your Kandel parameters. It should be taken as an explanation on how the various parameters can impact your Kandel, and how the market conditions (ex: volatility) could be taken into account. It is **not** a trading advice.

**Note** : As a reminder, Kandel is not intended as a "set and forget" strategy, and needs ongoing maintenance and checks.

We will be going through standard steps you might want a take in order to check the market and deploy a new Kandel. Essentially, that means that by using discrete AMM such as Kandel, you can fix the level of liquidity you are offering adjusted per volatility. So choosing the spread starts with answering the question - what is the volatility? If you can estimate or predict it well enough, the only thing you need to do is pick the spread (i.e. your parameters for Kandel).

### Check-in frequency <a href="#check-in-frequency" id="check-in-frequency"></a>

First, it is good practice to know how often you aim to update your Kandel. Depending on the trading pair you chose, markets can behave very differently.

**Example** : I will update my Kandel every 24h.

### Set your price range <a href="#set-your-price-range" id="set-your-price-range"></a>

Next, you should try to anticipate how much the market/price will vary during that period you just decided on. You are kind of betting on daily volatility.

**Example :** I will look at the market volatility for the past 24h, and decide on the price range for my new Kandel.

### Number of Offers / Ratio <a href="#number-of-offers--ratio" id="number-of-offers--ratio"></a>

This is the number of offers / ratio of the progression used to calculate the price grid. You would logically bet on intra-day volatility (few min or hours). If the volatility is increasing, you might want to increase the grid size (space between the offers). You will find more information about its calculation in the previous table.

**Note :**&#x20;

* High volatility: spaced out offers (less offers in the chosen range) -> higher ratio
* Low volatility: narrow offers (more offers in the chosen range) -> smaller ratio

### Step size <a href="#step-size" id="step-size"></a>

The general idea to configure your step size, is that a bigger volatility would likely lead to a bigger step size.

### Simple use case <a href="#simple-use-case" id="simple-use-case"></a>

Let's say you want to have a continuous Kandel, and maybe your current paramaters allow you only 2 offers:

* The solution to this is instead of having 2 offers with a step size = 1, you can configure 16 offers with a step size of 8
* That gives you continuity (more offers for a similar interval)
* When your offers are taken, Kandel will be able to "grab" lower prices


# Published Liquidity

Kandel instances don't lock your funds into the strategy. It uses the funds on the selected source, for publishing the chosen amount of liquidity.

Published liquidity is the amount of liquidity in active offers that are managed by the particular Kandel instance.


# More on failing offers

This section explains the reasons why some offers might fail using Kandel.

### Definition <a href="#definition" id="definition"></a>

When we talk about an offer "failing", we mean that it could not execute. An offer can also fail to update itself. While we won't go into details in this part of the documentation, it is important to mention and differentiate those cases to further understand Kandel strategy's behavior.

* `makerExecute()`: it is the callback function that is called when an offer is matched. Its role is to execute all offers that were posted on Oxium by a given contract.
  * A failure in `makerExecute()` means the trade is canceled, and the bounty is given to the Taker as a compensation. The offer is removed from the book.
* `makerPosthook()`: it is the callback function that is called after the offer execution (i.e. after a successful execution of `makerExecute()`).
  * A failure in `makerPosthook()` means the offer cannot update or repost itself after being taken. It does not cancel the trade, since it is called after `makerExecute()`.

### Kandel and `makerExecute()` failure <a href="#kandel-and-makerexecute-failure" id="kandel-and-makerexecute-failure"></a>

After launching a Kandel strategy, Bids and Asks are populated with a certain volume. Kandel strategy's contract is handling all the posting for the user, using liquidity that has been previously deposited.\
Therefore, since the user is not in charge of writing and maintaining the smart contract, failures to execute `makerExecute()` can be almost entirely ruled out, with the exception of some very specific scenarios such as:

* Someone severely modifies the volume distribution/sourcing methods, creating issues when a Kandel Bid/Ask is taken (via the SDK)
* Kandel runs on YEI, and the user's liquidity is not available for sourcing at the time the offer is taken. That could happen if the user's funds are suddenly borrowed entirely (on YEI)

### Kandel and `makerPosthook()` failure <a href="#kandel-and-makerposthook-failure" id="kandel-and-makerposthook-failure"></a>

The main failures that Kandel could run into are linked to reposting Bids and Asks. This has little incidence for the user, nor does it affect the behavior of his Kandel strategy.\
Non-reposted liquidity will be placed into the Unallocated liquidity reserve, and the offer will be "empty" for Kandel, until the user replenishes it.<br>

**Note** :

> If too many empty offers stack up, it would diminish Kandel's ability to profit from the spread, and therefore the overall generated yield. Kandel is not intended as a "set and forget" strategy, and needs ongoing maintenance and checks.

Reposting offers is handled with `makerPosthook()`, and failure could happen if:

* The residual of a partially taken offer is too small with regard to density:
  * A partially taken offer is the result of a Taker placing a Market order
  * If an offer is almost entirely taken, the remainder (dust) could be too small to pass the density check, leading to a failure to repost itself
* Kandel runs out of gas during the execution of the `makerPosthook()` because the gas requirements suddenly changed
  * This is unlikely to happen, but it theoretically could (if the order book becomes very dense in offers, for example)


# Potential risks

Kandel strategy is subject to some risks that should be taken into consideration. By using Kandel, you acknowledge (i) having the necessary knowledge and understanding of the blockchain technology and the tokens, and (ii) comprehended the risks associated with blockchain-based software systems and tokens, as described below and in the disclaimer.

### Economical risks <a href="#economical-risks" id="economical-risks"></a>

As a user of the Kandel strategy, you understand that using Kandel can be affected by economic risks, including but not limited to:

* Partial or total loss of the tokens used;
* Partial or total loss of the value of the tokens used;
* Market extreme volatility;
* Insolvency of a third-party platform or company;
* Absence of liquidity and impossible resale on markets of the tokens.

### Impermanent Loss <a href="#impermanent-loss" id="impermanent-loss"></a>

Kandel is a passive market-maker where profit is generated from the spread. An example of impermanent loss on an ETH/USDC pair would be as follows:

1. If the current price of ETH/USDC pair moves up, asks will be consumed.
2. If the price keeps going up and crosses the max price range value, Kandel strategy will be left only with active bid offers on the ETH/USDC market.
3. It is likely that no one would be interested in taking these bids since they would not match the current price (you would be offering too little USDC for ETH, considering the new current price). This is what we call impermanent loss - your strategy stops generating profit from the spread.

### Smart contract and technological risks <a href="#smart-contract-and-technological-risks" id="smart-contract-and-technological-risks"></a>

You understands that even though the strategy has been implemented by an experienced team of researchers and developers, the use of Kandel can be affected by smart contract and technological risks, including but not limited to:

* Security error or failure allowing and/or resulting in hacking and stealing of user, third-party platform and/or website/app data;
* Stealing or loss of the user external wallet private key or his access to the third-party platform;
* Risks associated with blockchains used for the strategy, including but not limited to due to successful attacks from hackers or other criminal groups or organizations or countries, including but not limited to denial of service attacks, Sybil attacks, spoofing, smurfing malware attacks, consensus-based attacks, or phishing, or other new methods that may or may not be known;
* Lack of transparency in crypto asset management and markets;

That being said, please note that the **Kandel strategy has been thoroughly audited** by ChainSecurity.


# Deployment adresses

### Contract Addresses[​](https://docs.mangrove.exchange/developers/addresses/contract-addresses#core-contract-addresses) <a href="#core-contract-addresses" id="core-contract-addresses"></a>

{% tabs %}
{% tab title="Base" %}

#### Core contracts

These contracts are the immutable base of Mangrove both holding the book and markets, as well as exposing key view functions.

<table><thead><tr><th width="129.67578125">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Mangrove</td><td>0x22613524f5905Cb17cbD785b956e9238Bf725FAa</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/core/Mangrove.sol">Mangrove.sol</a></td></tr><tr><td>MgvReader</td><td>0xe5B118Ea1ffBC502EA7A666376d448209BFB50d3</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/periphery/MgvReader.sol">MgvReader.sol</a></td></tr></tbody></table>

#### Oracles

Mangrove oracles are used in order to define the minimum order size. They often (statically or dinamically) are the price of the asset relative to the native token (gas token) times a constant. The oracle also gives the final mulitplier which is an (over)estimation of the chain's gas price.

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>MgvPriceOracle</td><td>0x8Fb396e0745F0B4b1Cf12FB2e4d1662Ff7560ffD</td><td><a href="https://github.com/mangrovedao/mgv-oracle/blob/main/src/price/MgvPriceOracle.sol">MgvPriceOracle.sol</a></td></tr></tbody></table>

#### Strategies

These contracts (also called Maker contracts) are the one allowing to create limit orders, kandel strategies, ...

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>MangroveOrder</td><td>0xA3c363Ca0EA3603faEe9FAcffD65E777122adF36</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/MangroveOrder.sol">MangroveOrder.sol</a></td></tr><tr><td>KandelSeeder</td><td>0x808bC04030bC558C99E6844e877bb22D166A089A</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/KandelSeeder.sol">KandelSeeder.sol</a></td></tr><tr><td>AaveKandelSeeder</td><td>0x095854c8C4591Fb0a413615B9a366B4Dd69b9B1D</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/AaveKandelSeeder.sol">AaveKandelSeeder.sol</a></td></tr><tr><td>ERC4626KandelSeeder</td><td>0x4778c54E6380BBC6eF9647f2A31528B0640B41fE</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/ERC4626KandelSeeder.sol">ERC4626KandelSeeder.sol</a></td></tr></tbody></table>

#### Vaults

Vaults is a contract that allow any curators to open and manage a kandel a position with user funds in order to enable a seamless deposit and earn experience.

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Vault Factory</td><td>0x26A0e433f89317Ca5585945198a5F0760C1dAFA5</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/MangroveVaultFactory.sol">MangroveVaultFactory.sol</a></td></tr><tr><td>ERC4626 VaultFactory</td><td>0x92dB74A11Ec2b2acDCFC354cf55243cF33C052B8</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/integrations/MangroveERC4626KandelVaultFactory.sol">MangroveERC4626KandelVaultFactory.sol</a></td></tr><tr><td>Chainlink oracle factory</td><td>0x656A6ac038D1686D4f80427ddaF59b352f960123</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/v2/MangroveChainlinkOracleFactoryV2.sol">MangroveChainlinkOracleFactoryV2.sol</a></td></tr><tr><td>Chainlink oracle factory (legacy)</td><td>0x9d05c7A303efEbD215B86B57Da2Fc671039E5712</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/MangroveChainlinkOracleFactory.sol">MangroveChainlinkOracleFactory.sol</a></td></tr><tr><td>Dia Oracle Factory</td><td>0x5297561cb9df1D2Ff83698C6fc51aBeF24D39560</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/dia/MangroveDiaOracleFactory.sol">MangroveDiaOracleFactory.sol</a></td></tr><tr><td>Oracle Combiner</td><td>0xb898C4a986a1e4Fd31b9818772F9EC16dbf3EFED</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/OracleCombinerFactory.sol">OracleCombinerFactory.sol</a></td></tr><tr><td>Mint helper (V1)</td><td>0x2AE6F95F0AC61441D9eC9290000F81087567cDa1</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/mint-helper/MintHelperV1.sol">MintHelperV1.sol</a></td></tr></tbody></table>

#### Ghostbook

The ghostbook is a tool used in the frontend in order to combine Mangrove's order book liquidity with external liquidity

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>Ghost Book</td><td>0x15F02Fb9c9Bb772A3303349F88c94Fc971bd549F</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/MangroveGhostBook.sol">MangroveGhostBook.sol</a></td></tr><tr><td>UniV3 module</td><td>0xAf31bEb21d2b1f8C3BdD211eC02470265A21ea3f</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/modules/UniswapV3Swapper.sol">UniswapV3Swapper.sol</a></td></tr></tbody></table>
{% endtab %}

{% tab title="Arbitrum One" %}

#### Core contracts

These contracts are the immutable base of Mangrove both holding the book and markets, as well as exposing key view functions.

<table><thead><tr><th width="129.67578125">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Mangrove</td><td>0x109d9CDFA4aC534354873EF634EF63C235F93f61</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/core/Mangrove.sol">Mangrove.sol</a></td></tr><tr><td>MgvReader</td><td>0x7E108d7C9CADb03E026075Bf242aC2353d0D1875</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/periphery/MgvReader.sol">MgvReader.sol</a></td></tr></tbody></table>

#### Oracles

Mangrove oracles are used in order to define the minimum order size. They often (statically or dinamically) are the price of the asset relative to the native token (gas token) times a constant. The oracle also gives the final mulitplier which is an (over)estimation of the chain's gas price.

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>MgvPriceOracle</td><td>/ (Arbitrum uses static values)</td><td>/</td></tr></tbody></table>

#### Strategies

These contracts (also called Maker contracts) are the one allowing to create limit orders, kandel strategies, ...

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>MangroveOrder</td><td>0x50793D97A0c905Ea51c1C93f37FC73aBE6D2ffCc</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/MangroveOrder.sol">MangroveOrder.sol</a></td></tr><tr><td>KandelSeeder</td><td>0x89139Bed90B1Bfb5501F27bE6D6f9901aE35745D</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/KandelSeeder.sol">KandelSeeder.sol</a></td></tr><tr><td>AaveKandelSeeder</td><td>0x55B12De431C6e355b56b79472a3632faec58FB5a</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/AaveKandelSeeder.sol">AaveKandelSeeder.sol</a></td></tr></tbody></table>

#### Vaults

Vaults is a contract that allow any curators to open and manage a kandel a position with user funds in order to enable a seamless deposit and earn experience.

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Vault Factory</td><td>0x6B82CE8a45Ce9BeF9B20c3D65747356a5cDab41A</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/MangroveVaultFactory.sol">MangroveVaultFactory.sol</a></td></tr><tr><td>Chainlink oracle factory</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/v2/MangroveChainlinkOracleFactoryV2.sol">MangroveChainlinkOracleFactoryV2.sol</a></td></tr><tr><td>Chainlink oracle factory (legacy)</td><td>0x31c47E3F442F521E1c65b5b626aC2e978C1f2587</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/MangroveChainlinkOracleFactory.sol">MangroveChainlinkOracleFactory.sol</a></td></tr><tr><td>Dia Oracle Factory</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/dia/MangroveDiaOracleFactory.sol">MangroveDiaOracleFactory.sol</a></td></tr><tr><td>Oracle Combiner</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/OracleCombinerFactory.sol">OracleCombinerFactory.sol</a></td></tr><tr><td>Mint helper (V1)</td><td>0xC39b5Fb38a8AcBFFB51D876f0C0DA0325b5cD440</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/mint-helper/MintHelperV1.sol">MintHelperV1.sol</a></td></tr></tbody></table>

#### Ghostbook

The ghostbook is a tool used in the frontend in order to combine Mangrove's order book liquidity with external liquidity

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>Ghost Book</td><td>0x46708Dd6E68e1f09c6f4830C2586f73659dFafEA</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/MangroveGhostBook.sol">MangroveGhostBook.sol</a></td></tr><tr><td>UniV3 module</td><td>0x22Ba67Eb361Ec40e0949ED034F3CE08Af51099fA</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/modules/UniswapV3Swapper.sol">UniswapV3Swapper.sol</a></td></tr></tbody></table>
{% endtab %}

{% tab title="Base Sepolia" %}

#### Core contracts

These contracts are the immutable base of Mangrove both holding the book and markets, as well as exposing key view functions.

<table><thead><tr><th width="129.67578125">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Mangrove</td><td>0xBe1E54d0fC7A6044C0913013593FCd7D854C07FB</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/core/Mangrove.sol">Mangrove.sol</a></td></tr><tr><td>MgvReader</td><td>0xe118B2CF4e893DD8D954bB1D629e95026b5E8D5A</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/periphery/MgvReader.sol">MgvReader.sol</a></td></tr></tbody></table>

#### Oracles

Mangrove oracles are used in order to define the minimum order size. They often (statically or dinamically) are the price of the asset relative to the native token (gas token) times a constant. The oracle also gives the final mulitplier which is an (over)estimation of the chain's gas price.

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>MgvPriceOracle</td><td>/ (Static values)</td><td><a href="https://github.com/mangrovedao/mgv-oracle/blob/main/src/price/MgvPriceOracle.sol">MgvPriceOracle.sol</a></td></tr></tbody></table>

#### Strategies

These contracts (also called Maker contracts) are the one allowing to create limit orders, kandel strategies, ...

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>MangroveOrder</td><td>0xC00D2Da52195B123d3c994aaf2eb1E8DA8999d4f</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/MangroveOrder.sol">MangroveOrder.sol</a></td></tr><tr><td>KandelSeeder</td><td>0x1A839030107167452D69d8f1a673004B2a1b8A3A</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/KandelSeeder.sol">KandelSeeder.sol</a></td></tr><tr><td>AaveKandelSeeder</td><td>0xCb62cD0Ea7aD46d5B630C1068C7bED2cBd2b7E23</td><td><a href="https://github.com/mangrovedao/mangrove-strats/blob/develop/src/strategies/offer_maker/market_making/kandel/AaveKandelSeeder.sol">AaveKandelSeeder.sol</a></td></tr></tbody></table>

#### Vaults

Vaults is a contract that allow any curators to open and manage a kandel a position with user funds in order to enable a seamless deposit and earn experience.

<table><thead><tr><th width="167.68359375">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Vault Factory</td><td>0x751A2128aDA840049D0Cc1C4B7F8cF7311F568Fd</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/MangroveVaultFactory.sol">MangroveVaultFactory.sol</a></td></tr><tr><td>Chainlink oracle factory</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/v2/MangroveChainlinkOracleFactoryV2.sol">MangroveChainlinkOracleFactoryV2.sol</a></td></tr><tr><td>Chainlink oracle factory (legacy)</td><td>0xC6488ED14C0AD6763eC56d8e81F1bDE5016772dD</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/chainlink/MangroveChainlinkOracleFactory.sol">MangroveChainlinkOracleFactory.sol</a></td></tr><tr><td>Dia Oracle Factory</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/dia/MangroveDiaOracleFactory.sol">MangroveDiaOracleFactory.sol</a></td></tr><tr><td>Oracle Combiner</td><td>/</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/oracles/OracleCombinerFactory.sol">OracleCombinerFactory.sol</a></td></tr><tr><td>Mint helper (V1)</td><td>0xC0Ba6baF6899686bB601effE73bFC42404B93670</td><td><a href="https://github.com/mangrovedao/mangrove-vault/blob/main/src/mint-helper/MintHelperV1.sol">MintHelperV1.sol</a></td></tr></tbody></table>

#### Ghostbook

The ghostbook is a tool used in the frontend in order to combine Mangrove's order book liquidity with external liquidity

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>Ghost Book</td><td>/</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/MangroveGhostBook.sol">MangroveGhostBook.sol</a></td></tr><tr><td>UniV3 module</td><td>/</td><td><a href="https://github.com/mangrovedao/mgv-ghost-book/blob/main/src/modules/UniswapV3Swapper.sol">UniswapV3Swapper.sol</a></td></tr></tbody></table>
{% endtab %}

{% tab title="Blast (deprecated)" %}

#### Core contracts

These contracts are the immutable base of Mangrove both holding the book and markets, as well as exposing key view functions.

<table><thead><tr><th width="129.67578125">Contract</th><th width="417.78125">Address</th><th>Source</th></tr></thead><tbody><tr><td>Mangrove</td><td>0xb1a49c54192ea59b233200ea38ab56650dfb448c</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/core/Mangrove.sol">Mangrove.sol</a></td></tr><tr><td>MgvReader</td><td>0x26fd9643baf1f8a44b752b28f0d90aebd04ab3f8</td><td><a href="https://github.com/mangrovedao/mangrove-core/blob/develop/src/periphery/MgvReader.sol">MgvReader.sol</a></td></tr></tbody></table>

#### Oracles

Mangrove oracles are used in order to define the minimum order size. They often (statically or dinamically) are the price of the asset relative to the native token (gas token) times a constant. The oracle also gives the final mulitplier which is an (over)estimation of the chain's gas price.

<table><thead><tr><th width="146.734375">Contract</th><th width="408.75390625">Address</th><th>Source</th></tr></thead><tbody><tr><td>MgvPriceOracle</td><td>/ (static values)</td><td><a href="https://github.com/mangrovedao/mgv-oracle/blob/main/src/price/MgvPriceOracle.sol">MgvPriceOracle.sol</a></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

### NPM packages[​](https://docs.mangrove.exchange/developers/addresses/contract-addresses#npm-packages) <a href="#npm-packages" id="npm-packages"></a>

The addresses and API documentation corresponds to the following packages NPM packages published in [@mangrovedao](https://www.npmjs.com/org/mangrovedao):

* @mangrovedao/mgv


# Technical Architecture

Oxium is built on the infrastructure developed by Mangrove — a **battle-tested** and **audited** programmable order book protocol. This foundation provides a robust and flexible execution engine, well-suited for the demands of decentralized trading.

Oxium offers its own interface, positioning, and feature set, while relying on a proven underlying technology.


# Audits

Oxium is an open-source protocol based on Mangrove’s battle-tested technology, rigorously audited by the highly reputable firms ChainSecurity and Nethermind, ensuring the highest level of security and reliability.

Oxium has been thoroughly audited. You will find here official reports of the audits we passed:

### Oxium core​ <a href="#mangrove-core" id="mangrove-core"></a>

| Version                                                                                                                                                           | Auditor       | Date    |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------- |
| [V0](https://github.com/mangrovedao/audits/blob/main/core/v0/ChainSecurity_Mangrove_Association_\(ADDMA\)_Mangrove_audit-c7a5bd87cc411539606ff9082bb5c8a1.pdf)    | ChainSecurity | 03/2023 |
| [V1](https://github.com/mangrovedao/audits/blob/main/core/v1/ChainSecurity_Mangrove_Association_ADDMA_Mangrove_Core_audit_2-d3425cee36b3dad60bfac272af328fd4.pdf) | ChainSecurity | 11/2023 |

### Strategies

| Version                                                                                                                                                                                               | Auditor       | Date    |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------- |
| [V0](https://github.com/mangrovedao/audits/blob/main/strats/v0/ChainSecurity_Mangrove_Association_ADDMA_MangroveOrder_audit-7e289d0c705233f1d69d419d7689cab5.pdf)                                     | ChainSecurity | 03/2023 |
| [V1](https://github.com/mangrovedao/audits/blob/main/strats/v1/ChainSecurity_Mangrove_Association_Mangrove_Strategies_audit-caa8fc55eadb26bf40eead2b80af0c99.pdf)                                     | ChainSecurity | 11/2023 |
| [Amplifier & Routing](https://github.com/mangrovedao/audits/blob/main/strats/v1/2024-02-14-NM-0162-Nethermind_SmartRouter_MangroveOrder_MangroveAmplifier_audit-26ca97c4578d39c3ca4cb82ae7a0f374.pdf) | Nethermind    | 02/2024 |
| [UniV3 & Orbit Routers](https://github.com/mangrovedao/audits/blob/main/strats/v1/NM0208_FINAL_MANGROVE-684a6582cd4f3a18a25feeed05fb5482.pdf)                                                         | Nethermind    | 03/2024 |
| [Kandle Takara](https://drive.google.com/file/d/1CxoIHWUDODN8nE4OzWk8C3UBYqIOWIzA/view?usp=sharing)                                                                                                   | Sherlock      | 08/2025 |

### Kandel <a href="#kandel" id="kandel"></a>

| Version                                                                                                                                                           | Auditor       | Date    |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------- |
| [V0](https://github.com/mangrovedao/audits/blob/main/strats/v0/ChainSecurity_Mangrove_Association_ADDMA_Kandel_Strats_audit-db1b0f4516874f622d2a7f5bc7837f7c.pdf) | ChainSecurity | 04/2023 |

### Vaults

| Version                                                                                                    | Auditor     | Date    |
| ---------------------------------------------------------------------------------------------------------- | ----------- | ------- |
| [V0](https://github.com/mangrovedao/audits/blob/main/vaults/NM_0339_Mangrove_Vault_FINAL.pdf)              | Nethermind  | 10/2024 |
| [V2](https://drive.google.com/file/d/1CxoIHWUDODN8nE4OzWk8C3UBYqIOWIzA/view?usp=sharing)                   | Sherlock    | 08/2025 |
| [Chainlink Aggregator](https://drive.google.com/file/d/1ds488DKc2hAwMjeX1v1GcctjU24I6d5W/view?usp=sharing) | Three Sigma | 11/2025 |

Note:

* Oxium core and Strategies each have two distinct audits, which are complementary to each other.
* MangroveOrder is a peripheral contract for the Oxium core protocol which allows users to submit limit orders such as:
  * Good-til-cancelled (GTC, or GTT)
  * Fill-or-kill (FOK)
* Kandel is "buy low, sell high" market making strategy that leverages Oxium core protocol.


# Terms of Service

### **Disclaimer and Exclusion of Warranties**

Oxium is a decentralized Web3 service that provides technical tools exclusively for experienced users who are capable of understanding the risks inherent in blockchain technology, smart contracts, and decentralized financial services. Oxium, its founders, administrators, developers, and all partners and collaborators expressly disclaim any and all liability, whether direct or indirect, for any loss, damage, or harm, whether material or immaterial, resulting from the use of its services, access to its interfaces, or reliance on any information made available on its website or associated applications.

By using Oxium and any associated strategies, including the Kandel strategy, you acknowledge that you assume all risks and confirm that you have the necessary knowledge and understanding of blockchain technology, tokens, and the decentralized financial environment. You understand that Oxium does not act as an intermediary, agent, fiduciary, or custodian, and you alone are responsible for your use of the services and for the security of your private keys and wallets.

### **1. Legal Compliance and Jurisdiction**

It is solely your responsibility to ensure that your use of our services complies with the laws, regulations, and legal requirements applicable in your jurisdiction. Oxium is not intended for use, directly or indirectly, by any person or entity located in a jurisdiction where the use of blockchain-based services, decentralized exchanges (DEX), or decentralized financial (DeFi) products is prohibited or restricted. This includes, but is not limited to, any person or entity located in the United States of America (including all its territories and possessions), as well as any other jurisdiction or territory subject to economic or trade sanctions imposed by the U.S. Department of the Treasury’s Office of Foreign Assets Control (OFAC), the European Union, or any other relevant authority. Prohibited jurisdictions include, but are not limited to, North Korea, Iran, Syria, Sudan, Crimea, Donbass, Cuba, and any other country or region subject to similar embargoes or sanctions.

You must not use VPNs or other means to circumvent these restrictions. By using our services, you represent and warrant that:

* You are not a citizen or resident of, or located in, any prohibited or embargoed jurisdiction.
* You are not listed on any government sanctions list, such as the OFAC Specially Designated Nationals (SDN) List or any similar list maintained by a competent authority.
* You are not acting for the benefit of, or on behalf of, any person or entity in such jurisdictions or subject to such restrictions.
* You will not use our services to violate or circumvent any applicable laws, regulations, or economic and trade sanctions.

Oxium reserves the right, at any time and in its sole discretion, to restrict or block access to its services to any person or entity that it determines may violate applicable legal or regulatory requirements or that may pose a risk to the integrity or security of its services.

By using our services, you confirm that you are not subject to any legal or regulatory restrictions that would prohibit you from accessing or using the services provided by Oxium. You understand and agree that failure to comply with these requirements may result in the immediate suspension or termination of your access to the services, without notice or compensation.

### **2. Economic and Market Risks**

As a user of the Kandel strategy and other services provided by Oxium, you understand and accept that you are exposed to economic risks, including but not limited to:

* Partial or total loss of the tokens used.
* Partial or total loss of the value of the tokens used.
* Extreme market volatility.
* Insolvency of third-party platforms or companies.
* Lack of liquidity and the impossibility of reselling tokens on markets.

You are solely responsible for verifying that you are legally allowed to hold and use the crypto-assets you acquire, as well as for any taxes, duties, or assessments associated with your use of the services.

### **3. Impermanent Loss**

Kandel operates as a passive market-making strategy, generating profit from the spread between bids and asks. However, impermanent loss can occur in scenarios where market prices move significantly. For example, if the current price of an ETH/USDC pair rises and exceeds the maximum price range of your strategy, your remaining bids may no longer match the market price, stopping any profit generation and potentially leading to a partial or total loss.

### **4. Smart Contract and Technological Risks**

You acknowledge that even though the Kandel strategy has been implemented by an experienced team of researchers and developers and has been thoroughly audited by ChainSecurity, using Kandel and Oxium’s services entails technological and security risks, including but not limited to:

* Security errors or failures that allow and/or result in hacking, theft, or unauthorized access to user, third-party platform, or website/app data.
* The theft or loss of your external wallet’s private key or your access to third-party platforms.
* Risks inherent to the blockchains used for the strategy, including but not limited to successful attacks by hackers, criminal groups, organizations, or countries (such as denial-of-service attacks, Sybil attacks, spoofing, smurfing, malware attacks, consensus-based attacks, phishing, or other methods known or unknown).
* Lack of transparency in crypto asset management and markets.
* The irreversible nature of blockchain transactions; once executed, transactions cannot be reversed or refunded by Oxium, third parties, or blockchain validators.

### **5. Third-Party Services and Wallets**

Oxium is not responsible for any third-party tools, wallets, or services you use to access our services, including but not limited to wallet providers such as MetaMask, Coinbase Wallet, or Ledger. You are solely responsible for ensuring the security of your private keys and wallets, and any compromise of these may result in the loss of your assets.

Oxium also disclaims any responsibility for damages caused by third-party services or external links made available through the Oxium interface. Use of such services is at your own risk and may be governed by separate terms of use.

### **6. No Warranties and Limitation of Liability**

Oxium makes no representations or warranties, express or implied, regarding the reliability, accuracy, timeliness, security, or availability of its services. All services and content are provided on an “as is” and “as available” basis, without any representation or warranty of any kind. No information, advice, or data obtained through Oxium or the Kandel strategy shall constitute a warranty or binding commitment of Oxium, nor shall it establish any contractual, tort, or other legal liability.

Oxium shall not, under any circumstances, be liable for any losses, damages, or disputes arising from the use of, or inability to use, its services or the Kandel strategy, whether in contract, tort, strict liability, or any other legal theory. This exclusion of liability includes, but is not limited to, direct, indirect, incidental, consequential, punitive, special, or exemplary damages, even if Oxium has been advised of the possibility of such damages.

### **7. Intellectual Property**

All rights, titles, and interests in and to the services and all related content, code, data, and materials remain the exclusive property of Oxium or its licensors. You may not reproduce, imitate, or use any Oxium intellectual property without prior written authorization.

### **8. Modifications and Updates**

Oxium reserves the right to modify, suspend, or discontinue any part of its services at any time, for any reason, without notice and without liability. It is your responsibility to review the Terms of Service periodically to remain informed of any updates.

### **9. Acknowledgment and Acceptance of Risks**

By accessing or using our services and the Kandel strategy, you confirm that you have read, understood, and accepted the entirety of these Terms of Service, including the associated risks and limitations. You agree that your sole and exclusive remedy for any dispute with Oxium is to discontinue use of our services.


# Privacy policy

### Privacy Policy – Oxium

#### 1. Introduction

Oxium is a decentralized finance (DeFi) protocol that respects your privacy and is committed to protecting your personal data. This Privacy Policy describes how we collect, use, store, and protect your information when you use our services, websites, and applications (collectively, the “Services”).

***

#### 2. Data We Collect

**Public Blockchain Data**

When you connect your non-custodial wallet to our Services, we collect and log your publicly-available blockchain address. These addresses are public data, not created or assigned by us or any central authority, and are not personally identifying on their own.

**Technical Information**

We may collect technical information such as browser type, operating system, referring and exit pages, browser or device language, and similar data. This information helps us improve the user experience and detect any illicit activity.

**Tracking Technologies**

We and our third-party service providers may access and collect information from technologies such as cookies, localStorage, mobile device identifiers, web beacons, and other similar technologies to provide and personalize the Services and their features for you across sessions.

**Direct Communications**

When you contact us via email, social media, or other support channels like Twitter, Discord, or Telegram, or participate in surveys or questionnaires, we receive the information and communications you share. We do not attempt to link this information to your wallet address, IP address, or other personal details.

**Job Applications**

If you apply for a position with us, we collect all information you provide through our application form, including your name, email address, phone number, professional and immigration status, and any other documents such as your CV, cover letter, or freeform text you include.

***

#### 3. Use of Data

The information we collect is used in accordance with our Terms of Use and legal requirements. We may use this information to:

* Provide, maintain, personalize, and improve our Services and their features.
* Provide user support and respond to your requests regarding the Services.
* Protect against, investigate, and stop any fraudulent, unauthorized, or illegal activity.
* Comply with our legal and regulatory obligations.
* Process your job application and contact you throughout the recruitment process.

***

#### 4. Data Sharing

We do not share your information with third parties for marketing purposes. However, we may share or disclose the data we collect in the following situations:

* With staff or members of our organization.
* With regulators, government entities, and law enforcement to comply with our legal obligations.
* With service providers and vendors who may assist us in providing, delivering, and improving the Services (e.g., hosting provider, mailing provider, external recruitment platforms, etc.).

***

#### 5. Your Rights

In accordance with the General Data Protection Regulation (GDPR), you have the following rights regarding your personal data:

* Right to be informed: you have the right to be informed about how your personal data is collected and used.
* Right of access: you can request access to your personal data that we hold.
* Right to rectification: you can request the correction of inaccurate or incomplete personal data.
* Right to erasure: you can request the deletion of your personal data.
* Right to restrict processing: you can request the restriction of processing of your personal data in certain circumstances.
* Right to data portability: you can request to receive your personal data in a structured, commonly used, and machine-readable format.
* Right to object: you can object to the processing of your personal data in certain circumstances.
* Right to withdraw consent: where processing is based on your consent, you can withdraw it at any time.
* Right to file a complaint: you have the right to lodge a complaint with the competent data protection authority.

To exercise these rights, please contact us at: \[your contact email address].

***

#### 6. Data Retention

We retain your personal data only as long as necessary for the purposes for which it was collected, to provide our Services, resolve disputes, enforce our agreements, and comply with legal obligations. This period may vary depending on the nature of the data and the reasons for collecting it, considering the purposes described in this Privacy Policy and our own legal and regulatory requirements.

***

#### 7. Security

We take reasonable steps to protect your personal data from misuse, loss, unauthorized access, modification, or disclosure, including implementing appropriate security measures. Security measures in place will be reviewed from time to time in line with legal and technical developments. However, we cannot guarantee that such misuse, loss, unauthorized access, modification, or disclosure will not occur. You are responsible for all your activities on the Services, including the security of your blockchain network addresses, cryptocurrency wallets, and their cryptographic keys.

***

#### 8. Links

Our Services may contain links to other websites and resources provided by third parties. This Privacy Policy applies only to our Services. Accessing those third-party websites or resources requires you to leave our Services. We do not control those third-party sites or any of the content contained therein, and you agree that we are in no circumstances responsible or liable for any of those third-party sites, including, without limitation, their content, policies, failures, promotions, products, services, or actions and/or any damages, losses, failures, or problems caused by, related to, or arising from those sites. We encourage you to review all policies, rules, terms, and regulations, including the privacy policies, of each site you visit.

***

#### 9. Changes to the Policy

We may modify this Privacy Policy at any time, particularly to comply with any regulatory, case law, editorial, or technical changes. These modifications will apply as of the effective date of the modified version.

If we change this Privacy Policy, we will take steps to notify all users via a notice on our Site and will post the amended Privacy Policy on the Site. Please regularly review the latest version of this Privacy Policy.


