This post is part of a series on DeFi. Here is the previous post, and this is the first post in the series.

Now that we have a reliable way to add/remove liquidity from our Automated Market Maker (AMM), and liquidity provider tokens (LP tokens) to keep track of who provided our liquidity, we can create an incentive for our liquidity providers.

As the DeFi ecosystem develops, we see lots of projects trying out weird and baroque ways to incentivise different actors in different ways; especially liquidity providers. But, the original and simplest way is probably the way version 1 of Uniswap did it:

  • Every time someone trades on our AMM, take a small commission (0.3% for Uniswap V1)
  • Put the commission amount back into the AMM’s asset reserves

That’s it.

This is the code for the Uniswap V1 getInputPrice method:

# @dev Pricing function for converting between ETH and Tokens.
# @param input_amount Amount of ETH or Tokens being sold.
# @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
# @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
# @return Amount of ETH or Tokens bought.
@private
@constant
def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
    assert input_reserve > 0 and output_reserve > 0
    input_amount_with_fee: uint256 = input_amount * 997
    numerator: uint256 = input_amount_with_fee * output_reserve
    denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee
    return numerator / denominator

By multiplying the numerator by 997, and the denominator by 1000, the effect here is to factor in a 0.3% commission before the figure is returned and used in the trade calculation.

Although the method is called getInputPrice, it actually returns the amount of tokens/ether bought

There is a similar adjustment in the getOutputPrice method, so whether the counterparty is buying tokens or selling them, the AMM keeps 0.3% of the value of the trade.

You can see the full code here.

Liquidity providers hold LP tokens which represent their share of the AMM’s total asset reserves (ether and tokens, in our case). If a liquidity provider has tokens representing 5% of the pool’s assets, then adding the 0.3% commission from every trade to the AMM’s asset pools makes the LP tokens more valuable, creating an incentive for the liquidity provider to deposit their assets into the AMM.

Let’s see how that works out with our AMM.

Adding 0.3% commission to the AMM

We need to tweak our trade method to incorporate the 0.3% fee:

  def trade(amount, input_reserve, output_reserve)
    konst = @token_reserve * @ether_reserve

    new_input_reserve = input_reserve + amount
    gross_output = konst / new_input_reserve
    proceeds = output_reserve - gross_output

    proceeds_with_fee = proceeds * 0.997
    new_output_reserve = output_reserve - proceeds_with_fee

    return [proceeds_with_fee, new_input_reserve, new_output_reserve]
  end

First, we work out what the output amount would be, then we reduce it by 0.3%. The net amount is what we take out of our asset pool, and give back to the counterparty. The effect is to increase the reserve of whichever asset was bought by 0.3% of the value of the trade.

Rewarding liquidity providers

To see how this rewards liquidity providers, we’ll create a script in which a liquidity provider adds liquidity to the AMM, then a bunch of trades happen, then the liquidity provider removes her liquidity again:

script.txt

zoe add 10 1000

alice buy 1
alice sell all
# ... repeat 99 more times ...

zoe remove 10
counterparties

Now let’s see what happens (some lines omitted for clarity):

$ cat script.txt | bin/amm.rb
> Amm eth: 10.0, tokens: 1000.0, price: 0.01 eth/token
...
> alice gets 90.63636363636361 tokens for 1.0 ether, price 0.0110
Amm eth: 11.0, tokens: 909.3636363636364, price: 0.012096371088673398 eth/token
> alice gets 0.9940089999999999 ether for 90.63636363636361 tokens, price 0.0110
Amm eth: 10.005991, tokens: 1000.0, price: 0.010005991 eth/token
...
> Amm eth: 0.0, tokens: 0.0, price: NaN eth/token
> alice	ether: 9.4009,	tokens: 0.0000, lp_tokens: 0.0000
zoe	ether: 10.5991,	tokens: 1000.0000, lp_tokens: 0.0000
Amm eth: 0.0, tokens: 0.0, price: NaN eth/token
> bye.

When zoe removes her 100% share of the AMM’s liquidity, she’s made a profit of 0.5991 ether, all of which comes from fees extracted from the counterparties who trade on the AMM.

In this very simplified case, we had alice do all the trading. In a more realistic scenario, there would be lots of liquidity providers, and lots of counterparties trading back and forth, but the principle is the same:

more trading => more fees going into the asset reserves => LP tokens increase in value

So, we have a virtuous cycle of incentives:

  • Liquidity providers want to supply liquidity to earn a profit
  • More liquidity means less slippage
  • With low slippage, our AMM attracts more traders
  • More trading means more fees to reward liquidity providers

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s