Deposit

Please see for explanation of pending vs instant deposit

Short Example

import { Connection, PublicKey } from "@solana/web3.js";
import Decimal from "decimal.js";

// SOL Covered Call Volt
const voltVaultId = new PublicKey(
  "CbPemKEEe7Y7YgBmYtFaZiECrVTP5sGrYzrrrviSewKY"
);
const PROVIDER_URL = "https://api.mainnet-beta.solana.com";
const CLUSTER = "mainnet-beta";

const provider = new AnchorProvider(
  new Connection(PROVIDER_URL),
  Wallet.local(),
  {}
);
const connection = provider.connection;

const friktionSDK: FriktionSDK = new FriktionSDK({
  provider: provider,
  network: CLUSTER,
});

const user = provider.wallet.publicKey;

const depositAmount: Decimal = new Decimal(0.00001);

(async () => {
  const cVoltSDK = toConnectedSDK(
    await friktionSDK.loadVoltSDKByKey(voltVaultId),
    connection,
    user,
    // below field is only used if depositing from a PDA or other program-owned account
    undefined
  );

  await cVoltSDK.doFullDeposit(depositAmount);
})();

Full Example

import {
  FriktionSDK,
  PendingDeposit,
  toConnectedSDK,
} from "@friktion-labs/friktion-sdk";
import { TimeoutError } from "@friktion-labs/friktion-utils";
import { AnchorProvider, Wallet } from "@friktion-labs/anchor";
import {
  ASSOCIATED_TOKEN_PROGRAM_ID,
  createAssociatedTokenAccountInstruction,
  createSyncNativeInstruction,
  getAccount,
  getAssociatedTokenAddress,
  TokenAccountNotFoundError,
} from "@solana/spl-token";
import type { TransactionInstruction } from "@solana/web3.js";
import {
  Connection,
  PublicKey,
  SystemProgram,
  Transaction,
} from "@solana/web3.js";
import Decimal from "decimal.js";

// SOL Covered Call Volt
const voltVaultId = new PublicKey(
  "CbPemKEEe7Y7YgBmYtFaZiECrVTP5sGrYzrrrviSewKY"
);
const PROVIDER_URL = "https://api.mainnet-beta.solana.com";
const CLUSTER = "mainnet-beta";

const SOL_NORM_FACTOR = Math.pow(10, 9);

const provider = new AnchorProvider(
  new Connection(PROVIDER_URL),
  Wallet.local(),
  {}
);
const connection = provider.connection;

const friktionSDK: FriktionSDK = new FriktionSDK({
  provider: provider,
  network: CLUSTER,
});

const user = provider.wallet.publicKey;

(async () => {
  const cVoltSDK = toConnectedSDK(
    await friktionSDK.loadVoltSDKByKey(voltVaultId),
    connection,
    user,
    // below field is only used if depositing from a PDA or other program-owned account
    undefined
  );

  const payer = user;
  const authority = user;
  const solTransferAuthority = user;
  const voltVault = cVoltSDK.voltVault;
  const depositMint = voltVault.depositMint;
  const vaultMint = voltVault.vaultMint;

  const isWrappedSol =
    depositMint.toString() === friktionSDK.net.mints.SOL.toString();
  const depositInstructions: TransactionInstruction[] = [];

  const depositTokenAccountKey: PublicKey = await getAssociatedTokenAddress(
    depositMint,
    authority,
    true
  );
  const vaultTokenAccountKey: PublicKey = await getAssociatedTokenAddress(
    vaultMint,
    authority,
    true
  );

  const depositAmount: Decimal = new Decimal(0.00001);

  if (isWrappedSol) {
    try {
      // try to get account info
      await getAccount(connection, depositTokenAccountKey);
      const numLamports =
        (await connection.getAccountInfo(depositTokenAccountKey))?.lamports ??
        0;
      const additionalLamportsRequired = Math.max(
        depositAmount.toNumber() * SOL_NORM_FACTOR - numLamports,
        0
      );
      if (additionalLamportsRequired > 0) {
        depositInstructions.push(
          SystemProgram.transfer({
            fromPubkey: solTransferAuthority,
            toPubkey: depositTokenAccountKey,
            lamports: additionalLamportsRequired,
          })
        );
        depositInstructions.push(
          createSyncNativeInstruction(depositTokenAccountKey)
        );
      }
    } catch (err) {
      if (
        !(
          err instanceof TimeoutError ||
          err instanceof TokenAccountNotFoundError
        )
      ) {
        throw err;
      }

      depositInstructions.push(
        createAssociatedTokenAccountInstruction(
          payer,
          depositTokenAccountKey,
          authority,
          depositMint
        )
      );
      depositInstructions.push(
        SystemProgram.transfer({
          fromPubkey: solTransferAuthority,
          toPubkey: depositTokenAccountKey,
          lamports: depositAmount.toNumber() * SOL_NORM_FACTOR,
        })
      );
      depositInstructions.push(
        createSyncNativeInstruction(depositTokenAccountKey)
      );
    }
  }

  try {
    await getAccount(connection, vaultTokenAccountKey);
  } catch (err) {
    depositInstructions.push(
      createAssociatedTokenAccountInstruction(
        payer,
        vaultTokenAccountKey,
        authority,
        vaultMint
      )
    );
  }

  // if instant transfers aren't currently possible, need to handle already existing pending deposits
  if (!voltVault.instantTransfersEnabled) {
    let pendingDepositInfo: PendingDeposit | undefined;
    try {
      pendingDepositInfo = await cVoltSDK.getPendingDepositForGivenUser(
        authority
      );
    } catch (err) {
      pendingDepositInfo = undefined;
    }

    // if a pending deposit exists, need to handle it
    if (
      pendingDepositInfo &&
      pendingDepositInfo?.numUnderlyingDeposited?.gtn(0) &&
      pendingDepositInfo.roundNumber.gtn(0)
    ) {
      // if is claimable, then claim it first
      if (pendingDepositInfo.roundNumber.lt(voltVault.roundNumber)) {
        depositInstructions.push(
          await cVoltSDK.claimPendingDeposit(vaultTokenAccountKey)
        );
      }
      // else, cancel the deposit or throw an error
      else {
        depositInstructions.push(
          await cVoltSDK.cancelPendingDeposit(depositTokenAccountKey)
        );
        // if don't want to override existing deposit, can throw error instead
        // throw new Error("pending deposit already exists")
      }
    }
  }

  depositInstructions.push(
    await cVoltSDK.deposit(
      depositAmount,
      depositTokenAccountKey,
      vaultTokenAccountKey,
      authority
    )
  );

  if (isWrappedSol) {
    // OPTIONAL: close account once done with it. Don't do this by default since ATA will be useful in future
    // const closeWSolIx = createCloseAccountInstruction(
    //   depositTokenAccountKey,
    //   this.wallet, // Send any remaining SOL to the owner
    //   this.wallet,
    //   []
    // );
    // depositInstructions.push(closeWSolIx);
  }

  const transaction = new Transaction();

  for (const ix of depositInstructions) {
    transaction.add(ix);
  }

  console.log("sending transaction...");
  const txResult = await provider.sendAndConfirm(transaction);
  console.log("tx result = ", txResult);

  return txResult;
})();

Last updated