# Safe offer logic guidelines

### Gatekeeping[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#gatekeeping) <a href="#gatekeeping" id="gatekeeping"></a>

#### Offer logic should only be called by Mangrove[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#offer-logic-should-only-be-called-by-mangrove) <a href="#offer-logic-should-only-be-called-by-mangrove" id="offer-logic-should-only-be-called-by-mangrove"></a>

External functions of an [offer logic](https://docs.mangrove.exchange/dev/quick-links/glossary#offer-logic), `makerExecute` and `makerPosthook`, should only be callable if `msg.sender` is Mangrove. [Maker contracts](https://docs.mangrove.exchange/dev/quick-links/glossary#maker-contract) implemented with the strat library take care of this by construction.

#### Public functions that are called by offer logic[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#public-functions-that-are-called-by-offer-logic) <a href="#public-functions-that-are-called-by-offer-logic" id="public-functions-that-are-called-by-offer-logic"></a>

It is sometimes convenient to define public function that can also be called internally during offer logic's execution. If such function needs to be restricted to privileged access, one cannot simply use `require(msg.sender == admin_address)` as `msg.sender` will be Mangrove when the function is called internally by the offer logic. Using a guard of the form `require(msg.sender == admin_address || msg.sender == mangrove_address)` will work though (notice that internal call preserves `msg.sender` of `makerExecute`).

### Token amounts[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#token-amounts) <a href="#token-amounts" id="token-amounts"></a>

[Outbound](https://docs.mangrove.exchange/dev/quick-links/glossary#outbound) and [inbound](https://docs.mangrove.exchange/dev/quick-links/glossary#inbound) tokens may have different decimals. Mangrove always use raw amounts, so offer do not have directly a price but a [wants](https://docs.mangrove.exchange/dev/quick-links/glossary#wants) and a [gives](https://docs.mangrove.exchange/dev/quick-links/glossary#gives) both expressed in raw token amounts.

### Which part of your [Maker contract](https://docs.mangrove.exchange/dev/quick-links/glossary#maker-contract) should not be in the [offer logic](https://docs.mangrove.exchange/dev/quick-links/glossary#offer-logic)?[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#which-part-of-your-maker-contract-should-not-be-in-the-offer-logic) <a href="#which-part-of-your-maker-contract-should-not-be-in-the-offer-logic" id="which-part-of-your-maker-contract-should-not-be-in-the-offer-logic"></a>

Functions in offer logic are automatically executed by Mangrove, who is then `msg.sender`. Beware that taker is not necessarily `tx.origin`, as a contract could be acting as a taker. Importantly, make sure that your logic is not exploitable by context manipulation, which could force your offer to fail.

### How to factor your offer logic between [`makerExecute`](https://docs.mangrove.exchange/dev/quick-links/glossary#makerexecute) and [`makerPosthook`](https://docs.mangrove.exchange/dev/quick-links/glossary#makerposthook).[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#how-to-factor-your-offer-logic-between-makerexecute-and-makerposthook) <a href="#how-to-factor-your-offer-logic-between-makerexecute-and-makerposthook" id="how-to-factor-your-offer-logic-between-makerexecute-and-makerposthook"></a>

**Must** be in maker execute:

* decision to renege on trade
* every moves that are needed to bring liquidity promised to the taker.

The offer logic in `makerExecute` **should** be gas bounded since an out-of-gas exception will lead to Mangrove transferring your whole [provision](https://docs.mangrove.exchange/dev/quick-links/glossary#provision) to the taker as a [bounty](https://docs.mangrove.exchange/dev/quick-links/glossary#bounty).

**Must** be in `makerPosthook`:

* any write action to the [offer list](https://docs.mangrove.exchange/dev/quick-links/glossary#offer-list) to which the currently executed offer belongs.
* any logging of a revert reason raised during `makerExecute`. The (truncated to a bytes32) reason is passed to `makerPosthook` in the `makerData` field.

**Should** be in `makerPosthook`:

* actions that are not gas bounded, such as posting or updating an offer on Mangrove.
* in general, calls which may raise an exception that should not cause the current trade execution to fail.
* offer logic that revert during `makerPosthook` do not abort trade and Mangrove will emit a `PosthookFail` log.

### Hooks that make your contract dev friendly[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#hooks-that-make-your-contract-dev-friendly) <a href="#hooks-that-make-your-contract-dev-friendly" id="hooks-that-make-your-contract-dev-friendly"></a>

#### Activate functions[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#activate-functions) <a href="#activate-functions" id="activate-functions"></a>

The [`activate(IERC20[] calldata tokens)`](https://docs.mangrove.exchange/dev/technical-references/api-preferences/strats/src/strategies/mangroveoffer#activate) public function of all strat library based maker contracts, enables one to perform all maker contract centric approvals, for the provided token list, in a single transaction. If your implementation requires more approval from the maker contract you **should** add them by overriding the `__activate__` hook. For instance assume your offer logic requires depositing asset on a lender's pool and the corresponding function requires an approval from the depositor, either you should approve the lender each time your logic deposits, or if you would rather approve once for all (with infinite approval), then you should add the approval to activate using:

```
__activate__(IERC20 token) internal override {
    super.__activate__(token); // perform all pre defined approvals
    token.approve({spender: <lender>, owner: address(this), amount:type(uint).max});
}
```

The [`activate(IERC20[] calldata tokens)`](https://docs.mangrove.exchange/dev/technical-references/api-preferences/strats/src/strategies/mangroveoffer#activate) function follows the same pattern for custom [routers](https://docs.mangrove.exchange/dev/quick-links/glossary#router) (see router [activation](https://docs.mangrove.exchange/dev/technical-references/liquidity-routing#router-activation)).

**cascading activation**

The activate function's default behavior is to perform the maker contract's activations and then ask its router (if any) to perform its own.

#### Checklist functions[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#checklist-functions) <a href="#checklist-functions" id="checklist-functions"></a>

[`checkList(IERC20[] calldata tokens)`](https://docs.mangrove.exchange/dev/technical-references/api-preferences/strats/src/strategies/mangroveoffer#checklist) is a dev friendly view function that reverts whenever the `tokens` list contains an ERC20 token that `msg.sender` cannot yet use to trade using the maker contract, typically because it requires an approval from `msg.sender`. The revert reason should be documented or as self contained as possible. Following the `activate` pattern, this function can be augmented with additional checks, using the `__checkList__` hook.

Router use a similar [function](https://docs.mangrove.exchange/dev/technical-references/api-preferences/strats/src/strategies/routeurs/abstract/abstractrouter#checklist) to verify that maker contract can source tokens via the router (see router [checklist](https://old.docs.mangrove.exchange/developers/strat-lib/technical-references/router#router-checklist)).

**cascading checkList**

The checkList function's default behavior is to perform maker contract's checkList and then ask its router (if any) to perform its own.

### Keepers as offer maintainers[​](https://old.docs.mangrove.exchange/developers/strat-lib/guides/HowToImplement#keepers-as-offer-maintainers) <a href="#keepers-as-offer-maintainers" id="keepers-as-offer-maintainers"></a>

A failing offer should not be the consequence of a bug in your offer logic, but rather be a feature of it. Raising an exception during `makerExecute` is the proper way to cancel a trade if your logic deems it necessary. You should customize the [last look](https://docs.mangrove.exchange/dev/technical-references/principal-hooks#last-look-before-trade) [hook](https://docs.mangrove.exchange/dev/quick-links/glossary#hook) for this, in order to fail early in the trade and save you money. For instance, if your logic relies on funds being on a lender, and a price oracle as a relative protection against arbitrage, you should check the oracle before redeeming the funds from the lender.
