> ## Documentation Index
> Fetch the complete documentation index at: https://docs.meteora.ag/llms.txt
> Use this file to discover all available pages before exploring further.

# Example Scripts

> Alpha Vault

**Alpha Vaults can be configured to either be permissionless or permissioned.**

* For `Permissionless` Alpha Vaults, anyone can deposit assets into the Alpha Vault after creation.
* For permissioned Alpha Vaults, only whitelisted addresses can deposit assets into the Alpha Vault after creation. There are 2 types of permissioned Alpha Vaults:
  * `PermissionedWithAuthority` - In this mode, only the Alpha Vault creator can create escrow account with max\_cap. This allows the creator to easily use a permissioned (with whitelist) setup without having to use the merkle tree. Creator needs to pay SOL rent for each escrow account for the whitelisted wallets, so this Alpha Vault whitelist mode is suitable for scenarios where there are very few whitelisted addresses `(e.g. <=100)`. If they need to support a lot more whitelisted addresses, they should still use the merkle tree (PermissionWithMerkleProof whitelist mode).
  * `PermissionedWithMerkleProof` - In this mode, only wallets that are whitelisted can deposit into the Alpha Vault. CSV file containing the list of whitelisted wallets needs to be provided by the project to Meteora, for the Merkle proof to be hosted by Meteora and shown on the UI. Alpha Vault deposits should not open until the Merkle proof is hosted by Meteora.

# Example Timeline of an Alpha Vault

<Frame>
  <img src="https://mintcdn.com/meteora/gSl19wO31n1wt0qg/images/developer-guide/alpha-vault.webp?fit=max&auto=format&n=gSl19wO31n1wt0qg&q=85&s=a2d41d900eb7bef507c54df63717e325" width="1142" height="258" data-path="images/developer-guide/alpha-vault.webp" />
</Frame>

# Code Examples

### Creating an Alpha Vault

<Tabs>
  <Tab title="Permissionless Alpha Vault" icon="people">
    <AccordionGroup>
      <Accordion title="Create DAMM V1 Pool with Permissionless Alpha Vault">
        This example shows how to create a new DAMM v1 Pool that also adds a permissionless Alpha Vault.

        <Warning>You have to find a pool config and vault config that meets your requirements. Please contact us on [discord](https://discord.gg/meteora) if you need new pool configs or vault configs.</Warning>

        <Note> Currently, only SOL or USDC is accepted as the quote token when initializing a DAMM v1 Pool with Alpha Vault in a permissionless setup.</Note>

        ```typescript theme={"system"}
        import {
          clusterApiUrl,
          Connection,
          Keypair,
          PublicKey,
          sendAndConfirmTransaction,
          SYSVAR_CLOCK_PUBKEY,
        } from "@solana/web3.js";
        import AlphaVault, { DYNAMIC_AMM_PROGRAM_ID, PoolType, VaultMode } from "..";
        import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
        import {
          ActivationType,
          Clock,
          ClockLayout,
          createTokenAndMint,
          loadKeypairFromFile,
        } from "./utils";
        import dotenv from "dotenv";
        import { BN } from "bn.js";
        import { derivePoolAddressWithConfig } from "@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils";

        dotenv.config();

        async function createDummyMints(connection: Connection, payer: Keypair) {
          console.log("Creating mint A");
          const mintAInfo = await createTokenAndMint(
            connection,
            payer,
            6,
            100_000_000_000
          );

          console.log("Creating mint B");
          const mintBInfo = await createTokenAndMint(
            connection,
            payer,
            6,
            100_000_000_000
          );

          return {
            mintAInfo,
            mintBInfo,
          };
        }

        /**
         * @param connection
         * @param creator
         * @param activationType Pool activation based on time or slot
         * @param maximumActivationDuration Maximum duration for pool to be activation after creation
         * @param minimumLockDuration Minimum duration for bought token be locked
         * @param maximumLockDuration Maximum duration for bought token to be locked
         * @param minimumVestingDuration Minimum duration for bought token to be vested
         * @param maximumVestingDuration Maximum duration for bought token be vested
         * @param vaultMode Vault mode: fcfs or prorata
         */
        async function getPoolConfigByRequirement(
          connection: Connection,
          creator: PublicKey,
          activationType: ActivationType,
          maximumActivationDuration: number,
          minimumLockDuration: number,
          maximumLockDuration: number,
          minimumVestingDuration: number,
          maximumVestingDuration: number,
          vaultMode: VaultMode
        ) {
          // 1. Pool configs that can be used by anyone to create pool
          const publicPoolConfigs =
            await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
              connection,
              PublicKey.default
            );

          // 2. Pool configs that can only be used by specific pubkey to create pool
          const creatorPoolConfigs =
            await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
              connection,
              creator
            );

          // 3. Look for pool configs that have vault support
          const poolConfigsWithVaultSupport = [
            ...publicPoolConfigs,
            ...creatorPoolConfigs,
          ].filter((config) => config.account.vaultConfigKey != PublicKey.default);

          console.log(
            `Gotten ${poolConfigsWithVaultSupport.length} usable pool configs with vault support`
          );

          const configFuture =
            vaultMode === VaultMode.FCFS
              ? AlphaVault.getFcfsConfigs(connection)
              : AlphaVault.getProrataConfigs(connection);

          const configs = await configFuture;

          for (const programAccount of poolConfigsWithVaultSupport) {
            const { account } = programAccount;
            // 3.1 Pool activation type and duration matches
            if (
              account.activationType == activationType &&
              account.activationDuration.toNumber() >= maximumActivationDuration
            ) {
              const vaultConfig = configs.find((c) =>
                c.publicKey.equals(account.vaultConfigKey)
              );

              if (!vaultConfig) {
                continue;
              }

              const startVestingDuration =
                vaultConfig.account.startVestingDuration.toNumber();
              const endVestingDuration =
                vaultConfig.account.endVestingDuration.toNumber();

              const vestingDuration = endVestingDuration - startVestingDuration;

              // 3.2 Vault activation type, lock and vesting duration matches
              if (
                startVestingDuration >= minimumLockDuration &&
                startVestingDuration <= maximumLockDuration &&
                vestingDuration >= minimumVestingDuration &&
                vestingDuration <= maximumVestingDuration &&
                vaultConfig.account.activationType == activationType
              ) {
                return programAccount;
              }
            }
          }

          return null;
        }

        async function createDynamicPoolWithPermissionlessVault(
          connection: Connection,
          payer: Keypair
        ) {
          const { mintAInfo, mintBInfo } = await createDummyMints(connection, payer);

          // Pool and vault requirement
          const maximumActivationDuration = 86400; // 1 day
          const minimumLockDuration = 60 * 30; // 30 minutes
          const maximumLockDuration = 86400; // 1 day
          const minimumVestingDuration = 60 * 60; // 1 hour
          const maximumVestingDuration = 60 * 60 * 24 * 7; // 1 week
          const vaultMode = VaultMode.PRORATA;

          // 1. Find pool config where it allow user to create pool with customizable start trading time which start from NOW -> NOW + 24H
          // With lock duration fall between 30 minutes -> 1 days (non customizable)
          // And vesting duration fall between 1 hour -> 1 week (non customizable)
          // And prorata vault
          const poolConfig = await getPoolConfigByRequirement(
            connection,
            payer.publicKey,
            ActivationType.Timestamp,
            maximumActivationDuration,
            minimumLockDuration,
            maximumLockDuration,
            minimumVestingDuration,
            maximumVestingDuration,
            vaultMode
          );

          console.log("Got pool config");
          console.log(poolConfig);

          const clockAccount = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);
          const clock: Clock = ClockLayout.decode(clockAccount.data);

          // Pool start trade after created for 5 hour
          const activationPoint = clock.unixTimestamp.add(new BN(3600 * 5));

          // 2. Create the pool
          const transactions =
            await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
              connection,
              payer.publicKey,
              mintAInfo.mint,
              mintBInfo.mint,
              new BN(100_000_000),
              new BN(100_000_000),
              poolConfig.publicKey,
              {
                activationPoint,
              }
            );

          console.log("Creating pool");
          for (const tx of transactions) {
            const txHash = await sendAndConfirmTransaction(connection, tx, [payer]);
            console.log(txHash);
          }

          const poolPubkey = derivePoolAddressWithConfig(
            mintAInfo.mint,
            mintBInfo.mint,
            poolConfig.publicKey,
            DYNAMIC_AMM_PROGRAM_ID
          );

          console.log("Pool created", poolPubkey.toBase58());

          // 3. Create the alpha vault
          const initPermissionlessVaultTx = await AlphaVault.createPermissionlessVault(
            connection,
            {
              baseMint: mintAInfo.mint,
              quoteMint: mintBInfo.mint,
              poolType: PoolType.DYNAMIC,
              vaultMode: VaultMode.PRORATA,
              poolAddress: poolPubkey,
              config: poolConfig.account.vaultConfigKey,
            },
            payer.publicKey
          );

          console.log("Creating vault");
          const txHash = await sendAndConfirmTransaction(
            connection,
            initPermissionlessVaultTx,
            [payer]
          );
          console.log(txHash);
        }

        const connection = new Connection(clusterApiUrl("devnet"));
        const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

        /**
         * This example shows how to create dynamic pool with permissionless vault
         * Please contact meteora team if the existing pool and vault config doesn't meet the requirement
         * Currently only dynamic pool support permissionless vault
         */
        createDynamicPoolWithPermissionlessVault(connection, payer)
          .then(() => {
            console.log("Done");
          })
          .catch(console.error);
        ```

        **Note for token vesting period:**

        * `startVestingSlot = poolState.activationSlot + startVestingDuration`
        * `endVestingSlot = poolState.activationSlot + endVestingDuration`
        * `startVestingPoint`: Absolute value, the slot or timestamp that start vesting depend on the pool activation type. If no vesting is required, you should put this as 1 sec after the pool's activationPoint
        * `endVestingPoint`: Absolute value, the slot or timestamp that end vesting depend on the pool activation type. If no vesting is required, this should be the same as startVestingPoint
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="Permissioned Alpha Vault" icon="list-check">
    <Note>
      ### Main Steps

      This example demonstrates how to use the permissioned Alpha Vault to achieve authorization of user deposit with whitelisted wallet and deposit cap.

      1. Update address and deposit cap. Check `whitelist_wallet.csv`.
      2. Create a pool with permissioned vault. Check `createDynamicPoolWithPermissionedVault.ts` for more details.
      3. Generate merkle tree, and create merkle root config. Check `createMerkleRootConfig.ts` for more details.
      4. Deposit with merkle proof. Check `depositWithProof.ts` for more details.

      Whitelist CSV file example: [whitelist\_wallet.csv](https://github.com/MeteoraAg/meteora-invent/blob/main/studio/data/whitelist_wallet_example.csv)
    </Note>

    <AccordionGroup>
      <Accordion title="Create DAMM V1 Pool with Permissioned Alpha Vault">
        This example shows how to create a DAMM v1 Pool with permissioned Alpha Vault (that has a whitelist and deposit cap).

        <Warning>You have to find a pool config and vault config that meets your requirements. Please contact us on [discord](https://discord.gg/meteora) if you need new pool configs or vault configs.</Warning>

        <Note> Currently, only SOL or USDC is accepted as the quote token when initializing a DAMM v1 Pool with Alpha Vault in a permissionless setup.</Note>

        ```typescript theme={"system"}
        import {
        clusterApiUrl,
        Connection,
        Keypair,
        PublicKey,
        sendAndConfirmTransaction,
        SYSVAR_CLOCK_PUBKEY,
        } from "@solana/web3.js";
        import AlphaVault, { DYNAMIC_AMM_PROGRAM_ID, PoolType, VaultMode } from "../..";
        import AmmImpl from "@meteora-ag/dynamic-amm-sdk";
        import {
        ActivationType,
        Clock,
        ClockLayout,
        createTokenAndMint,
        loadKeypairFromFile,
        } from "../utils";
        import dotenv from "dotenv";
        import { BN } from "bn.js";
        import { derivePoolAddressWithConfig } from "@meteora-ag/dynamic-amm-sdk/dist/cjs/src/amm/utils";

        dotenv.config();

        async function createDummyMints(connection: Connection, payer: Keypair) {
        console.log("Creating mint A");
        const mintAInfo = await createTokenAndMint(
            connection,
            payer,
            6,
            100_000_000_000
        );

        console.log("Creating mint B");
        const mintBInfo = await createTokenAndMint(
            connection,
            payer,
            6,
            100_000_000_000
        );

        return {
            mintAInfo,
            mintBInfo,
        };
        }

        /**
         * @param connection
        * @param creator
        * @param activationType Pool activation based on time or slot
        * @param maximumActivationDuration Maximum duration for pool to be activation after creation
        * @param minimumLockDuration Minimum duration for bought token be locked
        * @param maximumLockDuration Maximum duration for bought token to be locked
        * @param minimumVestingDuration Minimum duration for bought token to be vested
        * @param maximumVestingDuration Maximum duration for bought token be vested
        * @param vaultMode Vault mode: fcfs or prorata
        */
        async function getPoolConfigByRequirement(
        connection: Connection,
        creator: PublicKey,
        activationType: ActivationType,
        maximumActivationDuration: number,
        minimumLockDuration: number,
        maximumLockDuration: number,
        minimumVestingDuration: number,
        maximumVestingDuration: number,
        vaultMode: VaultMode
        ) {
        // 1. Pool configs that can be used by anyone to create pool
        const publicPoolConfigs =
            await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
            connection,
            PublicKey.default
            );

        // 2. Pool configs that can only be used by specific pubkey to create pool
        const creatorPoolConfigs =
            await AmmImpl.getPoolConfigsWithPoolCreatorAuthority(
            connection,
            creator
            );

        // 3. Look for pool configs that have vault support
        const poolConfigsWithVaultSupport = [
            ...publicPoolConfigs,
            ...creatorPoolConfigs,
        ].filter((config) => config.account.vaultConfigKey != PublicKey.default);

        console.log(
            `Gotten ${poolConfigsWithVaultSupport.length} usable pool configs with vault support`
        );

        const configFuture =
            vaultMode === VaultMode.FCFS
            ? AlphaVault.getFcfsConfigs(connection)
            : AlphaVault.getProrataConfigs(connection);

        const configs = await configFuture;

        for (const programAccount of poolConfigsWithVaultSupport) {
            const { account } = programAccount;
            // 3.1 Pool activation type and duration matches
            if (
            account.activationType == activationType &&
            account.activationDuration.toNumber() >= maximumActivationDuration
            ) {
            const vaultConfig = configs.find((c) =>
                c.publicKey.equals(account.vaultConfigKey)
            );

            if (!vaultConfig) {
                continue;
            }

            const startVestingDuration =
                vaultConfig.account.startVestingDuration.toNumber();
            const endVestingDuration =
                vaultConfig.account.endVestingDuration.toNumber();

            const vestingDuration = endVestingDuration - startVestingDuration;

            // 3.2 Vault activation type, lock and vesting duration matches
            if (
                startVestingDuration >= minimumLockDuration &&
                startVestingDuration <= maximumLockDuration &&
                vestingDuration >= minimumVestingDuration &&
                vestingDuration <= maximumVestingDuration &&
                vaultConfig.account.activationType == activationType
            ) {
                return programAccount;
            }
            }
        }

        return null;
        }

        async function createDynamicPoolWithPermissionedVault(
        connection: Connection,
        payer: Keypair
        ) {
        const { mintAInfo, mintBInfo } = await createDummyMints(connection, payer);

        // Pool and vault requirement
        const maximumActivationDuration = 86400; // 1 day
        const minimumLockDuration = 60 * 30; // 30 minutes
        const maximumLockDuration = 86400; // 1 day
        const minimumVestingDuration = 60 * 60; // 1 hour
        const maximumVestingDuration = 60 * 60 * 24 * 7; // 1 week
        const vaultMode = VaultMode.PRORATA;

        // 1.Find pool config where it allow user to create pool with customizable start trading time which start from NOW -> NOW + 24H
        // With lock duration fall between 30 minutes -> 1 days (non customizable)
        // And vesting duration fall between 1 hour -> 1 week (non customizable)
        // And prorata vault
        const poolConfig = await getPoolConfigByRequirement(
            connection,
            payer.publicKey,
            ActivationType.Timestamp,
            maximumActivationDuration,
            minimumLockDuration,
            maximumLockDuration,
            minimumVestingDuration,
            maximumVestingDuration,
            vaultMode
        );

        console.log("Got pool config");
        console.log(poolConfig);

        const clockAccount = await connection.getAccountInfo(SYSVAR_CLOCK_PUBKEY);
        const clock: Clock = ClockLayout.decode(clockAccount.data);

        // Pool start trade after created for 5 hour
        const activationPoint = clock.unixTimestamp.add(new BN(3600 * 5));

        // 2. Create the pool
        const transactions =
            await AmmImpl.createPermissionlessConstantProductPoolWithConfig2(
            connection,
            payer.publicKey,
            mintAInfo.mint,
            mintBInfo.mint,
            new BN(100_000_000),
            new BN(100_000_000),
            poolConfig.publicKey,
            {
                activationPoint,
            }
            );

        console.log("Creating pool");
        for (const tx of transactions) {
            const txHash = await sendAndConfirmTransaction(connection, tx, [payer]);
            console.log(txHash);
        }

        const poolPubkey = derivePoolAddressWithConfig(
            mintAInfo.mint,
            mintBInfo.mint,
            poolConfig.publicKey,
            DYNAMIC_AMM_PROGRAM_ID
        );

        console.log("Pool created", poolPubkey.toBase58());

        // 3. Create the alpha vault
        const initPermissionlessVaultTx = await AlphaVault.createPermissionedVault(
            connection,
            {
            baseMint: mintAInfo.mint,
            quoteMint: mintBInfo.mint,
            poolType: PoolType.DYNAMIC,
            vaultMode: VaultMode.PRORATA,
            poolAddress: poolPubkey,
            config: poolConfig.account.vaultConfigKey,
            },
            payer.publicKey
        );

        console.log("Creating vault");
        const txHash = await sendAndConfirmTransaction(
            connection,
            initPermissionlessVaultTx,
            [payer]
        );
        console.log(txHash);
        }

        const connection = new Connection(clusterApiUrl("devnet"));
        const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

        /**
         * This example shows how to create dynamic pool with permissioned vault
        * Please contact meteora team if the existing pool and vault config doesn't meet the requirement
        * Currently only dynamic pool support permissioned vault
        */
        createDynamicPoolWithPermissionedVault(connection, payer)
        .then(() => {
            console.log("Done");
        })
        .catch(console.error);
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Creating a Merkle Root Config

<AccordionGroup>
  <Accordion title="Create Merkle Root Config for Permissioned Alpha Vault">
    This example shows how to create a merkle root config after generating a merkle tree, which is required to verify the whitelisted wallet address data, and enable deposits by whitelisted wallets.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "../utils";
    import { AlphaVault } from "../../alpha-vault";
    import dotenv from "dotenv";
    import { createMerkleTree, loadWhitelistWalletCsv } from "./utils";
    import { BN } from "bn.js";

    dotenv.config();

    async function createMerkleRootConfig(
    vault: PublicKey,
    csvPath: string,
    payer: Keypair
    ) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
    const alphaVault = await AlphaVault.create(connection, vault);

    // 1. Load whitelist wallet from csv file
    const whitelistWallets = await loadWhitelistWalletCsv(csvPath);
    console.log("Loaded whitelist wallets");
    console.log(whitelistWallets);

    // 2. Create merkle tree
    const tree = await createMerkleTree(connection, alphaVault, whitelistWallets);

    // 3. Create merkle root config
    // If the tree grew too large, one can partition it into multiple tree by setting different version
    const version = new BN(0);
    const createMerkleRootConfigTx = await alphaVault.createMerkleRootConfig(
        tree.getRoot(),
        version,
        payer.publicKey
    );

    // 4. Send transaction
    console.log("Sending transaction");
    const txHash = await sendAndConfirmTransaction(
        connection,
        createMerkleRootConfigTx,
        [payer]
    );
    console.log(txHash);
    }

    // Permissioned alpha vault
    const vault = new PublicKey("ARGqVVUPPqtqH9UeBHvYsv7AtZv623YdEaEziZ1pdDUs");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
    const whitelistWalletCsvFilepath =
    "src/examples/permissioned/whitelist_wallet.csv";

    /**
     * This example shows how to create merkle root config for permissioned alpha vault
     */
    createMerkleRootConfig(vault, whitelistWalletCsvFilepath, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

### Depositing into an Alpha Vault

<Tabs>
  <Tab title="Permissionless Alpha Vault" icon="people">
    <AccordionGroup>
      <Accordion title="Deposit into an Alpha Vault">
        This example shows how to deposit SOL or USDC into an Alpha Vault. Deposit can only happen before the end of the deposit period.

        ```typescript theme={"system"}
        import {
        clusterApiUrl,
        Connection,
        Keypair,
        PublicKey,
        sendAndConfirmTransaction,
        } from "@solana/web3.js";
        import { loadKeypairFromFile } from "./utils";
        import { AlphaVault } from "../alpha-vault";
        import BN from "bn.js";
        import dotenv from "dotenv";

        dotenv.config();

        async function depositToAlphaVault(
        vault: PublicKey,
        depositAmount: BN,
        payer: Keypair
        ) {
        const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

        const alphaVault = await AlphaVault.create(connection, vault);
        const depositTx = await alphaVault.deposit(depositAmount, payer.publicKey);

        console.log(`Depositing ${depositAmount.toString()}`);
        const txHash = await sendAndConfirmTransaction(connection, depositTx, [
            payer,
        ]);
        console.log(txHash);

        const escrow = await alphaVault.getEscrow(payer.publicKey);
        console.log("Escrow info");
        console.log(escrow);
        }

        // Alpha vault to be deposited to
        const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
        const depositAmount = new BN(100_000);
        const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

        /**
         * This example shows how to deposit to alpha vault. Deposit can only happen before the deposit close.
         */
        depositToAlphaVault(vault, depositAmount, payer)
        .then(() => {
            console.log("Done");
        })
        .catch(console.error);
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="Permissioned Alpha Vault" icon="list-check">
    <AccordionGroup>
      <Accordion title="Deposit into an Alpha Vault with Merkle Proof">
        This example shows how to deposit into a permissioned alpha vault using a whitelisted wallet. Deposit can only happen before the end of the deposit period.

        ```typescript theme={"system"}
        import {
        clusterApiUrl,
        Connection,
        Keypair,
        PublicKey,
        sendAndConfirmTransaction,
        } from "@solana/web3.js";
        import { loadKeypairFromFile } from "../utils";
        import { AlphaVault } from "../../alpha-vault";
        import BN from "bn.js";
        import dotenv from "dotenv";
        import Decimal from "decimal.js";
        import { deriveMerkleRootConfig } from "../../alpha-vault/helper";
        import { createMerkleTree, loadWhitelistWalletCsv } from "./utils";
        import { PROGRAM_ID } from "../../alpha-vault/constant";

        dotenv.config();

        async function depositToPermissionedAlphaVault(
        vault: PublicKey,
        depositAmount: BN,
        csvPath: string,
        payer: Keypair
        ) {
        const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
        const alphaVault = await AlphaVault.create(connection, vault);

        // 1. Load whitelisted wallet
        const whitelistedWallets = await loadWhitelistWalletCsv(csvPath);

        // 2. Create merkle tree
        const tree = await createMerkleTree(
            connection,
            alphaVault,
            whitelistedWallets
        );

        // 3. Get wallet proof info
        const depositorWhitelistInfo = whitelistedWallets.find((w) =>
            w.wallet.equals(payer.publicKey)
        );
        const quoteMint = await connection.getTokenSupply(alphaVault.vault.quoteMint);
        const toNativeAmountMultiplier = new Decimal(10 ** quoteMint.value.decimals);

        const nativeDepositCap = new BN(
            depositorWhitelistInfo.depositCap.mul(toNativeAmountMultiplier).toString()
        );

        const depositorProof = tree
            .getProof(payer.publicKey, nativeDepositCap)
            .map((buffer) => {
            return Array.from(new Uint8Array(buffer));
            });

        const [merkleRootConfig] = deriveMerkleRootConfig(
            alphaVault.pubkey,
            new BN(0),
            new PublicKey(PROGRAM_ID["mainnet-beta"])
        );

        // 4. Deposit
        const depositTx = await alphaVault.deposit(depositAmount, payer.publicKey, {
            merkleRootConfig,
            maxCap: nativeDepositCap,
            proof: depositorProof,
        });

        console.log(`Depositing ${depositAmount.toString()}`);
        const txHash = await sendAndConfirmTransaction(connection, depositTx, [
            payer,
        ]);
        console.log(txHash);

        const escrow = await alphaVault.getEscrow(payer.publicKey);
        console.log("Escrow info");
        console.log(escrow);
        }

        // Alpha vault to be deposited to
        const vault = new PublicKey("ARGqVVUPPqtqH9UeBHvYsv7AtZv623YdEaEziZ1pdDUs");
        const depositAmount = new BN(100_000);
        const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);
        const whitelistWalletCsvFilepath =
        "src/examples/permissioned/whitelist_wallet.csv";

        /**
         * This example shows how to deposit to permissioned alpha vault. Deposit can only happen before the deposit close.
         */
        depositToPermissionedAlphaVault(
        vault,
        depositAmount,
        whitelistWalletCsvFilepath,
        payer
        )
        .then(() => {
            console.log("Done");
        })
        .catch(console.error);
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Withdrawing from an Alpha Vault

<AccordionGroup>
  <Accordion title="Withdraw from an Alpha Vault">
    This example shows how to withdraw SOL or USDC from an Alpha Vault. Withdraw function only available before the end of the deposit period, and the function is applicable only when the Alpha Vault is using Pro rata mode.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import BN from "bn.js";
    import dotenv from "dotenv";

    dotenv.config();

    async function withdrawFromAlphaVault(
    vault: PublicKey,
    withdrawAmount: BN,
    payer: Keypair
    ) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);
    const withdrawTx = await alphaVault.withdraw(withdrawAmount, payer.publicKey);

    console.log(`Withdrawing ${withdrawAmount.toString()}`);
    const txHash = await sendAndConfirmTransaction(connection, withdrawTx, [
        payer,
    ]);
    console.log(txHash);

    const escrow = await alphaVault.getEscrow(payer.publicKey);
    console.log("Escrow info");
    console.log(escrow);
    }

    // Alpha vault to be withdraw from
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const withdrawAmount = new BN(100_000);
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to withdraw from an alpha vault. Withdraw can only happen before the deposit close,
     * and it applicable only when the vault is in Prorata mode.
     */
    withdrawFromAlphaVault(vault, withdrawAmount, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

<AccordionGroup>
  <Accordion title="Withdraw unused tokens from an Alpha Vault">
    This example shows how to withdraw unused SOL or USDC deposit from an Alpha Vault after the Alpha Vault has completed the purchase of tokens from the liquidity pool. This is applicable only for Alpha Vault using Pro rata mode.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import BN from "bn.js";
    import dotenv from "dotenv";

    dotenv.config();

    async function withdrawRemainingFromAlphaVault(
    vault: PublicKey,
    payer: Keypair
    ) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);
    const withdrawRemainingTx = await alphaVault.withdrawRemainingQuote(
        payer.publicKey
    );

    console.log(`Withdrawing unused fund`);
    const txHash = await sendAndConfirmTransaction(
        connection,
        withdrawRemainingTx,
        [payer]
    );
    console.log(txHash);

    const escrow = await alphaVault.getEscrow(payer.publicKey);
    console.log("Escrow info");
    console.log(escrow);
    }

    // Alpha vault to be withdraw / refund from
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to withdraw remaining unused deposit from an alpha vault after the vault done buying.
     */
    withdrawRemainingFromAlphaVault(vault, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

### Cranking an Alpha Vault

<AccordionGroup>
  <Accordion title="Cranking the Alpha Vault to buy from DAMM v1 pool">
    This example shows how to crank an Alpha Vault to purchase the base token from the liquidity pool during the crank period. Alpha Vault would purchase tokens using the SOL or USDC deposited into the Alpha Vault earlier.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import dotenv from "dotenv";
    import { PoolType } from "../alpha-vault/type";

    dotenv.config();

    async function fillVaultWithDynamicAmm(vault: PublicKey, payer: Keypair) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);

    console.log(
        "Pool type: ",
        alphaVault.vault.poolType == PoolType.DYNAMIC ? "Dynamic AMM" : "DLMM"
    );

    // Dynamic AMM require only single fill transaction
    const fillVaultWithDynamicAmmTransaction = await alphaVault.fillVault(
        payer.publicKey
    );

    console.log("Fill vault with dynamic AMM");
    const txHash = await sendAndConfirmTransaction(
        connection,
        fillVaultWithDynamicAmmTransaction,
        [payer]
    );
    console.log(txHash);
    }

    // Alpha vault to be cranked
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to crank the vault to purchase base token from the pool, with deposited token from the vault.
     */
    fillVaultWithDynamicAmm(vault, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

<AccordionGroup>
  <Accordion title="Cranking the Alpha Vault to buy from DLMM pool">
    This example shows how to crank an Alpha Vault to purchase the base token from the liquidity pool during the crank period. Alpha Vault would purchase tokens using the SOL or USDC deposited into the Alpha Vault earlier.

    Typically, we have a keeper that cranks the Alpha Vault to automatically purchase tokens from the pool. However, if the auto-crank fails, you can visit this [fillVaultDlmm.ts](https://github.com/MeteoraAg/alpha-vault-sdk/blob/main/ts-client/src/examples/fillVaultDlmm.ts) and input your PublicKey.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import dotenv from "dotenv";
    import { PoolType, VaultMode } from "../alpha-vault/type";

    dotenv.config();

    async function fillVaultWithDlmm(vault: PublicKey, payer: Keypair) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);

    console.log(
        "Pool type: ",
        alphaVault.vault.poolType == PoolType.DYNAMIC ? "Dynamic AMM" : "DLMM"
    );

    // DLMM require require one to many transactions
    while (true) {
        const fillVaultWithDLMMTransaction = await alphaVault.fillVault(
        payer.publicKey
        );

        if (!fillVaultWithDLMMTransaction) {
        // Vault bought out the whole pool and still have remaining
        break;
        }

        console.log("Fill vault with DLMM");
        const txHash = await sendAndConfirmTransaction(
        connection,
        fillVaultWithDLMMTransaction,
        [payer]
        );
        console.log(txHash);

        await alphaVault.refreshState();
        const inAmountCap =
        alphaVault.vault.vaultMode == VaultMode.FCFS
            ? alphaVault.vault.totalDeposit
            : alphaVault.vault.totalDeposit.lt(alphaVault.vault.maxBuyingCap)
            ? alphaVault.vault.totalDeposit
            : alphaVault.vault.maxBuyingCap;

        if (inAmountCap.eq(alphaVault.vault.swappedAmount)) {
        break;
        }
    }
    }

    // Alpha vault to be cranked
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to crank the vault to purchase base token from the pool, with deposited token from the vault.
     */
    fillVaultWithDlmm(vault, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

### Claiming from an Alpha Vault

<AccordionGroup>
  <Accordion title="Claiming tokens from an Alpha Vault">
    This example shows how to claim tokens from an Alpha Vault after it has purchased those tokens from the liquidity pool. Claiming can only happen after the start of the vesting period.

    <Note> **Important Reminder**: Claim start time should NOT be earlier than Pool activation time </Note>

    For a new token launch, the project should ensure that token claiming from the Alpha Vault is NOT possible before the launch pool trading activation or before the token starts trading anywhere, whether on a Dynamic AMM or DLMM Pool. If users are able to claim tokens before the launch pool/token starts trading, they may create a separate market with a price that deviates from the project's preferred launch price.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import dotenv from "dotenv";

    dotenv.config();

    async function claimBoughtTokenFromAlphaVault(
    vault: PublicKey,
    payer: Keypair
    ) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);
    const claimTx = await alphaVault.claimToken(payer.publicKey);

    console.log("Claiming bought token");
    const txHash = await sendAndConfirmTransaction(connection, claimTx, [payer]);
    console.log(txHash);

    const escrow = await alphaVault.getEscrow(payer.publicKey);
    console.log("Escrow info");
    console.log(escrow);
    }

    // Alpha vault to be deposited to
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to claim bought token from an alpha vault. Claim can only happen when the vesting start.
     */
    claimBoughtTokenFromAlphaVault(vault, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

### Close Escrow Account

<AccordionGroup>
  <Accordion title="Close Escrow Account">
    When a user deposits to the vault, it will create an escrow account, which stores the user info, such as deposit, claimed token, etc. Once user fully claims all tokens, they can close the escrow account.

    Close escrow can only happen after vesting of tokens is complete, and the escrow has claimed all the bought token. This example shows how to close an escrow account and get rental back.

    ```typescript theme={"system"}
    import {
    clusterApiUrl,
    Connection,
    Keypair,
    PublicKey,
    sendAndConfirmTransaction,
    } from "@solana/web3.js";
    import { loadKeypairFromFile } from "./utils";
    import { AlphaVault } from "../alpha-vault";
    import dotenv from "dotenv";

    dotenv.config();

    async function closeEscrow(vault: PublicKey, payer: Keypair) {
    const connection = new Connection(clusterApiUrl("devnet"), "confirmed");

    const alphaVault = await AlphaVault.create(connection, vault);
    const claimTx = await alphaVault.closeEscrow(payer.publicKey);

    console.log("Close escrow");
    const txHash = await sendAndConfirmTransaction(connection, claimTx, [payer]);
    console.log(txHash);
    }

    // Alpha vault to be deposited to
    const vault = new PublicKey("AxRoXRwQgxyaQBMwQsTRrtQ9i9Hd59BKNZBycTcYru5Z");
    const payer = loadKeypairFromFile(process.env.KEYPAIR_PATH);

    /**
     * This example shows how to close an escrow account and get rental back. Close escrow can only happen after vesting is complete, and escrow have claimed all the bought token.
     */
    closeEscrow(vault, payer)
    .then(() => {
        console.log("Done");
    })
    .catch(console.error);
    ```
  </Accordion>
</AccordionGroup>

## Configure Alpha Vault Timings

If you are integrating the Alpha Vault program and need to view and select the predefined timings for the various phases, such as:

* Deposit open time (only for FCFS mode currently)
* Deposit close time
* Vault crank/buy start time
* Vault crank/buy end time
* Withdraw unused USDC or SOL after crank is successful
* Pool Activation time
* Token claim start time
* Vesting start time
* Vesting end time

<Note>There must be a \~1 hour 5 minutes period between the deposit close time and the pool activation time. </Note>

You can use this config endpoint that has predefined timings created by Meteora.

<CardGroup cols={2}>
  <Card title="DAMM v1 Pool Config List" icon="list" href="/api-reference/fee-configs/get_fee_configs">
    View all available pool configurations for DAMM v1 Pools with Alpha Vault.
  </Card>

  <Card title="DAMM v1 Vault Config List" icon="vault" href="/api-reference/alpha-vault/get_alpha_vault_configs">
    Browse all vault configurations for DAMM v1 Pools with Alpha Vault.
  </Card>
</CardGroup>

If your preferred configs are not available in the predefined config lists above, and you want more customization, please contact the Meteora team.

## Config endpoint based on Pool Activation Timing

This config endpoint is tied to the pool activation timing, so all timings for the different Alpha Vault phases is derived from the pool activation timing.

In this example below, the claim process will start 3600 seconds (1 hour) after pool activation, and it will end 7200 seconds (2 hours) after pool activation. In other words, after the pool starts trading, tokens are locked first and released for claiming 3600 seconds (1 hour) later.

```typescript theme={"system"}
{
  maxBuyingCap: new BN(10000000),
  index,
  startVestingDuration: new BN(3600),
  endVestingDuration: new BN(7200),
  escrowFee: new BN(0),
  individualDepositingCap: new BN(50000),
  activationType: ActivationType.TIMESTAMP,
  depositingPoint: new BN(1028979080),
}
```

## Considerations for Slot Parameters

### Alpha Vault Slot Progression

```math theme={"system"}
d \rightarrow j \rightarrow p \rightarrow a \rightarrow s \rightarrow e
```

### Current Slot Condition

```math theme={"system"}
\text{current\_slot} < p
```

<Note> Alpha Vault will start to buy from the pool from pre\_activation\_slot ($p$) </Note>

### Slot Constraints

```math theme={"system"}
d + 3000 \leq j
```

```math theme={"system"}
j > \text{current\_slot}
```

```math theme={"system"}
j + 750 = p
```

```math theme={"system"}
p + 9000 = a
```

```math theme={"system"}
a < s
```

```math theme={"system"}
e \geq s
```

## User Submission Requirements

```math theme={"system"}
\{d, a, s, e\}
```

## Slot Calculation Guidelines

### Recommended Calculation Sequence

1. **Get Current Slot**
   ```math theme={"system"}
   \text{current\_slot} = \text{getCurrentSlot()}
   ```

2. **Calculate Activation Slot**
   ```math theme={"system"}
   a = \text{current\_slot} + 9000 + 750 + \text{buffer}
   ```

3. **Calculate Depositing Slot**
   ```math theme={"system"}
   d = a - 9000 - 3000 - 750 - \text{buffer}
   ```

4. **Set Vesting Slots**
   ```math theme={"system"}
   e \geq s > a
   ```

## Slot-to-Timestamp Conversion

```math theme={"system"}
3000 = 20 minutes 
```

```math theme={"system"}
750 = 5 minutes 
```

```math theme={"system"}
9000 = 1 hour
```

**Note for Quote mint:**
New endpoint only supports wSOL or USDC as Quote mint on mainnet.

Devnet has more flexibility regarding the Quote mint; please reach out to the team.

## Variable Definitions

Where:

* $d$ = depositing\_slot
* $j$ = last\_join\_slot
* $p$ = pre\_activation\_slot
* $a$ = activation\_slot
* $s$ = start\_vesting\_slot
* $e$ = end\_vesting\_slot

## Important Reminders

### A) Claim start time should NOT be earlier than Pool activation time

For a new token launch, the project should ensure that token claiming from the Alpha Vault is NOT possible before the launch pool trading activation or before the token starts trading anywhere, whether on a Dynamic AMM or DLMM Pool. If users are able to claim tokens before the launch pool/token starts trading, they may create a separate market with a price that deviates from the project's preferred launch price.

### B) For Memecoins that want to permanently lock liquidity, lock it before Pool activation time

If the Alpha Vault is used for a Memecoin launch pool, and the project wants to permanently lock liquidity in the Memecoin pool, they should ideally lock the liquidity BEFORE the pool starts trading, so that swap fees from locked liquidity are captured the second trading starts.

In a scenario where:

* The pool started trading - t0
* Liquidity gets deposited to the pool by the project, but not locked - t1
* Subsequently, that liquidity is permanently locked by the project - t2

The project will not be able to claim swap fees earned from t1 to t2, since fees from t1 to t2 are assigned to the LP token before the LP token gets permanently locked. When the LP token gets locked, the earlier fees are locked along with it.

The project will only be able to claim swap fees from locked liquidity starting from t2.

### C) Quote token must be SOL or USDC

Only SOL or USDC is accepted as the quote token when initializing a Dynamic AMM or DLMM Pool with Alpha Vault.

### D) For permissionless Alpha Vault (any wallet can deposit), is there a way to set an individual user cap?

Permissionless FCFS Alpha Vault allows you to set an individual cap, but this will be the same individual cap for everyone.

### E) If no vesting is required, what should the startVestingPoint and endVestingPoint be?

* `startVestingPoint`: Absolute value, the slot or timestamp that start vesting depend on the pool activation type. If no vesting is required, you should put this as 1 sec after the pool's `activationPoint`
* `endVestingPoint`: Absolute value, the slot or timestamp that end vesting depend on the pool activation type. If no vesting is required, this should be the same as startVestingPoint

### F) How do you determine the Alpha Vault deposit close time?

**Crank start point (time when vault buys tokens from the pool):**

* Timestamp-based: `Crank start point = activationPoint - 3600`
* Slot-based: `Crank start point = activationPoint - 9000`

**Vault deposit close point (time when vault deposits close):**

* Timestamp-based Vault: `Deposit close point = Crank start point - 5 min`
* Slot-based Vault: `Deposit close point = Crank start point - 750`

### G) How to crank the Alpha Vault so that it purchases the token from the pool?

Typically, we have a keeper that cranks the Alpha Vault to automatically purchase tokens from the pool.

However, if the auto-crank fails, you can visit this [fillVaultDlmm.ts](https://github.com/MeteoraAg/alpha-vault-sdk/blob/main/ts-client/src/examples/fillVaultDlmm.ts) repo and input your PublicKey.
