Takers

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.

 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

    • outbound_tkn: token sent by the offer

    • inbound_tkn: token received by the offer

    • tickSpacing: spacing between valid ticks (see 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 and gasreq constraints.

  • gasreq: gas made available to the offer execution logic.

  • gasprice: gas price override in Mwei/gas used to compute the order provision (see offer bounties).

    • Lower values than Mangrove's current gasprice are ignored (thus 0 means "use Mangrove's current gasprice").

    • Must fit in 26 bits.

newOfferByTick(olKey, 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)

  • 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 of the newly created offer.

  • Note that offer ids are scoped to offer lists, 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:

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

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

// 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.

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

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.

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 offers are removed from the offer list 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 .

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

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:

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.

// 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.

Last updated