> For the complete documentation index, see [llms.txt](https://move-developers-dao.gitbook.io/aptos-move-by-example/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://move-developers-dao.gitbook.io/aptos-move-by-example/decentralized-finance/code-of-swapping-protocol.md).

# Code of Swapping Protocol

```rust
// Module for implementing a simple swap protocol for generating LP tokens, creating a pool, adding/removing liquidity, and swapping tokens.
module swap_account::Swap{
// Import required modules and libraries
use aptos_framework::coin::{Self, Coin, MintCapability, BurnCapability};
use std::string;
use std::string::String;
use std::option;
use swap_account::Math::{sqrt, min};
use std::signer::address_of;
use swap_account::Math;

// Constant for minimum liquidity required in LP tokens
const MINIMUM_LIQUIDITY: u64 = 1000;

// Define a phantom struct LP with generic types X and Y to represent LP tokens for token pair X-Y
struct LP<phantom X, phantom Y> {}

// Define a struct Pair with generic types X and Y representing a token pair with its related data
struct Pair<phantom X, phantom Y> has key {
    x_coin: Coin<X>,
    y_coin: Coin<Y>,
    lp_locked: Coin<LP<X, Y>>,
    lp_mint: MintCapability<LP<X, Y>>,
    lp_burn: BurnCapability<LP<X, Y>>,
}

// Function to generate LP token name symbol for a given token pair X-Y
public fun generate_lp_name_symbol<X, Y>(): String {
    let lp_name_symbol = string::utf8(b"");
    string::append_utf8(&mut lp_name_symbol, b"LP");
    string::append_utf8(&mut lp_name_symbol, b"-");
    string::append(&mut lp_name_symbol, coin::symbol<X>());
    string::append_utf8(&mut lp_name_symbol, b"-");
    string::append(&mut lp_name_symbol, coin::symbol<Y>());
    lp_name_symbol
}

// Function to create a new pool for token pair X-Y
public entry fun create_pool<X, Y>(sender: &signer) {
    // Check if the pair already exists (a pair for X-Y or Y-X)
    assert!(!pair_exist<X, Y>(@swap_account), 1000);

    // Generate LP token name and symbol for the token pair X-Y
    let lp_name_symbol = generate_lp_name_symbol<X, Y>();

    // Initialize LP token and get its mint and burn capabilities
    let (lp_burn, lp_freeze, lp_mint) = coin::initialize<LP<X, Y>>(
        sender,
        lp_name_symbol,
        lp_name_symbol,
        6, // Number of decimal places for the LP token
        true, // LP token is fungible
    );

    // Remove the freeze capability to prevent freezing LP tokens
    coin::destroy_freeze_cap(lp_freeze);

    // Create a new Pair for token pair X-Y and store it in the global storage
    move_to(
        sender,
        Pair<X, Y> {
            x_coin: coin::zero<X>(),
            y_coin: coin::zero<Y>(),
            lp_locked: coin::zero<LP<X, Y>>(),
            lp_mint,
            lp_burn,
        },
    );
}

// Function to add liquidity for a given token pair X-Y
public entry fun add_liquidity<X, Y>(sender: &signer, x_amount: u64, y_amount: u64)
    acquires Pair
{
    // Make sure the pair exists
    assert!(exists<Pair<X, Y>>(@swap_account), 1000);

    // Borrow the Pair data from global storage
    let pair = borrow_global_mut<Pair<X, Y>>(@swap_account);

    // Convert the amounts to u128 to prevent overflow during calculations
    let x_amount = (x_amount as u128);
    let y_amount = (y_amount as u128);

    // Get the current reserves for token X and Y
    let x_reserve = (coin::value(&pair.x_coin) as u128);
    let y_reserve = (coin::value(&pair.y_coin) as u128);

    // Calculate the optimal amount of Y to be added given the amount of X
    let y_amount_optimal = quote(x_amount, x_reserve, y_reserve);

    // Choose the smaller of the actual Y amount and the optimal Y amount
    if (y_amount_optimal <= y_amount) {
        y_amount = y_amount_optimal;
    }else{
        let x_amount_optimal = quote(y_amount,y_reserve,x_reserve);
        x_amount = x_amount_optimal;
    };

    // Withdraw X and Y tokens from the sender's account
    let x_amount_coin = coin::withdraw<X>(sender, (x_amount as u64));
    let y_amount_coin = coin::withdraw<Y>(sender, (y_amount as u64));

    // Deposit the withdrawn tokens into the Pair
    coin::merge(&mut pair.x_coin, x_amount_coin);
    coin::merge(&mut pair.y_coin, y_amount_coin);

    // Calculate the liquidity to be minted and mint LP tokens accordingly
    let liquidity;
    let total_supply = *option::borrow(&coin::supply<LP<X, Y>>());
    if (total_supply == 0){
        liquidity = sqrt(((x_amount * y_amount) as u128)) - MINIMUM_LIQUIDITY;
        let lp_locked = coin::mint(MINIMUM_LIQUIDITY, &pair.lp_mint);
        coin::merge(&mut pair.lp_locked, lp_locked);
    } else {
        liquidity = (min(
            Math::mul_div(x_amount, total_supply, x_reserve),
            Math::mul_div(y_amount, total_supply, y_reserve),
        ) as u64);
    };

    // Mint the liquidity and deposit it into the sender's account
    let lp_coin = coin::mint<LP<X, Y>>(liquidity, &pair.lp_mint);
    let addr = address_of(sender);
    if (!coin::is_account_registered<LP<X, Y>>(addr)) {
        coin::register<LP<X, Y>>(sender);
    };
    coin::deposit(addr, lp_coin);
}

// Function to remove liquidity for a given token pair X-Y
public entry fun remove_liquidity<X, Y>(sender: &signer, liquidity: u64) acquires Pair {
    // Make sure the pair exists
    assert!(exists<Pair<X, Y>>(@swap_account), 1000);

    // Borrow the Pair data from global storage
    let pair = borrow_global_mut<Pair<X, Y>>(@swap_account);

    // Withdraw LP tokens from the sender's account
    let liquidity_coin = coin::withdraw<LP<X, Y>>(sender, liquidity);
    coin::burn(liquidity_coin, &pair.lp_burn);

    // Get the total supply of LP tokens, and the current reserves for token X and Y
    let total_supply = *option::borrow(&coin::supply<LP<X,Y>>());
    let x_reserve = (coin::value(&pair.x_coin) as u128);
    let y_reserve = (coin::value(&pair.y_coin) as u128);

    // Calculate the amounts of X and Y to be removed based on the liquidity
    let x_amount = Math::mul_div((liquidity as u128), x_reserve, total_supply);
    let y_amount = Math::mul_div((liquidity as u128), y_reserve, total_supply);

    // Extract the amounts of X and Y tokens from the Pair
    let x_amount_coin = coin::extract<X>(&mut pair.x_coin,( x_amount as u64));
    let y_amount_coin = coin::extract<Y>(&mut pair.y_coin,( y_amount as u64));

    // Deposit the extracted tokens into the sender's account
    coin::deposit(address_of(sender), x_amount_coin);
    coin::deposit(address_of(sender), y_amount_coin);
}

// Function to swap token X for token Y
public entry fun swap_x_to_y<X, Y>(sender: &signer, amount_in: u64) acquires Pair {
    // Make sure the pair exists
    assert!(exists<Pair<X, Y>>(@swap_account), 1000);

    // Borrow the Pair data from global storage
    let pair = borrow_global_mut<Pair<X, Y>>(@swap_account);

    // Withdraw the input token X from the sender's account
    let coin_in = coin::withdraw<X>(sender, amount_in);

    // Register the sender's account for token Y if not already registered
    if (!coin::is_account_registered<Y>(address_of(sender))) {
        coin::register<Y>(sender);
    };

    // Get the current reserves for token X and Y
    let in_reserve = (coin::value(&pair.x_coin) as u128);
    let out_reserve = (coin::value(&pair.y_coin) as u128);

    // Calculate the amount of token Y to be received for the given amount of X
    let amount_out = get_amount_out((amount_in as u128), in_reserve, out_reserve);

    // Merge the input token X into the Pair and extract the output token Y from the Pair
    coin::merge(&mut pair.x_coin, coin_in);
    let amount_out_coin = coin::extract(&mut pair.y_coin, (amount_out as u64));

    // Deposit the received token Y into the sender's account
    coin::deposit(address_of(sender), amount_out_coin);
}

// Function to check if a Pair exists for the token pair X-Y or Y-X
public fun pair_exist<X, Y>(addr: address): bool {
    exists<Pair<X, Y>>(addr) || exists<Pair<Y, X>>(addr)
}

// Function to calculate the optimal amount of Y given X, X reserve, and Y reserve
public fun quote(x_amount:u128,x_reserve:u128,y_reserve:u128):u128{
    Math::mul_div(x_amount,y_reserve,x_reserve)
}

// Function to calculate the amount of output token for a given amount of input token
public fun get_amount_out(amount_in:u128,in_reserve:u128,out_reserve:u128):u128{
    let amount_in_with_fee = amount_in * 997;
    let numerator = amount_in_with_fee * out_reserve;
    let denominator = in_reserve * 1000 + amount_in_with_fee;
    numerator / denominator
}

// Function to get the current reserves of token X and Y in the Pair
public fun get_coin<X,Y>():(u64,u64) acquires Pair {
    let pair = borrow_global<Pair<X,Y>>(@swap_account);
    (coin::value(&pair.x_coin),coin::value(&pair.y_coin))
}
}

```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://move-developers-dao.gitbook.io/aptos-move-by-example/decentralized-finance/code-of-swapping-protocol.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
