Swap

Swap parameters

Swaps (BUY/SELL) are possible using exacts amounts IN or OUT. That makes 4 types of swaps, handled as an enum in the program. This translates to the following type for Anchor:

/// Swap inputs are gathered in a single object (Anchor's conversion from the rust enum)
/// Every usual type of swap is supported:
// - buyExactIn: {amountIn: number, minAmountOut: number}
// - buyExactOut: {amountOut: number, maxAmountIn: number}
// - sellExactIn: {amountIn: number, minAmountOut: numer}
// - sellExactOut: {amountOut: number, maxAmountIn: number}
const swapParameters = {
  buyExactIn: [
    new anchor.BN(10_000_000), // 0.01 SOL
    new anchor.BN(1),
  ],
};

We'll use buyExactIn for the rest of this example.

SOL wrapping

If the quote token is WSOL, buying will require some wrapped SOL.

const transferIx = anchor.web3.SystemProgram.transfer({
  fromPubkey: wallet.publicKey,
  toPubkey: userTokenAccount1.address,
  lamports: swapParameters.buyExactIn[0].toNumber(),
});

const syncNativeIx = createSyncNativeInstruction(userTokenAccount1.address);

const tx = new anchor.web3.Transaction().add(transferIx, syncNativeIx);

Fee addresses

Protocol and KOTM addresses are specified on the config account, that can be fetched on-chain.

const config = new PublicKey(process.env.CONFIG ?? "");
const configAccount = await program.account.tokenMillConfig.fetch(config);

const market = new PublicKey(process.env.MARKET ?? "");
const marketAccount = await program.account.market.fetch(market);
const baseTokenMint = marketAccount.tokenMint0;

// The market fee reserve can be set directly on the market account, but if it isn't, it falls back to the config account
const marketFeeReserve =
  marketAccount.feeReserve ?? configAccount.creatorFeePool;
  
const userTokenAccount0 = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  baseTokenMint,
  wallet.publicKey
);

const userTokenAccount1 = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  marketAccount.tokenMint1,
  wallet.publicKey
);

Transaction

const swapIx = await program.methods
  .swap(swapParameters)
  .accountsPartial({
    config,
    market,
    marketReserve0: marketAccount.reserve0,
    marketReserve1: marketAccount.reserve1,
    feeReserve: marketFeeReserve,
    creatorFeePool: configAccount.creatorFeePool,
    userTokenAccount0: userTokenAccount0.address,
    userTokenAccount1: userTokenAccount1.address,
    protocolFeeReserve: configAccount.protocolFeeReserve,
    user: wallet.publicKey,
    swapAuthority: null,
  })
  .signers([wallet.payer])
  .instruction();
  
tx.push(swapIx);

const txSignature = await connection.sendTransaction(tx, [wallet.payer]);

await connection.confirmTransaction(txSignature);

Last updated