# Introduction
Flat curves have shown to perform very well for assets that are supposed to have a fixed target price, i.e. uusd vs kusd. Especially in growing ecosystems with little liquidity coming up with solutions to leverage the liquidity more effectively is key to success and speeds up said growth. The flat curves allow the liquidity to be concentrated at the target price, effectively enabling a larger volume compared to a naive constant product market maker.
This brainstorming aims at finding a way to use flat curves with target price set by an external observation (aka oracle).
If we choose a naive approach and use all of the same formulas and logic from the flat curve, but adapt the target price at an interval we can achieve the effect we are looking for, but are introducing a couple of issues that need to be mitigated:
- Pool front-running: If we have an observation every i.e. 15 minutes short before the next observation an arbitrageur can swap at the "old" price from the pool knowing the new target allows them to make a profit.
- Stale price: The external observation can fail for many reasons (API down, bug in the oracle software, protocol updates, congestion on protocol level, etc...). What should be done if the set target on-chain deviates too much from the off-chain observation?
# Solutions
## Swap pre-commit
We introduce to the flat curve additional state:
- `intent_counter` nat: an incremental counter that keeps track of the order of the intents
- `executed_intent_counter` nat: an incremental counter that keeps track of the order of the intents
- `intents` big-map: a big map storing intentions
- `epoch_counter` nat: an incremental counter that keeps track of the observation count.
We introduce a new entry point:
- `execute_intent(intent_id: nat)`
An "intent" can be the users' intent to:
- `add_liquidity`
- `remove_liquidity`
- `token_to_cash`
- `cash_to_token`
The intents don't differ from the current implementations, only the flow is different. Instead of executing the intent immediately the intent is only stored and allowed to be executed iff:
- it is the next intent in line `executed_intent_counter+1 == intent_id`
- the new target of a future epoch is set
This two-stepped approach mitigates the risks above at the cost of a delay in the trade.
# Appendix
## Setting the target
Setting a target different than 1:1 on the flat curves requires only small adaptions of the current code:
```
let tokensBought (cashPool : nat) (cashMultiplier : nat) (tokenPool : nat) (tokenMultiplier : nat) (cashSold : nat) : nat =
let x = cashPool * cashMultiplier in
let y = tokenPool * tokenMultiplier in
(* 4 round is enough for most cases and underestimates the true payoff, so the user
can always break up a trade for better terms *)
let u, _ = util x y in
(newton {x = x; y = y ; dx = cashSold * cashMultiplier ; dy = 0n ; u = u ; n = 5}) / tokenMultiplier
let cashBought (cashPool : nat) (cashMultiplier : nat) (tokenPool : nat) (tokenMultiplier : nat) (tokenSold : nat) : nat =
let x = tokenPool * tokenMultiplier in
let y = cashPool * cashMultiplier in
let u, _ = util x y in
(newton {x = x; y = y ; dx = tokenSold * tokenMultiplier ; dy = 0n ; u = u ; n = 5}) / cashMultiplier
```