Mangrove
Mangrove
Mangrove
  • START HERE
    • What is Mangrove?
      • Smart offers
      • Bounty
      • Makers, Takers, Keepers
        • Makers
        • Takers
        • Keepers
    • Why Mangrove?
    • Who is the Mangrove dApp for?
    • Audits
    • FAQ
    • Glossary
    • Terms & Conditions
  • Strategies
    • Kandel
      • What is Kandel?
      • How does Kandel Work?
        • Step-by-step visual explanation
        • Parameters
        • Choosing Kandel parameters
        • Published Liquidity
        • More on failing offers
      • Potential risks
  • DAPP GUIDE
    • Swap
    • Trade
      • How to make an order
        • Market Order
        • Limit Order
        • Amplified Order
        • More on order types
      • Approvals
      • Minimum Volume
      • How to Track and Manage Orders
    • Earn
    • Rewards
    • Bridge
    • Wrap
  • MGV INCENTIVES
    • Fee Rewards
      • How the programs Work
      • Current programs
    • Vault LP programs
      • How the Programs Work
      • Current programs
      • Earning rewards
      • Example
      • Previous programs
    • MS2 Program (closed)
      • How Rewards Are Calculated
        • Reward Rate ρ
        • Takers Rewards
        • Adjusted Volume for Makers
        • How to Maximize Your Score
      • MGV Token Allocation per User Type
        • Specific Allocation for Kandel users and vault managers
        • Community Contributors
        • Incentives with a custom strategy
      • Epochs and Updates
    • MS1 Program (closed)
      • Intro
      • Trading Points
      • Boost
      • Referral Points
      • Community Points
      • Parameters
      • Technical Insights
      • MS1 FAQ
      • Disclaimer
  • Governance
    • General Governance
      • Key Stakeholders
        • Token Holders
          • Builders
        • Builders
        • Pods
      • Guardians
      • Governance Process
        • Initial Discussions
        • Proposals
        • Voting
        • Execution
    • Councils
      • Responsibilities
      • Elections
      • Budgets
    • Guides and resources
      • How to vote on a governance proposal
      • How to delegate my voting power
      • How to access the Builders’ directory
      • How to access the Pods’ directory
      • Snapshot configuration & membership
      • Links and adresses
  • QUICK LINKS
    • Whitepaper
    • Website
    • Feedback
    • Blog
    • GitHub
    • X
    • Discord
    • Telegram
    • Deployment adresses
Powered by GitBook
On this page
  • Offer Logic
  • Offer post-hook
  1. Contracts
  2. Technical references
  3. Taking and making offers
  4. Creating & Updating offers

Executing offers

How to write offer execution logic

Last updated 2 years ago

Offer Logic

The logic associated with an offer must be implemented through a makerExecute callback function. (See for SingleOrder type).

function makerExecute(MgvLib.SingleOrder calldata order)
external returns (bytes32 makerData);
MakerContract-0.sol
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";
    }
}
    
    

Inputs

  • order is a containing a recap of the 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.

Outputs

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

Security concerns

Your contract should ensure that only Mangrove can call makerExecute to avoid unwanted state change.

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 .

Better fail early!

The taken from the offer maker's provision is to the gas consumed by makerExecute. To minimize costs, try to fail as early as possible.

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.

Offer post-hook

function makerPosthook(
    MgvLib.SingleOrder calldata order,
    MgvLib.OrderResult calldata result
  ) external;
MakerContract-1.sol
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
            );
        }
    }

Inputs

  • order same as in makerExecute.

    • the return value of makerExecute

Outputs

None.

Security concerns

Your contract should ensure that only Mangrove can call makerPosthook to avoid unwanted state change.

Gas management

MakerPosthook is given the executed offer's gasreq minus the gas used by makerExecute.

Updating offers during posthook

Reverting

Reverting during makerPosthook does not renege on trade, which is settled at the end of makerExecute.

The logic associated with an offer may include a makerPosthook callback function. Its intended use is to update offers in the containing the that was just executed.

result A containing:

additional data sent by Mangrove, more info .

During the execution of a posthook, the executed offer's list is unlocked. This feature can be used to repost an (even the one that was just executed), possibly at a different price.

offer list
offer
offer
data structure
struct
available here
data structures
taker order
bounty
bounty
proportional