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

Creating & Updating offers

Posting a new offer

New offers will mostly be posted by maker contracts able to source liquidity when asked by Mangrove.

Offers posted via maker contracts are called %%smart offers|smart-offer%% - as opposed to %%on-the-fly offers|on-the-fly-offer%% made from EOA's.

Offers on Mangrove can be posted in two ways which differ in how the "price" (%%ratio|ratio%%) is specified:

  • newOfferByTick: The "price" is specified as a tick.

  • newOfferByVolume: The "price" is specified as the ratio between two volumes, wants/gives.

The *ByVolume variant is a convenience wrapper for the *ByTick variant: The provided volumes are converted to a corresponding tick.

The output from the two functions is the same.

:::info

Both functions are payable and can be used to credit the maker contract's balance on Mangrove on the fly. A non-zero msg.value will allow Mangrove to credit the maker's balance prior to locking the %%provision|provision%% of the newly posted offer.

 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);
// 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
"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/tooBig"
"mgv/writeOffer/gives/tooBig"

// Invalid values
"mgv/writeOffer/gasreq/tooHigh" // gasreq above gasmax
"mgv/writeOffer/gives/tooLow"   // gives should be greater than 0
"mgv/writeOffer/density/tooLow" // wants / (gasreq + overhead) below density
"mgv/writeOffer/tick/outOfRange"

// Insufficient provision
"mgv/insufficientProvision"     // provision of `msg.sender` should cover offer bounty
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);

Inputs

The two function only differ in one input. They both functions take these inputs:

    • outbound_tkn: address of the outbound token (that the offer will send).

    • inbound_tkn: address of the inbound token (that the offer will receive).

  • tick: the desired "price" tick of the offer. The actual tick of the offer will be the smallest tick offerTick > tick that satisfies offerTick % tickSpacing == 0.

  • 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

Provisioning :

Since offers can fail, Mangrove requires each offer to be %%provisioned|provision%% in native token. 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 before calling newOffer*, otherwise the call will fail. The easiest way to go is to send a comfortable amount of native token to Mangrove from your offer-posting contract. Mangrove will remember your balance and use it when necessary.

Offer execution :

  • If the offer account is a contract, it should implement the IMaker interface. At the very least, it must have a function with signature makerExecute(MgvLib.SingleOrder calldata order) or it will systematically revert when called by Mangrove.

  • gives and gasreq are subject to 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.

Updating an existing offer

As for newOffer, offers on Mangrove can be updated in two ways which differ in how the "price" (%%ratio|ratio%%) is specified:

  • updateOfferByTick: The "price" is specified as a tick.

  • updateOfferByVolume: The "price" is specified as the ratio between two volumes, wants/gives.

The *ByVolume variant is a convenience wrapper for the *ByTick variant: The provided volumes are converted to a corresponding tick.

The output from the two functions is the same.

Info :

Both functions are payable and can be used to credit the maker contract's balance on Mangrove on the fly. A non-zero msg.value will allow Mangrove to credit the maker's balance prior to locking the %%provision|provision%% of the updated offer.

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;
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);
// 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/tooBig"
"mgv/writeOffer/gives/tooBig"

// Invalid values
"mgv/writeOffer/gasreq/tooHigh" // gasreq above gasmax
"mgv/writeOffer/gives/tooLow"   // gives should be greater than 0
"mgv/writeOffer/density/tooLow" // wants / (gasreq + overhead) below density
"mgv/writeOffer/tick/outOfRange"

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

Inputs

  • offerId is the %%offer id|offer-id%% of the offer to be updated.

  • All other parameters are the same as newOfferByTick and newOfferByVolume - see above.

Outputs

None.

Offer updater :

An offer can only be updated if msg.sender is the account that created the offer.

Reusing offers :

Retracting an offer

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

function retractOffer(
  OLKey memory olKey,
  uint offerId,
  bool deprovision
) external returns (uint provision);
// 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
); 
"mgv/retractOffer/unauthorized" // only the offer's Maker Contract may call.
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
);
...

Inputs

Outputs

  • provision: amount of native token deprovisioned for the offer (in wei).

Note : The withdraw(amount) function can be used to withdraw the funds after deprovisioning.

PreviousDelegationNextMaker contract

Last updated 28 days ago

olKey: identifies the and consists of:

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

gives: the amount of outbound tokens promised by the offer. Must fit in 127 bits and be strictly positive. Must provide enough volume w.r.t. to gasreq and offer list's parameter.

gasreq: the amount of gas that will be given to the offer's account. Must fit in 24 bits and be lower than . Should be sufficient to cover all calls to the maker contract's () and ). Must be compatible with the offered volume gives and the offer list's parameter. (See also .)

gasprice: gas price override in Mwei/gas used to compute the order (see also ). Any value lower than Mangrove's current will be ignored (thus 0 means "use Mangrove's current "). Must fit in 26 bits.

newOfferByTick(olKey, tick, gives, gasreq, gasprice)

newOfferByVolume(olKey, wants, gives, gasreq, gasprice)

offerId the of the newly created offer. Note that offer ids are scoped to , so many offers can share the same id if they belong to different offer lists.

After being executed or , an offer is moved out of the . It can still be updated and reinserted in the offer list. It is generally recommended to update offers instead of creating new ones, as it costs much less gas.

olKey: identifies the offer list, see details .

offerId: is the of the offer to be retracted.

deprovision: if true, will free the offer's so that you can them. Otherwise, will leave the provision in the offer.

offer list
Ticks, ratios, and prices
density
gasmax
offer logic
makerExecute
makerPosthook
density
gasreq
provision
offer bounties
gasprice
gasprice
​
​
id
offer lists
retracted
offer list
above
id
provision
withdraw