Skip to main content

Cleaning offers

Offers on Mangrove may fail during a market order. When they do, the taker is compensated for the gas wasted on making the offer fail in the form of a %%bounty|bounty%% in native tokens paid from the failing offer's %%provision|provision%% which the %%offer owner|offer-owner%% deposited with Mangrove when posting the offer. Refer to Offer provisions for details on how provisions and bounties work and are calculated.

From the taker's perspective, failing offers are a nuisance: They consume gas when running limit orders and they pollute the price and depth information of the market. It's important to note, that failing offers are only a nuisance, not a risk: Users are compensated for gas spent on making the offer fail and the limit avg. price will never be exceeded.

Therefore Mangrove provides a facility for removing specific failing offers and receiving the bounty without running a market order. This is called Offer Cleaning.

info

You can read more about the role of cleaning here.

Mangrove's cleanByImpersonation function allows anyone to clean a failing offer, by providing the execution parameters that will make it fail. The function will execute the specified offers, including token transfers, and (1) reward the cleaner and remove the offer from the book if the offer fails or (2) revert the offer execution if it succeeds and keep the offer in the book; in both cases, all token transfers are reverted.

Since this cleaning involves actual token transfers (though they will be reverted) Mangrove requires the caller to specify a taker account from which the inbound tokens will be transferred. In effect, this taker account will be impersonated during cleaning, hence *ByImpersonation.

The taker must of course have approved Mangrove for transferring the inbound token on their behalf. And cleaners are free to specify any account, including accounts they do not control.

Impersonated takers are unaffected

The takers that are impersonated during cleaning are unaffected: All token transfers made inside cleanByImpersonation will be reverted.

cleanByImpersonation(olKey, targets, taker)​

function cleanByImpersonation(
OLKey memory olKey,
MgvLib.CleanTarget[] calldata targets,
address taker
) external returns (uint successes, uint bounty);

struct CleanTarget {
uint offerId;
Tick tick;
uint gasreq;
uint takerWants;
}

Prerequisites​

The prerequisites and steps needed to use the Mangrove.cleanByImpersonation function are:

  • taker must have approved Mangrove for spending inbound_tkn on the offer list you want to clean.
  • taker must have sufficient inbound_tkn funds for the execute arguments

Inputs​

  • olKey: identifies the offer list and consists of:
    • outbound_tkn: address of the outbound token (that the taker will buy).
    • inbound_tkn: address of the inbound token (that the taker will spend).
    • tickSpacing: specifies the space between allowed ticks (see Ticks, ratios, and prices for details)
  • targets: an array of where each CleanTarget identifies an offer to clean and the execution parameters that will make it fail:
    • offerId: the ID of the offer to clean.
    • tick: the offer's expected tick. If this doesn't match when the tx is executed, cleaning of the offer will not be attempted to avoid wasting gas since the cleaning assumptions have changed.
    • gasreq: the offer's expected gasreq. If this is lower than the offer's actual gasreq when the tx is executed, cleaning of the offer will not be attempted to avoid wasting gas since the cleaning assumptions have changed.
    • takerWants: the amount to request from the offer.
  • taker: the address of the taker to impersonate.
Protection against malicious offer updates

Offers can be updated, so if targets was just an array of offerIds, there would be no way to protect against a malicious offer update mined right before a clean. 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 gasreq to type(uint).max, and
  • Set tick to maxTick.

Outputs​

  • successes is the number of successfully cleaned offers.
  • bounty is the total bounty received and transferred to msg.sender.

Example​

Consider the offers on this DAI-WETH offer list and let's construct a cleanByImpersonation call.

TickRatio (WETH/DAI)Offer IDGives (DAI)Gas required
-798150.000341977925.26250,000
-798150.0003419177916.47270,000
-797480.000344242871.76300,000

Let's say we've detected that offers 77 and 42 will fail. We can now construct the following targets array:

  • targets[0] = [77, -79815, 250_000, 925.26]
  • targets[1] = [42, -79748, 300_000, 871.76].

We also know the address of a taker who has approved Mangrove to transfer a sufficient amount of WETH on their behalf, such that it could pay for executing the most expensive of the offers. Remember, the transfers will be reverted after each cleaning, so the taker need only have sufficient funds for the most expensive offer, not the total of the offers cleaned.

Putting it together, the call to cleanByImpersonation would look like this (assuming mgv is ):

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

OLKey memory olkey = OLKey(<address of DAI>, <address of WETH>, 1);

MgvLib.CleanTarget[] memory targets = new MgvLib.CleanTarget[](2);
targets[0] = MgvLib.CleanTarget(77, -79815, 250_000, 0.3163);
targets[1] = MgvLib.CleanTarget(42, -79748, 300,000, 0.3000);

mgv.cleanByImpersonation(olKey, targets, taker);