# LP Token Mechanism

## Overview

LP (Liquidity Provider) tokens are credentials that represent a provider's share in a specific trading pair within JAMM DEX. Each trading pair has a corresponding LP token, implemented based on the `JAMMERC20` contract. It not only complies with the ERC-20 standard but also supports the EIP-2612 `permit` function, providing a better user experience.

## JAMMERC20 Contract Implementation

### Basic Information

```solidity
// from JAMMERC20.sol
contract JAMMERC20 is IJAMMERC20 {
    string public constant name = "JAMM LPs";
    string public constant symbol = "JAMM-LP";
    uint8 public constant decimals = 18;
    uint public totalSupply;
    mapping(address => uint) public balanceOf;
    mapping(address => mapping(address => uint)) public allowance;
    // ...
}
```

**LP Token Characteristics**:

* **Uniform Name**: All LP tokens for all pairs are named "JAMM LPs".
* **Uniform Symbol**: "JAMM-LP".
* **Precision**: 18 decimals.
* **Uniqueness**: Each trading pair is a separate instance of the LP token contract.

### EIP-2612 Permit Support

JAMM DEX's LP tokens support the EIP-2612 standard, allowing users to grant approvals via a signature, eliminating the need for a separate `approve` transaction.

```solidity
// from JAMMERC20.sol
bytes32 public DOMAIN_SEPARATOR;
bytes32 public constant PERMIT_TYPEHASH =
    0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint) public nonces;

constructor() {
    uint chainId;
    assembly {
        chainId := chainid()
    }
    DOMAIN_SEPARATOR = keccak256(abi.encode(
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
        keccak256(bytes(name)),
        keccak256(bytes("1")),
        chainId,
        address(this)
    ));
}

function permit(
    address owner,
    address spender,
    uint value,
    uint deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
) external {
    require(deadline >= block.timestamp, "JAMM: EXPIRED");
    bytes32 digest = keccak256(abi.encodePacked(
        "\x19\x01",
        DOMAIN_SEPARATOR,
        keccak256(abi.encode(
            PERMIT_TYPEHASH,
            owner,
            spender,
            value,
            nonces[owner]++,
            deadline
        ))
    ));
    address recoveredAddress = ecrecover(digest, v, r, s);
    require(recoveredAddress != address(0) && recoveredAddress == owner, "JAMM: INVALID_SIGNATURE");
    _approve(owner, spender, value);
}
```

## LP Token Lifecycle

### Minting

When a user adds liquidity to a pool, corresponding LP tokens are minted. This logic is implemented in `JAMMPair.sol`:

```solidity
// from JAMMPair.sol
function mint(address to) external lock returns (uint liquidity) {
    (uint112 _reserve0, uint112 _reserve1, ) = getReserves();
    uint balance0 = IERC20(token0).balanceOf(address(this));
    uint balance1 = IERC20(token1).balanceOf(address(this));
    uint amount0 = balance0 - _reserve0;
    uint amount1 = balance1 - _reserve1;

    bool feeOn = _mintFee(_reserve0, _reserve1);
    uint _totalSupply = totalSupply;
    if (_totalSupply == 0) {
        liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
        _mint(address(0), MINIMUM_LIQUIDITY);
    } else {
        liquidity = Math.min((amount0 * _totalSupply) / _reserve0, (amount1 * _totalSupply) / _reserve1);
    }
    require(liquidity > 0, "JAMM: INSUFFICIENT_LIQUIDITY_MINTED");
    _mint(to, liquidity);
    // ...
}
```

### Burning

When a user removes liquidity, the corresponding LP tokens are burned:

```solidity
// from JAMMPair.sol
function burn(address to) external lock returns (uint amount0, uint amount1) {
    (uint112 _reserve0, uint112 _reserve1, ) = getReserves();
    uint balance0 = IERC20(token0).balanceOf(address(this));
    uint balance1 = IERC20(token1).balanceOf(address(this));
    uint liquidity = balanceOf[address(this)];

    bool feeOn = _mintFee(_reserve0, _reserve1);
    uint _totalSupply = totalSupply;
    amount0 = (liquidity * balance0) / _totalSupply;
    amount1 = (liquidity * balance1) / _totalSupply;
    require(amount0 > 0 && amount1 > 0, "JAMM: INSUFFICIENT_LIQUIDITY_BURNED");
    _burn(address(this), liquidity);
    _safeTransfer(token0, to, amount0);
    _safeTransfer(token1, to, amount1);
    // ...
}
```

## Minimum Liquidity Mechanism

### Permanent Lock

```solidity
// from JAMMPair.sol
uint public constant MINIMUM_LIQUIDITY = 10**3;

// inside mint()
if (_totalSupply == 0) {
    liquidity = Math.sqrt(amount0 * amount1) - MINIMUM_LIQUIDITY;
    _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first tokens
}
```

**Purpose**:

* To prevent the liquidity pool from being completely drained, which would break price calculations.
* To prevent certain types of malicious manipulation attacks.

## `permit` Function Explained

### Advantage of Signature Approval

Traditional ERC-20 approvals require two transactions: `approve` and `transferFrom`. The `permit` function allows users to complete the approval and the action in a single on-chain transaction, preceded by an offline signature. This saves gas and improves user experience.

### Application in the Router

The `JAMMRouter` contract provides a function for removing liquidity using `permit`:

```solidity
// from JAMMRouter.sol
function removeLiquidityWithPermit(
    address tokenA, address tokenB, uint24 fee, uint liquidity,
    uint amountAMin, uint amountBMin, address to, uint deadline,
    bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB) {
    // Use permit to approve LP token spending
    IJAMMPair(JAMMLibrary.pairFor(factory, tokenA, tokenB, fee)).permit(
        msg.sender, address(this), approveMax ? type(uint).max : liquidity, deadline, v, r, s
    );
    // Then remove liquidity
    (amountA, amountB) = removeLiquidity(
        tokenA, tokenB, fee, liquidity, amountAMin, amountBMin, to, deadline
    );
}
```

## Usage Example

### Querying LP Token Information

```javascript
const pair = new ethers.Contract(pairAddress, pairABI, provider);

// Get LP token balance
const lpBalance = await pair.balanceOf(userAddress);
console.log("LP Balance:", ethers.utils.formatEther(lpBalance));

// Get total supply of LP tokens
const totalSupply = await pair.totalSupply();
console.log("Total Supply:", ethers.utils.formatEther(totalSupply));

// Calculate user's share of the pool
const userShare = lpBalance.mul(10000).div(totalSupply);
console.log("User Share:", userShare.toNumber() / 100, "%");
```

### Removing Liquidity with `permit`

```javascript
// Generate permit signature
const nonce = await pair.nonces(signer.address);
const deadline = Math.floor(Date.now() / 1000) + 60 * 20; // 20 minutes

const domain = {
    name: 'JAMM LPs',
    version: '1',
    chainId: await signer.getChainId(),
    verifyingContract: pairAddress
};

const types = {
    Permit: [
        { name: 'owner', type: 'address' },
        { name: 'spender', type: 'address' },
        { name: 'value', type: 'uint256' },
        { name: 'nonce', type: 'uint256' },
        { name: 'deadline', type: 'uint256' }
    ]
};

const value = {
    owner: signer.address,
    spender: routerAddress,
    value: liquidity,
    nonce: nonce,
    deadline: deadline
};

const signature = await signer._signTypedData(domain, types, value);
const { v, r, s } = ethers.utils.splitSignature(signature);

// Remove liquidity using the signature
const tx = await router.removeLiquidityWithPermit(
    tokenA, tokenB, fee, liquidity,
    amountAMin, amountBMin, to, deadline,
    false, v, r, s
);
```

## Summary

The LP token mechanism in JAMM DEX has the following features:

1. **Standard Compliance**: Fully compliant with the ERC-20 standard.
2. **Permit Support**: Offers a better user experience and gas efficiency through EIP-2612.
3. **Secure Design**: Multiple security mechanisms, including re-entrancy guards, overflow protection, and signature verification.
4. **Flexible Use**: Transferable and tradable liquidity credentials.
5. **Transparent Value**: The value corresponds directly to the share of assets in the pool.

LP tokens are a vital part of the JAMM DEX ecosystem, providing liquidity providers with a flexible way to manage their assets.
