# AutoSwap

An AutoSwap is like a swap, except instead of having to find a matching offer, an offer is always matched against the existing liquidity pool. The AutoSwap contract checks whether your offer will keep the constant product invariant before accepting.

Based on UniSwap.

# Initialization

const tokenAssays = [moolaAssay, simoleanAssay];
const { instance: autoswap } = zoe.makeInstance(
  installationHandle,
  { assays },
);

# Adding liquidity to the pool

The moola<->simolean autoswap that we just created has a number of methods in the API available to the user:

  1. addLiquidity
  2. removeLiquidity
  3. getPrice
  4. makeOffer

We can call addLiquidity with an escrow receipt from Zoe that proves that we've escrowed moola and simoleans appropriately. For instance, let's say that Alice decides to add liquidity. She creates an offer rule with the associated payments of moola and simoleans and escrows them:

const aliceOfferRules = harden({
  payoutRules: [
    {
      kind: 'offerExactly',
      units: moolaAssay.makeUnits(10),
    },
    {
      kind: 'offerExactly',
      units: simoleanAssay.makeUnits(5),
    },
    {
      kind: 'wantAtLeast',
      units: liquidityAssay.makeUnits(10),
    },
  ],
  exitRule: {
    kind: 'onDemand',
  },
]);
const alicePayments = [aliceMoolaPayment, aliceSimoleanPayment, undefined];

const {
  escrowReceipt,
  payout,
} = await zoe.escrow(aliceOfferRules, alicePayments);

She is able to ensure that she will get a minimum number of liquidity tokens back by specifying a rule for the liquidity token slot with wantAtLeast. In this case, Alice is stating that she wants at least 10 liquidity tokens back.

# Making a swap offer

Let's say that Bob wants to se the moola<->simolean autoswap to exchange 2 moola. First he will check the price:

const simoleanUnits = autoswap.getPrice([
  units2Moola,
  undefined,
  undefined,
]);

By using getPrice, he learns that the current price for 2 moola is 1 simolean. Because other people may make offers before Bob does, he can't rely on this price. However, he can make his offer conditional on getting at least 1 simolean back. If the price has moved, he will get a refund:

 const bobMoolaForSimOfferRules = harden({
   payoutRules: [
    {
      kind: 'offerExactly',
      units: moolaAssay.makeUnits(2),
    },
    {
      kind: 'wantAtLeast',
      units: simoleanAssay.makeUnits(1),
    },
    {
      kind: 'wantAtLeast',
      units: liquidityAssay.makeUnits(0),
    },
  ],
  exitRule: {
    kind: 'onDemand',
  },
);

He escrows 2 moola with Zoe and receives an escrow receipt.

const bobMoolaForSimPayments = [bobMoolaPayment, undefined, undefined];

const {
  escrowReceipt,
  payout,
} = await zoe.escrow(
  bobMoolaForSimOfferRules,
  bobMoolaForSimPayments,
);

Then Bob uses this escrow receipt to make an offer.

autoswap.makeOffer(escrowReceipt);

Now Bob can get his payout:

const [bobMoolaPayment, bobSimoleanPayment ] = await bobPayoutP;

# Removing Liquidity

If Alice wants to remove liquidity and get moola and simoleans back, she can do that by making new offerRules and escrowing a payment of liquidity tokens:

const aliceRemoveLiquidityOfferRules = harden({
  payoutRules: [
    {
      kind: 'wantAtLeast',
      units: allAssays[0].makeUnits(0),
    },
    {
      kind: 'wantAtLeast',
      units: allAssays[1].makeUnits(0),
    },
    {
      kind: 'offerExactly',
      units: allAssays[2].makeUnits(10),
    },
  ],
  exitRule: {
    kind: 'onDemand',
  },
});

const {
  escrowReceipt,
  payout,
} = await zoe.escrow(
  aliceRemoveLiquidityOfferRules,
  harden([undefined, undefined, liquidityPayment]),
);

aliceAutoswap.removeLiquidity(
  aliceRemoveLiquidityEscrowReceipt,
);