Fixed product market maker
Overview
Underlying all markets, providing for a trading mechanism is fixed product market makers (FPMMs). These FPMMs are deployed upon market creation using a factory contract. As such, each market has a unique FPMM deployment/address.
The addresses and associations of these deployments are indexed in the subgraph and made available via the Gamma API. The contracts themselves are also self-descriptive. As the name suggests, FPMMs implement a fixed (ie "constant") product scoring rule wherein the product of the tokens in the pool (ie the liquidity) is held constant.
By maintaining this invariant, the price of a trade is calculated. Importantly, the tokens in the pool are outcome shares. Anyone can provide liquidity to the contract, and in return get ERC20 tokens representing their share of the liquidity pool.
When users trade against the pool they pay a configured fee, in collateral, which is reserved proportionally for liquidity providers. When a trader buys shares from a pool, their collateral is split into the underlying conditional tokens, the token they are buying is kept and the rest are sold to the pool for more of the token they are buying. When selling, the user is actually trading the token for equal amounts of the other tokens in the pool (in the binary case just one other outcome token) and then the full sets are merged for collateral.
The source implementation of the fixed product was developed by Gnosis.
Basic AMM mechanics
Essentially, an automated market maker (AMM) is just a market participant that's a bot that makes sure there are always some outcome tokens for every outcome in its inventory and that there is always a price that can be offered for an outcome token. As long as the AMM is active, traders can buy and sell outcome tokens for a prediction market, and the AMM will aggregate the trade data to produce estimates for the odds of outcomes.
The FPMM is using the same mechanism as Uniswap and Balancer pools. It was originally designed for the more general use case of swapping tokens, but has been tailored for the prediction market use case in the FixedProductMarketMaker contract.
In FPMM, the formula for the invariant is:
invariant = product(numOutcomeTokensInInventoryForOutcome for every outcome)
When traders buy an amount of an outcome token from an AMM, essentially the following steps occur:
- The trader sends the cost amount to the AMM.
- The AMM converts the cost amount received to a set of outcome tokens and adds the 1. outcome tokens to its inventory. The AMM's invariant expression is now broken.
- The AMM now sends enough of the demanded outcome token back to the trader so that the invariant is restored. This is the amount of the demanded outcome token bought.
Similarly, selling works as follows:
- The trader sends the sold amount of an outcome token to the AMM.
- The AMM adds the sold outcome token to its inventory. The AMM's invariant expression is now broken.
- The AMM converts an amount of the full set of outcome tokens back to collateral and sends this collateral back the trader so that the invariant is restored. This amount is the sale price.
The odds for an outcome with the FPMM can be found with the formula:
oddsWeightForOutcome = product(numOutcomeTokensInInventoryForOtherOutcome for every otherOutcome)
oddsForOutcome = oddsWeightForOutcome / sum(oddsWeightForOutcome for every outcome)
An example with FPMM
Let's fund an FPMM named Digi with $10. Digi takes $10, converts it to 10 Yes and 10 No tokens, and adds them to its inventory.
Now let's say Alice buys $10 worth of Yes tokens from Digi:
- Alice sends $10 to Digi.
- Digi turns $10 into 10 Yes and 10 No tokens. Digi has now 20 Yes and 20 No tokens, breaking its invariant (invariant should be 100, but now it's 400).
- Digi returns 15 Yes tokens to Alice, restoring the invariant.
At the end of this trade, Digi has 5 Yes and 20 No tokens, and it estimates the odds of Yes are 80% and the odds of No are 20%.