# Introduction

Welcome to the documentation of Fwog.Fun! A platform for holders, memecoins, creators and influencers, prediction markets and more.

On most launchpads you're down 5% the moment you buy. Fees get extracted, tokens go to zero, and the only consistent winners are the platforms themselves. That's why nobody holds anymore. Why would you? You know how it ends.

Fwog was built to fix this. Fees on Fwog don't get extracted. They flow into a buyback mechanism that creates a rising price floor for every token. This floor is on-chain and visible. Rugging below it is impossible.

When zero isn't the endpoint, the game changes. Holding becomes viable. Tokens can survive long enough to actually run. More survivors, more runners, more people getting rich together instead of racing each other to the exit.

<figure><img src="/files/fkSBGjpyGFB5fe0PG24m" alt="" width="563"><figcaption></figcaption></figure>

Continue reading the documentation to understand how Fwog achieves this!


# Fwog: Extraction-free ecosystem maximising runners

Fwog is ‘unsolving’ memecoins on Solana by completely changing the game, reviving the trenches with higher odds of winning for traders. Fwog is fully focused on delivering more runners.

#### Dynamic Reserve Mechanism

Fwog changed the underlying maths of a memecoin launchpad through a **‘Dynamic Reserve Mechanism’ (DRM)**.&#x20;

Unlike other launchpads that use bonding curves, **Fwog uses one-sided liquidity pools**. There's no curve determining price, no migration needed. Tokens launch straight into real DEX liquidity and start trading immediately.

Every transaction is taxed, and that tax does two things: it grows the algorithmic reserve and it permanently removes tokens from circulation. This taxes traders while rewarding holders.

When you trade a token on Fwog, a percentage of that trade goes toward buying back the token itself. Those bought tokens get sent to the reserve and locked forever. They're gone. No one can sell them. Not the team, not early buyers, no one. Permanently removed from circulation.

So with every trade, the circulating supply shrinks. But demand stays intact. Same buyers chasing fewer tokens. That's the formula for runners.

On other platforms, volume just means fees leaving the ecosystem. Money flows out to the platform operators while tokens bleed to zero. On Fwog, volume makes tokens stronger. Every trade, whether it's a buy or a sell, locks up more supply. Even dumps make the token stronger for everyone still holding. This again highlights how Fwog's system rewards those who are holding, while taking fees from traders.

**Fwog's mechanics are designed to create more runners.**

<figure><img src="/files/UlwtzlgwNi86it0PSGhR" alt="" width="491"><figcaption></figcaption></figure>

### Buyback impact

The images above and show the massive impact of token buybacks. On this token, a whopping quarter of the supply was permanently removed from circulation. Those are tokens that can never be sold again, only pushing the floor price higher.

<figure><img src="/files/dgJeDRSQKHxIOL6fLbGv" alt=""><figcaption></figcaption></figure>

#### Bottom Market Cap

The continuous buybacks from this algorithmic reserve also make tokens unruggable. Every token has a visible floor price called the **Bottom Market Cap (BMC)**, showing the minimum value it can reach. It's impossible to get rugged below it. This bottom price grows exponentially with every transaction, building permanent liquidity that supports the token regardless of market conditions.

The BMC is transparently displayed, so for users it is clear which minimum value a token can reach. In Fwog’s architecture, when a token approaches the BMC it triggers an opposite reaction compared to the panic selling when normal memecoins go to zero: on Fwog this will lead to competitive buying.&#x20;

This makes tokens survive and leads to more runners, which makes the platform create more winners among its users.

<figure><img src="/files/PkSc0AVcPbVxN5gXqTvg" alt="" width="375"><figcaption></figcaption></figure>


# FwogBorrow: Memecoin leverage without liquidations

Borrowing against your bags without getting liquidated

Introducing FwogBorrow: letting you borrow against your tokens without selling them. 0% interest, no liquidations possible.

#### **The problem with crypto lending**

Traditional crypto lending is dangerous, especially for memecoins. You deposit collateral, borrow against it, and if the price drops too far you get liquidated. Your collateral gets sold automatically and you lose everything.

With memecoins this happens constantly. One dump, one wick, and your position is gone. So people don't borrow against their bags. They just sell when they need liquidity. This creates more sell pressure, kills momentum, and prevents runners.

#### **How FwogBorrow solves this**

FwogBorrow works differently because of the [Bottom Market Cap (BMC) floor mechanism](/fwog-extraction-free-ecosystem-maximising-runners#bottom-market-cap).

Every Fwog token has a BMC that can never decrease. When you borrow through FwogBorrow, you're borrowing against this floor, not the volatile market price.

Since the BMC can only go up, your collateral can never drop below your loan. Liquidation becomes impossible.

No margin calls. No getting wiped out on a wick. No watching your position get liquidated right before the bounce. The floor protects you.

#### **Why this changes everything for memecoins**

Memecoins have always been a game of timing your exit. Get out before the dump or get left holding the bag. Fwog is changing the memecoin game and FwogBorrow is part of this revolution.

Need liquidity? Borrow against your BMC instead of selling. Keep your position. If the token runs, you still benefit because you never sold.

This flips the game theory. Instead of racing to sell before everyone else, holders can stay in and access cash when they need it. Less selling means stronger price action. Stronger price action means more volume. More volume means higher floors. Higher floors mean more borrowing power.

It's a flywheel that rewards conviction instead of punishing it.

#### **Leverage looping**

Because you can borrow against your tokens, you can also loop for leverage.

Here's how it works: borrow SOL against your BMC, use that SOL to buy more of the same token, then borrow against your new larger position. Repeat.

Each loop increases your exposure. A $300k to $30m runner goes from being a 100x to potentially a 1000x.

And because liquidations are impossible, you can hold leveraged positions through any volatility. Diamond hands become actually viable instead of just copium.

<figure><img src="/files/zbFMsUJZb7tdjYtnuoyt" alt="" width="375"><figcaption></figcaption></figure>

#### **Coming soon**

You have probably seen the teaser on the token pages next to Swap: 'Leverage'. FwogBorrow is currently in development. Stay tuned for the launch!


# FwogSwap: Integration Guide

*Download the IDL file below:*

{% file src="/files/4Ss5ztIVBupRxa4dESBj" %}

### Overview

FwogSwap is a **Constant Product Market Maker (CPMM)** DEX on Solana with support for **one-sided liquidity provisioning**. It uses a concentrated liquidity model with configurable price ranges (`sqrtMinPrice` / `sqrtMaxPrice`), allowing pool creators to define the exact price boundaries for their liquidity.

**Program ID:** `fwogV3pR5UgBUWTbg8UKYCQZUbuNKCSKC8CyBtxxU7J`

**Protocol fees are set to 0%.**

#### Key Features

* **Concentrated Liquidity CPMM** with customizable price range (`sqrtMinPrice` to `sqrtMaxPrice`)
* **One-Sided Liquidity**: create pools where all initial liquidity is in a single token (e.g., launch a token without needing to pair it with SOL/USDC upfront)
* **SPL Token & Token-2022 support** (including transfer fees, transfer hooks)
* **NFT-based positions**: each liquidity position is represented by a Token-2022 NFT
* **Farming rewards**: up to 2 reward tokens per pool
* **Position locking & vesting**: lock positions with customizable vesting schedules
* **Dynamic fees**: optional volatility-based fee adjustments
* **Fee schedulers**: time-based or market-cap-based fee curves for token launches

***

### Architecture

#### Core Accounts

| Account            | Description                                                                                  |
| ------------------ | -------------------------------------------------------------------------------------------- |
| **Pool**           | Stores all pool state: reserves, price, fees, liquidity, reward info                         |
| **Config**         | Predefined pool configuration (fees, price range, activation type). Used by `initializePool` |
| **Position**       | Tracks a user's liquidity, pending fees, and pending rewards. Linked to an NFT mint          |
| **ProtocolConfig** | Singleton storing protocol-wide fee percentages                                              |

#### Price Model

Prices are stored as **sqrt prices in Q64.64 fixed-point format** (`u128`):

```
sqrtPrice = sqrt(price_token_b / price_token_a) * 2^64
```

Constants:

* `MIN_SQRT_PRICE = 4295048016`
* `MAX_SQRT_PRICE = 79226673521066979257578248091`

#### Fee Model

Fees use a numerator/denominator system:

* **Fee denominator**: `1,000,000,000` (1e9)
* **Fee numerator range**: `100,000` (0.01%) to `990,000,000` (99%)
* Trade fees go to LPs. Protocol and partner fees are configurable percentages split from the trade fee.

***

### Integration via IDL / ABI

The program is built with **Anchor**. You can integrate using the generated IDL at `target/idl/cp_amm.json`.

#### Setup

```typescript
import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
import { Connection, PublicKey, Keypair, SystemProgram, ComputeBudgetProgram } from "@solana/web3.js";
import { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync } from "@solana/spl-token";

// Import the IDL (JSON file from target/idl/cp_amm.json)
import CpAmmIDL from "./cp_amm.json";

const PROGRAM_ID = new PublicKey("fwogV3pR5UgBUWTbg8UKYCQZUbuNKCSKC8CyBtxxU7J");

const connection = new Connection("https://api.mainnet-beta.solana.com");
const provider = new AnchorProvider(connection, wallet, {});
const program = new Program(CpAmmIDL, provider);
```

#### PDA Derivations

All accounts are derived deterministically using PDAs:

```typescript
function derivePoolAuthority(): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("pool_authority")],
    PROGRAM_ID
  )[0];
}

// Pool PDA (config-based pool)
function derivePoolAddress(config: PublicKey, tokenAMint: PublicKey, tokenBMint: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from("pool"),
      config.toBuffer(),
      maxKey(tokenAMint, tokenBMint),   // larger pubkey first
      minKey(tokenAMint, tokenBMint),   // smaller pubkey second
    ],
    PROGRAM_ID
  )[0];
}

// Customizable pool PDA (no config, unique per token pair)
function deriveCustomizablePoolAddress(tokenAMint: PublicKey, tokenBMint: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [
      Buffer.from("cpool"),
      maxKey(tokenAMint, tokenBMint),
      minKey(tokenAMint, tokenBMint),
    ],
    PROGRAM_ID
  )[0];
}

function deriveTokenVaultAddress(tokenMint: PublicKey, pool: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("token_vault"), tokenMint.toBuffer(), pool.toBuffer()],
    PROGRAM_ID
  )[0];
}

function derivePositionAddress(positionNftMint: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("position"), positionNftMint.toBuffer()],
    PROGRAM_ID
  )[0];
}

function derivePositionNftAccount(positionNftMint: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("position_nft_account"), positionNftMint.toBuffer()],
    PROGRAM_ID
  )[0];
}

function deriveProtocolConfigAddress(): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("protocol_config")],
    PROGRAM_ID
  )[0];
}

// Helper: sort keys for deterministic PDA seeds
function maxKey(a: PublicKey, b: PublicKey): Buffer {
  return Buffer.compare(a.toBuffer(), b.toBuffer()) === 1 ? a.toBuffer() : b.toBuffer();
}

function minKey(a: PublicKey, b: PublicKey): Buffer {
  return Buffer.compare(a.toBuffer(), b.toBuffer()) === 1 ? b.toBuffer() : a.toBuffer();
}
```

***

### Creating a Customizable Pool (Two-Sided)

The `initializeCustomizablePool` instruction creates a pool where the creator specifies all parameters: price range, initial price, fees, and initial liquidity. This pool is unique per token pair (only one customizable pool per pair).

#### Sqrt Price Calculation

To compute the `sqrtPrice` from a human-readable price:

```typescript
function priceToSqrtPrice(price: number, decimalsA: number, decimalsB: number): BN {
  // price = tokenB_amount / tokenA_amount (in human-readable terms)
  // Adjust for decimal difference
  const adjustedPrice = price * Math.pow(10, decimalsB - decimalsA);
  const sqrtPriceDecimal = Math.sqrt(adjustedPrice);
  // Convert to Q64.64
  const sqrtPrice = new BN(
    BigInt(Math.floor(sqrtPriceDecimal * 2 ** 64)).toString()
  );
  return sqrtPrice;
}
```

#### Encoding Base Fee Parameters

The base fee is encoded as a 30-byte `data` array. For a simple static fee, use the `BorshFeeTimeScheduler` codec:

```typescript
import { BN } from "@coral-xyz/anchor";

// Encode a static fee (no time decay)
function encodeStaticBaseFee(feeNumerator: BN): { data: number[] } {
  // For a static fee, numberOfPeriod = 0, periodFrequency = 0, reductionFactor = 0
  // baseFeeMode = 0 (FeeTimeSchedulerLinear with no periods = static)
  const buffer = program.coder.types.encode("borshFeeTimeScheduler", {
    cliffFeeNumerator: feeNumerator,
    numberOfPeriod: 0,
    periodFrequency: new BN(0),
    reductionFactor: new BN(0),
    baseFeeMode: 0,
    padding: [0, 0, 0],
  });
  return { data: Array.from(buffer) };
}
```

#### Full Example: Two-Sided Pool

```typescript
async function createTwoSidedPool(
  payer: Keypair,
  tokenAMint: PublicKey,  // e.g., your token
  tokenBMint: PublicKey,  // e.g., SOL or USDC
  initialPriceBPerA: number,  // price of tokenA in terms of tokenB
  decimalsA: number,
  decimalsB: number,
) {
  const poolAuthority = derivePoolAuthority();
  const pool = deriveCustomizablePoolAddress(tokenAMint, tokenBMint);
  const positionNftKP = Keypair.generate();
  const position = derivePositionAddress(positionNftKP.publicKey);
  const positionNftAccount = derivePositionNftAccount(positionNftKP.publicKey);
  const tokenAVault = deriveTokenVaultAddress(tokenAMint, pool);
  const tokenBVault = deriveTokenVaultAddress(tokenBMint, pool);
  const protocolConfig = deriveProtocolConfigAddress();

  const tokenAProgram = (await connection.getAccountInfo(tokenAMint)).owner;
  const tokenBProgram = (await connection.getAccountInfo(tokenBMint)).owner;

  const payerTokenA = getAssociatedTokenAddressSync(tokenAMint, payer.publicKey, true, tokenAProgram);
  const payerTokenB = getAssociatedTokenAddressSync(tokenBMint, payer.publicKey, true, tokenBProgram);

  // Compute sqrt prices
  const sqrtPrice = priceToSqrtPrice(initialPriceBPerA, decimalsA, decimalsB);
  const sqrtMinPrice = new BN("4295048016");       // MIN_SQRT_PRICE
  const sqrtMaxPrice = new BN("79226673521066979257578248091"); // MAX_SQRT_PRICE

  // Fee: 1% static fee (fee_numerator = 10_000_000, denominator = 1_000_000_000)
  const baseFee = encodeStaticBaseFee(new BN(10_000_000));

  const poolFees = {
    baseFee,
    padding: new Array(2).fill(0),
    dynamicFee: null,  // no dynamic fee
  };

  const liquidity = new BN("1000000000000000"); // adjust based on desired depth

  const tx = await program.methods
    .initializeCustomizablePool({
      poolFees,
      sqrtMinPrice,
      sqrtMaxPrice,
      hasAlphaVault: false,
      liquidity,
      sqrtPrice,
      activationType: 1,       // 0 = slot-based, 1 = timestamp-based
      collectFeeMode: 0,       // 0 = both tokens, 1 = only token B
      activationPoint: null,   // null = activate immediately
    })
    .accountsPartial({
      creator: payer.publicKey,
      positionNftMint: positionNftKP.publicKey,
      positionNftAccount,
      payer: payer.publicKey,
      poolAuthority,
      pool,
      position,
      tokenAMint,
      tokenBMint,
      tokenAVault,
      tokenBVault,
      payerTokenA,
      payerTokenB,
      tokenAProgram,
      tokenBProgram,
      token2022Program: TOKEN_2022_PROGRAM_ID,
      systemProgram: SystemProgram.programId,
      protocolConfig,
    })
    .preInstructions([
      ComputeBudgetProgram.setComputeUnitLimit({ units: 350_000 }),
    ])
    .signers([payer, positionNftKP])
    .rpc();

  console.log("Pool created:", pool.toBase58());
  console.log("Position:", position.toBase58());
  return { pool, position };
}
```

***

### Creating a One-Sided Pool

One-sided liquidity is achieved by setting the **initial price at one of the price boundaries**. This makes the pool hold 100% of a single token at creation:

* **`sqrtPrice = sqrtMinPrice`**: the pool contains **only token A** (selling token A as price goes up)
* **`sqrtPrice = sqrtMaxPrice`**: the pool contains **only token B**

This is ideal for **token launches** where you want to seed the pool with your new token only, without needing to provide a quote token (SOL, USDC, etc.).

#### Example: One-Sided Pool (Token A Only)

```typescript
async function createOneSidedPool(
  payer: Keypair,
  tokenAMint: PublicKey,  // your new token (100% of initial liquidity)
  tokenBMint: PublicKey,  // quote token (SOL/USDC) - 0 needed at creation
  maxPriceBPerA: number,  // the price ceiling
  decimalsA: number,
  decimalsB: number,
) {
  const poolAuthority = derivePoolAuthority();
  const pool = deriveCustomizablePoolAddress(tokenAMint, tokenBMint);
  const positionNftKP = Keypair.generate();
  const position = derivePositionAddress(positionNftKP.publicKey);
  const positionNftAccount = derivePositionNftAccount(positionNftKP.publicKey);
  const tokenAVault = deriveTokenVaultAddress(tokenAMint, pool);
  const tokenBVault = deriveTokenVaultAddress(tokenBMint, pool);
  const protocolConfig = deriveProtocolConfigAddress();

  const tokenAProgram = (await connection.getAccountInfo(tokenAMint)).owner;
  const tokenBProgram = (await connection.getAccountInfo(tokenBMint)).owner;

  const payerTokenA = getAssociatedTokenAddressSync(tokenAMint, payer.publicKey, true, tokenAProgram);
  const payerTokenB = getAssociatedTokenAddressSync(tokenBMint, payer.publicKey, true, tokenBProgram);

  // For one-sided (token A only): sqrtPrice = sqrtMinPrice
  // Set sqrtMinPrice to a very small value (or MIN_SQRT_PRICE)
  // Set sqrtMaxPrice to represent the max price you want
  const sqrtMinPrice = new BN("4295048016"); // MIN_SQRT_PRICE
  const sqrtMaxPrice = priceToSqrtPrice(maxPriceBPerA, decimalsA, decimalsB);

  // Key: sqrtPrice = sqrtMinPrice => 100% token A, 0% token B
  const sqrtPrice = sqrtMinPrice;

  // Fee: 1% static fee
  const baseFee = encodeStaticBaseFee(new BN(10_000_000));

  const poolFees = {
    baseFee,
    padding: new Array(2).fill(0),
    dynamicFee: null,
  };

  const liquidity = new BN("1000000000000000");

  const tx = await program.methods
    .initializeCustomizablePool({
      poolFees,
      sqrtMinPrice,
      sqrtMaxPrice,
      hasAlphaVault: false,
      liquidity,
      sqrtPrice,           // = sqrtMinPrice => one-sided (token A only)
      activationType: 1,
      collectFeeMode: 0,
      activationPoint: null,
    })
    .accountsPartial({
      creator: payer.publicKey,
      positionNftMint: positionNftKP.publicKey,
      positionNftAccount,
      payer: payer.publicKey,
      poolAuthority,
      pool,
      position,
      tokenAMint,
      tokenBMint,
      tokenAVault,
      tokenBVault,
      payerTokenA,
      payerTokenB,
      tokenAProgram,
      tokenBProgram,
      token2022Program: TOKEN_2022_PROGRAM_ID,
      systemProgram: SystemProgram.programId,
      protocolConfig,
    })
    .preInstructions([
      ComputeBudgetProgram.setComputeUnitLimit({ units: 350_000 }),
    ])
    .signers([payer, positionNftKP])
    .rpc();

  console.log("One-sided pool created:", pool.toBase58());
  console.log("Only token A deposited. Token B is added by buyers.");
  return { pool, position };
}
```

> **Note**: Even in a one-sided pool, the payer still needs to have at least **1 lamport** worth of the other token to prove ownership of the mint. The program enforces `total_amount = max(computed_amount, 1)` for both tokens.

***

### Swapping

The swap instruction routes through the pool. The input/output direction is determined by matching the `inputTokenAccount` mint against `tokenAMint` / `tokenBMint`.

```typescript
async function swap(
  payer: Keypair,
  pool: PublicKey,
  inputMint: PublicKey,
  outputMint: PublicKey,
  amountIn: BN,
  minAmountOut: BN,
) {
  const poolState = await program.account.pool.fetch(pool);
  const poolAuthority = derivePoolAuthority();

  const tokenAProgram = (await connection.getAccountInfo(poolState.tokenAMint)).owner;
  const tokenBProgram = (await connection.getAccountInfo(poolState.tokenBMint)).owner;

  const inputTokenAccount = getAssociatedTokenAddressSync(
    inputMint, payer.publicKey, true,
    inputMint.equals(poolState.tokenAMint) ? tokenAProgram : tokenBProgram
  );
  const outputTokenAccount = getAssociatedTokenAddressSync(
    outputMint, payer.publicKey, true,
    outputMint.equals(poolState.tokenAMint) ? tokenAProgram : tokenBProgram
  );

  const tx = await program.methods
    .swap2({
      amount0: amountIn,
      amount1: minAmountOut,
      swapMode: 0,  // 0 = ExactIn, 1 = PartialFill, 2 = ExactOut
    })
    .accountsPartial({
      poolAuthority,
      pool,
      payer: payer.publicKey,
      inputTokenAccount,
      outputTokenAccount,
      tokenAVault: poolState.tokenAVault,
      tokenBVault: poolState.tokenBVault,
      tokenAMint: poolState.tokenAMint,
      tokenBMint: poolState.tokenBMint,
      tokenAProgram,
      tokenBProgram,
      referralTokenAccount: null,
    })
    .signers([payer])
    .rpc();

  console.log("Swap tx:", tx);
}
```

#### Swap Modes

| Mode        | Value | Description                                                           |
| ----------- | ----- | --------------------------------------------------------------------- |
| ExactIn     | `0`   | Swap exact input amount, receive at least `amount1`                   |
| PartialFill | `1`   | Swap up to `amount0` input, allowing partial fills at pool boundaries |
| ExactOut    | `2`   | Receive exactly `amount0` output, spend at most `amount1` input       |

***

### Adding / Removing Liquidity

#### Add Liquidity

```typescript
async function addLiquidity(
  owner: Keypair,
  pool: PublicKey,
  position: PublicKey,
  liquidityDelta: BN,
  maxTokenA: BN,
  maxTokenB: BN,
) {
  const poolState = await program.account.pool.fetch(pool);
  const positionState = await program.account.position.fetch(position);
  const positionNftAccount = derivePositionNftAccount(positionState.nftMint);

  const tokenAProgram = (await connection.getAccountInfo(poolState.tokenAMint)).owner;
  const tokenBProgram = (await connection.getAccountInfo(poolState.tokenBMint)).owner;

  await program.methods
    .addLiquidity({
      liquidityDelta,
      tokenAAmountThreshold: maxTokenA,
      tokenBAmountThreshold: maxTokenB,
    })
    .accountsPartial({
      pool,
      position,
      positionNftAccount,
      owner: owner.publicKey,
      tokenAAccount: getAssociatedTokenAddressSync(poolState.tokenAMint, owner.publicKey, true, tokenAProgram),
      tokenBAccount: getAssociatedTokenAddressSync(poolState.tokenBMint, owner.publicKey, true, tokenBProgram),
      tokenAVault: poolState.tokenAVault,
      tokenBVault: poolState.tokenBVault,
      tokenAMint: poolState.tokenAMint,
      tokenBMint: poolState.tokenBMint,
      tokenAProgram,
      tokenBProgram,
    })
    .signers([owner])
    .rpc();
}
```

#### Remove Liquidity

```typescript
async function removeLiquidity(
  owner: Keypair,
  pool: PublicKey,
  position: PublicKey,
  liquidityDelta: BN,
  minTokenA: BN,
  minTokenB: BN,
) {
  const poolState = await program.account.pool.fetch(pool);
  const positionState = await program.account.position.fetch(position);
  const positionNftAccount = derivePositionNftAccount(positionState.nftMint);
  const poolAuthority = derivePoolAuthority();

  const tokenAProgram = (await connection.getAccountInfo(poolState.tokenAMint)).owner;
  const tokenBProgram = (await connection.getAccountInfo(poolState.tokenBMint)).owner;

  await program.methods
    .removeLiquidity({
      liquidityDelta,
      tokenAAmountThreshold: minTokenA,
      tokenBAmountThreshold: minTokenB,
    })
    .accountsPartial({
      poolAuthority,
      pool,
      position,
      positionNftAccount,
      owner: owner.publicKey,
      tokenAAccount: getAssociatedTokenAddressSync(poolState.tokenAMint, owner.publicKey, true, tokenAProgram),
      tokenBAccount: getAssociatedTokenAddressSync(poolState.tokenBMint, owner.publicKey, true, tokenBProgram),
      tokenAVault: poolState.tokenAVault,
      tokenBVault: poolState.tokenBVault,
      tokenAMint: poolState.tokenAMint,
      tokenBMint: poolState.tokenBMint,
      tokenAProgram,
      tokenBProgram,
    })
    .signers([owner])
    .rpc();
}
```

***

### Reading Pool State

```typescript
async function getPoolInfo(poolAddress: PublicKey) {
  const pool = await program.account.pool.fetch(poolAddress);

  console.log("Token A Mint:", pool.tokenAMint.toBase58());
  console.log("Token B Mint:", pool.tokenBMint.toBase58());
  console.log("Sqrt Price:", pool.sqrtPrice.toString());
  console.log("Liquidity:", pool.liquidity.toString());
  console.log("Sqrt Min Price:", pool.sqrtMinPrice.toString());
  console.log("Sqrt Max Price:", pool.sqrtMaxPrice.toString());
  console.log("Pool Status:", pool.poolStatus === 0 ? "Enabled" : "Disabled");
  console.log("Pool Type:", pool.poolType === 0 ? "Permissionless" : "Customizable");

  return pool;
}
```

***

### Constants Reference

| Constant               | Value                           | Description                |
| ---------------------- | ------------------------------- | -------------------------- |
| `MIN_SQRT_PRICE`       | `4295048016`                    | Minimum allowed sqrt price |
| `MAX_SQRT_PRICE`       | `79226673521066979257578248091` | Maximum allowed sqrt price |
| `FEE_DENOMINATOR`      | `1,000,000,000`                 | Fee denominator (1e9)      |
| `MIN_FEE_NUMERATOR`    | `100,000`                       | Min fee (0.01%)            |
| `MAX_FEE_NUMERATOR`    | `990,000,000`                   | Max fee (99%)              |
| `PROTOCOL_FEE_PERCENT` | `0`                             | Protocol fee percentage    |

#### Common Fee Numerator Values

| Fee (bps) | Fee (%) | Numerator    |
| --------- | ------- | ------------ |
| 1         | 0.01%   | `100,000`    |
| 25        | 0.25%   | `2,500,000`  |
| 30        | 0.30%   | `3,000,000`  |
| 100       | 1.00%   | `10,000,000` |
| 500       | 5.00%   | `50,000,000` |

***

### Pool Initialization Methods

| Method                            | Description                                                      | Pool PDA                             |
| --------------------------------- | ---------------------------------------------------------------- | ------------------------------------ |
| `initializePool`                  | Create pool from a pre-existing `Config` account (static config) | `["pool", config, maxMint, minMint]` |
| `initializeCustomizablePool`      | Create pool with fully custom parameters, unique per token pair  | `["cpool", maxMint, minMint]`        |
| `initializePoolWithDynamicConfig` | Create pool from a dynamic `Config` with custom fee/price params | `["pool", config, maxMint, minMint]` |

***

### Important Notes

* **Compute budget**: Pool initialization requires \~350,000 compute units. Always include `ComputeBudgetProgram.setComputeUnitLimit({ units: 350_000 })`.
* **Token ordering**: When deriving PDAs, the larger pubkey comes first, smaller second. This ensures deterministic addresses regardless of input order.
* **Position NFTs**: Positions are Token-2022 NFTs. The `positionNftMint` keypair must be a signer during pool initialization and position creation.
* **Activation**: Pools can have delayed activation (slot-based or timestamp-based). Set `activationPoint: null` for immediate activation.
* **One customizable pool per pair**: The `initializeCustomizablePool` instruction allows only one pool per token pair since the PDA doesn't include a config key.


# Token Types

Most launchpads only do one thing. But Fwog has built multiple token types, each for different purposes: TikTok virality, Twitter/X influence, prediction markets. Or a straightforward memecoin launch, but even then there are multiple options.

Currently there are 5 different tokens available:

* **Regular tokens** are the simplest to launch with the least requirements and its fees are made up of buybacks.
* **Fwogtoks tokens** are a type of Creator tokens created by using a TikTok link where creators earn revenue on the trading volume.
* **Twitter/X tokens** are a type of Creator tokens similar to Fwogtoks, but with a different fee mechanism.
* **Prediction Market tokens** have the same fee system as Regular tokens, but of course trading of these tokens depends on completely different market dynamics.
* **Legacy tokens** are similar to Regular tokens. Legacy tokens were launched as the first tokens on the platform and are excluded from buyback fees.

<figure><img src="/files/1dR912nQv0YR5PxO5Avq" alt=""><figcaption></figcaption></figure>


# Creator Tokens

**Creator tokens** are Fwogtok tokens and Twitter/X tokens. Anyone can launch a creator token with any name and ticker. However, if a token gets launched using someone else's socials, it does not mean that the influencers owns or endorses the token.

Fwog has created a feature where Twitter/X and TikTok **influencers can claim a token** if their Twitter/X or TikTok handle is attached to the token. After the owner claims a token, the token will receive a **blue checkmark**. The creator then automatically receives creator rewards which consist of 3% of the trading fees.&#x20;

Only **one token** can be claimed per Twitter/X or TikTok username.&#x20;

Be sure to claim your token **within 6 months**. The rewards of unclaimed token are automatically reinvested into the platform after 6 months.

<figure><img src="/files/qAwsOlsZqradT3BiDfIC" alt=""><figcaption><p>The tokens above are examples, not real tokens. </p></figcaption></figure>


# Token Launch

Launch your tokens on Fwog's launchpad in different fashions!


# Bundle Options

Fwog introduces new mechanics to the memecoin game. The buybacks, the rising floor, the fee structure that rewards holders. But that's not all. Fwog also gives launchers tools to control their token's supply and starting conditions: bundle options.

More ways to launch means more ways to win. Different setups create different outcomes. The old playbooks don't work when every token can be configured differently. These options add more randomness to the game, creating more runners.

#### **Safe Bundle**

On most launchpads, traders run on autopilot. Token launches at X, sell at Y. Same patterns every time. When a token starts at a different point, that playbook breaks. Different starting conditions create different outcomes.

With the **Safe bundle** option you can launch your token at **10x of the usual starting market cap**. Normally a token is created with 1B supply. With Safe bundle, a token is launched with 10B supply and 9B is straight send to the reserve where it is locked forever.

<figure><img src="/files/IqI2YhPwqMtLMPfbNknb" alt=""><figcaption></figcaption></figure>

#### **Initial Buy**

This is different. You're actually putting in SOL and receiving tokens at launch. Enter the amount you want to buy and it executes the moment your token is created. No snipers getting in before you. No bots front-running the launch. You're first. SOL ends up in the liquidity pool and a small amount is also taken for fees.

You can combine both: use Safe bundle to start at 10x market cap, then Initial Buy to secure your bag on top of that.

#### **Control your supply**

These options let launchers be in control from block one. Influencers, creators, or anyone who wants skin in the game can set things up their way. Create a different market cap, hold big, be transparent about it, and let your bags align with your community. That's how trust gets built. That's how holders hold. That's one way runners get made.


# Alpha Vaults

Fwog gives launchers control over supply and starting conditions with [Bundle Options](/platform/token-launch/bundle-options). But what about the buyers? Alpha Vaults level the playing field for everyone getting in.

On most launchpads, bots and snipers dominate the first seconds of a launch. By the time regular users click buy, the best entries are gone. The fastest wallets continuously extract from everyone else.

Alpha Vaults change this.&#x20;

When everyone enters at the same price, there's no early advantage to dump on later buyers. No sniper sitting at 10x while you're at 2x. The game becomes about the token, not about who had the fastest bot. This creates fairer launches and another way how Fwog aims to provide more winners.

#### X/Twitter token launches

For all X/Twitter token launches with **accounts over 10k followers** Alpha Vaults are applied automatically. These launches attract the most attention and the most bots, so they get protection by default.

A 30 minute token sale starts where everyone buys at the same price. After contributions close, there's a 65 minute activation period during which trading is paused. When trading opens, everyone starts from the same position.

<figure><img src="/files/BbUMFRC3JmXcQi0F9r4d" alt=""><figcaption></figcaption></figure>

#### Optionality for Regular tokens

For regular token launches, Alpha Vaults are **optional**. In the future the Alpha vaults will be **customisable** for regular launches.


# Fee Breakdown

Unlike other platforms, Fwog's fees are not extractive. They flow back into the ecosystem through buybacks and creator rewards.&#x20;

### Fees

The platform takes fees on all transactions. These fees consist of the following:

* **Token buybacks:** Transactions on a token are taxed with a protocol fee collected in $SOL, which is straightaway used to buyback the token. Bought tokens get locked away reducing the supply, creating a higher floor price.
* **Creator fees:** TikTok and Twitter/X influencers can claim their tokens for rewards at any point. However, after 6 months creator revenue from unclaimed tokens is automatically reinvested into the platform.

<table data-header-hidden><thead><tr><th valign="top"></th><th valign="top">Text</th><th valign="top"></th></tr></thead><tbody><tr><td valign="top"> </td><td valign="top"><strong>Token buybacks</strong></td><td valign="top"><strong>Creator fee</strong></td></tr><tr><td valign="top">Regular Tokens</td><td valign="top">4%</td><td valign="top">-</td></tr><tr><td valign="top">Fwogtok Tokens</td><td valign="top">3.5%</td><td valign="top">0.5%</td></tr><tr><td valign="top">Prediction Market Tokens</td><td valign="top">4%</td><td valign="top">-</td></tr><tr><td valign="top">Twitter/X Tokens</td><td valign="top">2.9%</td><td valign="top">3%</td></tr><tr><td valign="top">Legacy Tokens</td><td valign="top">-</td><td valign="top">-</td></tr></tbody></table>

A 1% protocol fee is charged. Legacy tokens are not charged a protocol fee.

Meteora also charges a protocol fee of 20% of total fees, these are non-negotiable per Meteora.


# $FWOG Token

#### $FWOG rewards

Every trade and token you launch on Fwog earns you **$FWOG points**. These points will be converted into the **platform's token $FWOG** in the future. The more you trade now, the bigger your stake. And this compounds.&#x20;

<figure><img src="/files/agvsAatqP0zpNkTcGW2S" alt="" width="563"><figcaption></figcaption></figure>


# Future Updates

Fwog has many new features in the pipeline. Upcoming updates on Fwog’s platform include:

* **FwogBorrow:** Access fresh capital through borrowing against your tokens with 0% interest; never sell your bags. This results in leverage looping causing runners to go even higher. A special invention: liquidations are impossible.
* **FwogSwap:** Fwog’s Raydium fork with 100% cashback.
* **FwogTerminalPro:** Fwog’s trading terminal with 100% cashback.

<div align="center"><figure><img src="/files/GPm1p1l1azCK4NQppwyj" alt="" width="318"><figcaption></figcaption></figure></div>


# Official Links

Platform: <https://fwog.fun/>

Twitter/X: <https://x.com/PerpetualCow>


