# Makers

## Posting a New Offer

Most offers are posted by maker contracts, which source liquidity on demand when Mangrove calls them.

* Smart offers: offers posted via maker contracts.
* On-the-fly offers: offers posted directly by EOAs (Externally Owned Accounts).

There are two ways to post offers and specify an offer's price:

* `newOfferByTick` - price defined by a tick
* `newOfferByVolume` - price defined by the ratio `wants/gives`.

`*ByVolume` is a convenience wrapper around \*`ByTick`. Both functions return the same output and behave identically.&#x20;

```solidity
 function newOfferByTick(
    OLKey memory olKey,
    Tick tick, 
    uint gives, 
    uint gasreq, 
    uint gasprice
) external payable returns (uint offerId);

function newOfferByVolume(
    OLKey memory olKey,
    uint wants,
    uint gives,
    uint gasreq,
    uint gasprice
) external payable returns (uint offerId);
```

Both functions are payable. A non-zero `msg.value` will credit the maker's Mangrove balance before locking the offer's provision.

### Inputs

* `olKey`: identifies the [offer list](https://docs.mangrove.exchange/dev/protocol/the-order-book#offer-list-identification)
  * `outbound_tkn`: token sent by the offer
  * `inbound_tkn`: token received by the offer
  * `tickSpacing`: spacing between valid ticks (see [Ticks, ratios, and prices](https://docs.mangrove.exchange/dev/protocol/technical-references/ticks-ratios-and-prices))
* `gives`: amount of `outbound_tkn` promised by the offer.
  * **Must** be > 0 and fit in 127 bits.
  * **Must** meet offer list [density](https://docs.mangrove.exchange/dev/quick-links/glossary#density) and `gasreq` constraints.
* `gasreq`: gas made available to the offer execution logic.
  * &#x20;**Must** be ≤ [`gasmax`](https://docs.mangrove.exchange/dev/quick-links/glossary#gaslimit) and fit in 24 bits&#x20;
  * &#x20;Should cover [`makerExecute`](https://docs.mangrove.exchange/dev/protocol/technical-references/maker-contract#trade-execution) and [`makerPosthook`](https://docs.mangrove.exchange/dev/protocol/technical-references/maker-contract#trade-posthook) calls&#x20;
  * **Must** be compatible with `gives` and the offer list's [density](https://old.docs.mangrove.exchange/developers/terms/density) parameter. (See [gasreq](https://docs.mangrove.exchange/dev/quick-links/glossary#gasreq))
* `gasprice`: gas price override in Mwei/gas used to compute the order [provision](https://docs.mangrove.exchange/dev/quick-links/glossary#provision) (see [offer bounties](https://docs.mangrove.exchange/dev/protocol/technical-references/makers/offer-provisions)).&#x20;
  * Lower values than Mangrove's current [gasprice](https://docs.mangrove.exchange/dev/quick-links/glossary#gasprice) are ignored (thus 0 means "use Mangrove's current gasprice").&#x20;
  * **Must** fit in 26 bits.

**`newOfferByTick(olKey, tick, gives, gasreq, gasprice)`**[**​**](https://old.docs.mangrove.exchange/developers/protocol/technical-references/reactive-offer/#newofferbytickolkey-tick-gives-gasreq-gasprice)

* `tick`: the desired "price" tick.

  The actual tick is rounder up to the nearest valid tick satisfying\
  `offerTick % tickSpacing == 0`.

**`newOfferByVolume(olKey, wants, gives, gasreq, gasprice)`**[**​**](https://old.docs.mangrove.exchange/developers/protocol/technical-references/reactive-offer/#newofferbyvolumeolkey-wants-gives-gasreq-gasprice)

* `wants`: the amount of inbound tokens requested by the offer.
* **Must** fit in 127 bits and be strictly positive.
* The ratio `wants/gives` (rounded down) specifies the desired "price" ratio and thus tick.

### Outputs

* `offerId` the [id](https://docs.mangrove.exchange/dev/quick-links/glossary#offer-id) of the newly created offer.
* &#x20;Note that offer ids are scoped to [offer lists](https://docs.mangrove.exchange/dev/protocol/technical-references/the-order-book), so many offers can share the same id if they belong to different offer lists.

### Provisioning

Each offer must be **provisioned** in native tokens.\
If an offer fails, a portion of its provision compensates the taker for gas spent.

Ensure your maker contract holds enough provision before posting an offer.\
You can fund it by sending native tokens to Mangrove; the balance is stored and reused automatically.

### Offer Execution

If the offer’s account is a **contract**, it must implement the `IMaker` interface:

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

Otherwise, Mangrove will revert on execution.

The offer account must also:

* Maintain a sufficient ERC20 allowance for `outbound_tkn` (used via `transferFrom`).
* Satisfy density requirements (tokens per gas spent).

### Example

```solidity
import {IMangrove} from "@mgv/src/IMangrove.sol";
import "@mgv/src/core/MgvLib.sol";

// context of the call

// IMangrove mgv = IMangrove(payable(<address of Mangrove>));
// Mangrove contract
IMangrove mgv = IMangrove(payable(mgv));

// OLKey olKey = OLKey(<address of outbound token>, <address of inbound token>, <tick spacing>);
// struct containing outbound_tkn, inbound_tkn and tickSpacing
OLKey memory olKey = OLKey(address(base), address(quote), 1);

// Tick tick = TickLib.tickFromRatio(mantissa,exponent);
// ratios are represented as a (mantissa,exponent) pair which represents the number `mantissa * 2**-exponent`
// calculates the tick from a desired 1.25 ratio (1.25 = 20 * 2^(-4))
Tick tick = TickLib.tickFromRatio(20, 4);

// creates an offer at tick
mgv.newOfferByTick(olKey, tick, 1 ether, 10_000, 0);

// creates an offer at ⌈wants/tick⌉
mgv.newOfferByVolume(olKey, 1 ether, 1 ether, 10_000, 0);
```

### Events

| Event          | Description                                                                     |
| -------------- | ------------------------------------------------------------------------------- |
| **OfferWrite** | Emitted when a new offer is written to the order book.                          |
| **DebitWei**   | Emitted when the maker’s Mangrove balance is debited to cover offer provision.  |
| **CreditWei**  | Emitted when the maker’s Mangrove balance is credited (e.g., from `msg.value`). |

#### **Event definitions**

```solidity
// logging new offer's data 
event OfferWrite(
  bytes32 indexed olKeyHash,
  address indexed maker, // account that created the offer, will be called upon execution
  int tick,
  uint gives,
  uint gasprice, // gasprice that was used to compute the offer bounty
  uint gasreq,
  uint id // id of the new offer
);

// `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); 
```

#### Gatekeeping and Errors

| Error                            | Meaning                            |
| -------------------------------- | ---------------------------------- |
| `mgv/dead`                       | Mangrove contract is terminated    |
| `mgv/inactive`                   | Target market is inactive          |
| `mgv/offerIdOverflow`            | Max number of offers (2²⁴) reached |
| `mgv/writeOffer/gasprice/tooBig` | Gas price too large                |
| `mgv/writeOffer/gives/tooBig`    | Offer volume too large             |
| `mgv/writeOffer/gasreq/tooHigh`  | Gasreq above gasmax                |
| `mgv/writeOffer/gives/tooLow`    | Gives must be > 0                  |
| `mgv/writeOffer/density/tooLow`  | Density too low                    |
| `mgv/writeOffer/tick/outOfRange` | Tick invalid                       |
| `mgv/insufficientProvision`      | Maker provision insufficient       |

## Updating an Offer

Offers can be updated using the same two price-specification methods:

* `updateOfferByTick`
* `updateOfferByVolume`

`updateOfferByVolume` converts the volumes into a tick internally. Both versions are payable and can top up the maker’s balance via `msg.value`.

```solidity
function updateOfferByTick( 
    OLKey memory olKey,
    Tick tick,
    uint gives,
    uint gasreq,
    uint gasprice,
    uint offerId
) external payable;

function updateOfferByVolume( 
    OLKey memory olKey,
    uint wants,
    uint gives,
    uint gasreq,
    uint gasprice,
    uint offerId
) external payable;
```

### Inputs

* **offerId** — ID of the offer to update
* All other parameters are identical to `newOfferByTick` and `newOfferByVolume`      (see above)

### Output

* None

### Offer Updater

Only the creator of the offer (`msg.sender`) can update it.\
Unauthorized calls revert with `mgv/updateOffer/unauthorized`.

### Example

```solidity
import {IMangrove} from "@mgv/src/IMangrove.sol";
import "@mgv/src/core/MgvLib.sol";

// continuing from the previous example for the creation of new offers
// context of the call:
    // mgv: address of Mangrove's deployment typed as IMangrove
    // olKey struct containing outbound_tkn, inbound_tkn and tickSpacing

// creates an offer at `tick` and store its ID in ofrId_1
uint ofrId_1 = mgv.newOfferByTick(olKey, tick, 1 ether, 10_000, 0);

// getting packed (outTkn, inbTkn, tickSpacing) offer list data
Offer offer_1 = mgv.offers(olKey, ofrId_1);
OfferDetail detail_1 = mgv.offerDetails(olKey, ofrId_1);

// update the offer with the "ByTick" version
mgv.updateOfferByTick(
  olKey,
  tick,
  offer_1.gives() * 9 / 10, // decrease what offer gives by 10%
  detail_1.gasreq(), // keep offer's current gasreq 
  detail_1.gasprice(), // keep offer's current gasprice
  ofrId_1 // id of the offer to be updated 
);

// retrieves the amount of wants from the tick and gives
uint wants = TickLib.inboundFromOutbound(tick, offer_1.gives());

// update the offer with the "ByVolume" version
mgv.updateOfferByVolume(
  olKey,
  wants, // keep what the offer wants
  offer_1.gives() * 12 / 10, // increase what offer gives by 20%
  detail_1.gasreq(), // keep offer's current gasreq 
  detail_1.gasprice(), // keep offer's current gasprice
  ofrId_1 // id of the offer to be updated 
);
```

#### Events

| Event          | Description                                   |
| -------------- | --------------------------------------------- |
| **OfferWrite** | Emitted when an offer is updated.             |
| **DebitWei**   | Maker debited if provision needs to increase. |
| **CreditWei**  | Maker credited if provision decreased.        |

```solidity
event OfferWrite(
  bytes32 indexed olKeyHash,
  address indexed maker, // account that created the offer, will be called upon execution
  int tick,
  uint gives,
  uint gasprice, // gasprice that was used to compute the offer bounty
  uint gasreq,
  uint id // id of the new offer
);
// 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);
```

### Reusing Offers

Executed or [retracted](#retracting-an-offer) offers are removed from the [offer list](https://docs.mangrove.exchange/dev/protocol/technical-references/the-order-book) but can be updated and reinserted.\
Updating existing offers is significantly cheaper than creating new ones.

#### Gatekeeping and Errors

| Error                           | Meaning                    |
| ------------------------------- | -------------------------- |
| `mgv/dead`                      | Mangrove is terminated     |
| `mgv/inactive`                  | Offer list is inactive     |
| `mgv/writeOffer/gives/tooLow`   | Gives ≤ 0                  |
| `mgv/writeOffer/gasreq/tooHigh` | Gasreq above limit         |
| `mgv/writeOffer/density/tooLow` | Density constraint not met |
| `mgv/updateOffer/unauthorized`  | Caller not offer owner     |
| `mgv/insufficientProvision`     | Provision insufficient     |

## Retracting an offer

An offer can be withdrawn from the order book using `retractOffer` .

```solidity
function retractOffer(
  OLKey memory olKey,
  uint offerId,
  bool deprovision
) external returns (uint provision);
```

### Inputs

* **olKey** — identifies the offer list
* **offerId** — ID of the offer to retract
* **deprovision** — if true, releases the offer’s provision (in wei)

### Output

* **provision** — amount of native tokens released (in wei)

### Example

```solidity
import {IMangrove} from "@mgv/src/IMangrove.sol";

// continuing from the previous example for the creation of new offers
// context of the call:
    // mgv: address of Mangrove's deployment typed as IMangrove
    // olKey struct containing outbound_tkn, inbound_tkn and tickSpacing
    // ofrId_1: offer identifier of the offer created in the examples for new offer creation

// retracting offer with ID = ofrId_1
mgv.retractOffer(
  olKey,
  ofrId_1, // id of the offer to be retracted
  false // no deprovision of the offer, saves gas if one wishes to repost the offer later
);
```

If you choose to deprovision, you can later withdraw the funds using:

```solidity
mgv.withdraw(amount);
```

### Events

| Event            | Description                                           |
| ---------------- | ----------------------------------------------------- |
| **OfferRetract** | Emitted when an offer is removed from the book.       |
| **Credit**       | Emitted when provision is released back to the maker. |

```solidity
// emitted on all successful retractions
event OfferRetract(
  bytes32 indexed olKeyHash,
  address indexed maker,
  uint id, // the id of the offer that has been removed from the offer list
  bool deprovision
);

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

#### Authorization

Only the maker contract that created the offer may call `retractOffer`.\
Unauthorized calls revert with `mgv/retractOffer/unauthorized`.<br>
