<div id="top"></div>

<!-- PROJECT LOGO -->
<br />
<div align="center">

<h3>PsyFinance SDK Documentation</h3>
<p>Last updated v1.0.6</p>
</div>

### Prerequisites

yarn

```sh
yarn add @solana/web3.js
```

### Program IDs

| Program ID | Mainnet Public Key                          | Devnet Public Key                            |
| ---------- | ------------------------------------------- | -------------------------------------------- |
| PSYFI_V2   | PSYFiYqguvMXwpDooGdYV6mju92YEbFobbvW617VNcq | 95q3X9ADJv5hWt93oSaPqABPnP1rqfmjgrnto9v83LPK |
| PSYSTAKE   | pSystkitWgLkzprdAvraP8DSBiXwee715wiSXGJe8yr | 5LrZkBFgDkFiKEePeT2N9VuKfd2k8Rrad9PG6mKGbCRk |

### Installation

```sh
yarn add @mithraic-labs/psyfi-sdk
```

### Publishing a new version

```sh
yarn publish --public
```

<p align="right">(<a href="#top">back to top</a>)</p>

<!-- USAGE EXAMPLES -->

## Usage

### Vaults Information

```
const getVaultsInfo(isMainnet: boolean);
```

### Example

```
import { getVaultsInfo } from "psyfi-sdk";

const data = await getVaultsInfo(true);
```

#### Response Scheme

```
|-- vaults
   |-- id: ID of the vault
      |-- name: Name of the vault
      |-- staking
         |-- metadata
            |-- isValuePerVaultToken: Price of each vault token
         |-- stakePoolKey: Staking Key of vault tokens
         |-- stakingApr: Annual percentage rate (0, 30, 60, 180, 360) days.
         |-- poolRewards
            |-- rewardTokensPerWeek: Amount of reward tokens given out by the vault each week.
            |-- multiplier
            |-- metadata
               |-- usdValuePerRewardToken: Price of the reward token
               |-- rewardInUsdPerYearPerRewardUnit: Number of unit rewards staker is eligible for (size of their position * lock up period selected)
               |-- rewardPoolApr: Annual percentage rate (0, 30, 60, 180, 360) days.
               |-- rewardPoolKey: Vault pool reward address
               |-- rewardMintAddress: Reward token address
               |-- tokenSymbol: Short form of the token name
               |-- poolId: Unique identifier for the pool
      |-- deposits
         |-- current: Deposit amount in vault
         |-- max: Max deposit amount for the vault
      |-- strategyType: 0 (Covered Call), 1 (Secured Put)
      |-- accounts
         |-- optionsUnderlyingMint: SPL token address used as underlying asset for options minted
         |-- collateralAssetMint:  SPL token address of asset used as collateral for options minted
         |-- feeTokenAccount: Solana account for fee collection
         |-- vaultOwnershipTokenMint: SPL token address of vault ownership token
         |-- vaultAddress: Solana account address for the vault
         |-- pythPriceOracle: Price oracle address used for settlement
      |-- status
         |-- optionsActive: If any option are minted from vault
         |-- currentEpoch: Epoch number
         |-- nextOptionMintTime: Time for next option mint
         |-- nextEpochStartTime: Next epoch start time
         |-- isDeprecated: If the vault is deprecated
      |-- visibility: 0 - production, 1 - staging, 2 - development
      |-- selectedStrike: Strike price for options minted
      |-- fees
         |-- performance: Performance fee in percentage
         |-- withdrawal: Withdrawal fee in percentage
      |-- id: Unique identifier for the vault
      |-- version: Version of the vaults
      |-- valuePerVaultToken: Current value of vault token in collateral asset
      |-- apy:
         |-- stakingApy: Apy from SOL staking (When collateral asset is a liquid staking token)
         |-- weightedApy:
            |-- targetDelta: Delta used for strike selection
            |-- epochsCounted: Number of epochs included in the calculation
            |-- apyAfterFees: Apy after fee deductions
            |-- averageSaleYield: Average yield generated from option sale
            |-- apyBeforeFees: Apy before fee deductions
            |-- averageHistoricalLoss: Average percentage loss when option expire in the money
         |-- currentEpochApy: Apy based on projected current epoch yield
         |-- movingAverageApy:
            |-- apyAfterFees: Apy after fee deductions
            |-- epochsCounted: Number of epochs included in the calculation
            |-- averageEpochYield: Average yield generated from option sale
            |-- apyBeforeFees: Apy before fee deductions
   |-- vaultHistory: Array of each epoch's history
      |-- epoch: Epoch Number
      |-- endingValuePerVaultToken: Value of token at the end of epoch in collateral asset
      |-- saleAmount: Amount option was sold for in collateral asset.
      |-- percentageLossOnCollateral: Percentage loss on collateral at the end of epoch.
      |-- epochHistoryKey: Account storing epoch history
      |-- startDate: Epoch start date
      |-- optionMinted: Formatted string of option minted with strike price
      |-- priceAtExpiry: Price of underlying at expiry
      |-- strikePrice: Strike price of option minted
      |-- overallYield: Overall yield earned from epoch
      |-- saleYield: Yield earned from option sale
```

#### Response Object

```
{
   "vaults":{
      "btc-put":{
         "name":"BTC SECURED PUT",
         "staking":{
            "metadata":{
               "usdValuePerVaultToken":0.8799150861566609
            },
            "stakePoolKey":"7waRUqnzcLopivSH3FCBrTPXij63XY4qGnFJ99XjVRaB",
            "stakingApr":[
               13.623659938287103,
               15.667208929030169,
               18.663123213214559,
               22,
               901231231232142
            ],
            "poolRewards":[
               {
                  "rewardTokensPerWeek":1470,
                  "multiplier":1,
                  "metadata":{
                     "usdValuePerRewardToken":1.051,
                     "rewardInUsdPerYearPerRewardUnit":1.1987663908366946e-7,
                     "rewardPoolApr":[
                        13.623659938287103,
                        15.667208929030169,
                        18.663123213214559,
                        22,
                        901231231232142
                     ]
                  },
                  "rewardPoolKey":"33LYcoXVPWzvj4jpihfX5bLMw4irfx614jGoeENF3VTa",
                  "rewardMintAddress":"SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt",
                  "tokenSymbol":"SRM",
                  "poolId":1
               }
            ]
         },
         "deposits":{
            "current":528072.232153,
            "max":850000
         },
         "strategyType":1,
         "accounts":{
            "optionsUnderlyingMint":"9n4nbM75f5Ui33ZbPYXn59EwSgE8CGsHtAeTH5YFeJ9E",
            "collateralAssetMint":"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "feeTokenAccount":"EfNdRWbRU6NpNd3KZq85PDsdTdsp1SBiG1S6Pebo9yA2",
            "vaultOwnershipTokenMint":"Df312h5rL4LxGBmUGvRxD1F5gTUwVbsezNKYMRQteeg4",
            "vaultAddress":"792ELQdQ6nZBSBrKjRiJXxH1ZFpNjHktnpMdp2auyXMF",
            "pythPriceOracle":"GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU"
         },
         "status":{
            "optionsActive":true,
            "currentEpoch":9,
            "nextOptionMintTime":1659083400,
            "nextEpochStartTime":1659081600,
            "isDeprecated":false
         },
         "visibility":0,
         "selectedStrike":18500,
         "fees":{
            "performance":10,
            "withdrawal":0.1
         },
         "id":"btc-put",
         "version":2,
         "valuePerVaultToken":0.8803702375694843,
         "apy":{
            "weightedApy":{
               "targetDelta":0.075,
               "epochsCounted":5,
               "apyAfterFees":9.160780173655736,
               "averageSaleYield":0.16870302234227325,
               "apyBeforeFees":10.22809414018675,
               "averageHistoricalLoss":0
            },
            "currentEpochApy":13.55016666193871,
            "stakingApy":0,
            "movingAverageApy":{
               "apyAfterFees":10.171200641996037,
               "epochsCounted":4,
               "averageEpochYield":0.20717011873986652,
               "apyBeforeFees":11.362117467964561
            }
         },
         "vaultHistory":[
            {
               "epoch":3,
               "endingValuePerVaultToken":0.862161239511,
               "saleAmount":429.3282,
               "percentageLossOnCollateral":13.997020408163266,
               "epochHistoryKey":"EfsEWATN4LL7hhMedinKxaayH4rPGzK6WhKDxMmYGYmT",
               "startDate":1654848000,
               "optionMinted":"17 JUN EXP - BTC PUT STRIKE $24500",
               "priceAtExpiry":21070.73,
               "strikePrice":24500,
               "overallYield":-13.783876048900002,
               "saleYield":0.21314435926326425
            },
            {
               "strikePrice":15000,
               "saleAmount":2437.82448,
               "optionMinted":"24 JUN EXP - BTC PUT STRIKE $15000",
               "priceAtExpiry":20911.0525,
               "epoch":4,
               "startDate":1655452800,
               "overallYield":0.8392309928133335,
               "saleYield":0.8392309928133335,
               "endingValuePerVaultToken":0.869396763841,
               "percentageLossOnCollateral":0,
               "epochHistoryKey":"68u71YZfA3msFjvRwrAKV7eC2JQstevzYyGjGs7MAWgD"
            }
         ]
      }
   }
}
```

### Retrieve wallet positions for all vaults

```
const getAllUserVaultPositions = async (
    userWallet: PublicKey,
    connection: Connection,
    isMainnet = true
)
```

### Example

```
import { getAllUserVaultPositions } from "psyfi-sdk";

const userWallet = new PublicKey(
   "Fbhqzu1S9x9dik7Sjxt3iWZbUXUU2WSfFyeqGcKuBoR7"
);
const connection = new Connection("https://ssc-dao.genesysgo.net/");
const userPosition = await getAllUserVaultPositions(
   userWallet,
   connection,
);
```

#### Response Object

```
{
    scnsol-sol-call': {
        totalUserVaultTokens: 0,
        valuePerVaultToken: 1.0251216147403115,
        rewardMultiplier: 1,
        pendingWithdrawalInVaultTokens: 0,
        claimableRewards: {
            SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt: {
                totalClaimableAmount: 0.186569,
                tokenSymbol: 'SRM',
                epochsToClaim: { '1': [Array] }
            }
        },
        vaultTokensInWallet: 0,
        vaultTokensStaked: 0,
        remainingLockupInSeconds: 0,
        vaultTokenDecimals: 9,
        pendingCollateralAssetDeposits: 0
    },
    'stsol-call': {
        totalUserVaultTokens: 8403485,
        valuePerVaultToken: 1.0251216147403115,
        rewardMultiplier: 1,
        pendingWithdrawalInVaultTokens: 0,
        claimableRewards: {
            SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt: {
                totalClaimableAmount: 0.186569,
                tokenSymbol: 'SRM',
                epochsToClaim: { '1': [Array] }
            }
        },
        vaultTokensInWallet: 0,
        vaultTokensStaked: 8403485,
        remainingLockupInSeconds: 86400, // Staked tokes are locked up 1 more day.
        vaultTokenDecimals: 9,
        pendingCollateralAssetDeposits: 0
    }
}
```

### Retrieve wallet position for a single vault

```
const getUserVaultPosition = async (
    walletAddress: PublicKey,
    vaultName: string,
    connection: Connection,
    isMainnet = true
)
```

### Example

```
import { getUserVaultPosition } from "psyfi-sdk";
import { Connection, PublicKey } from "@solana/web3.js";

const connection = new Connection("https://ssc-dao.genesysgo.net/");

const userWallet = new PublicKey(
   "Fbhqzu1S9x9dik7Sjxt3iWZbUXUU2WSfFyeqGcKuBoR7"
);

const userPosition = await getUserVaultPosition(
  userWallet,
  "sol-call",
  connection,
);

```

#### Response Object

```
 {
    totalUserVaultTokens: 8403485,
    valuePerVaultToken: 1.0251216147403115,
    rewardMultiplier: 1,
    pendingWithdrawalInVaultTokens: 0,
    claimableRewards: {
        SRMuApVNdxXokk5GT7XD5cUUgXMBCoAz2LHeuAoKWRt: {
            totalClaimableAmount: 0.186569,
            tokenSymbol: 'SRM',
            epochsToClaim: { '1': [Array] }
        }
    },
    vaultTokensInWallet: 0,
    vaultTokensStaked: 8403485,
    remainingLockupInSeconds: 0,
    vaultTokenDecimals: 9,
    pendingCollateralAssetDeposits: 0
}

```

## PDAS

### Example

```
import { pdas } from "psyfi-sdk";

const userAuthority = pdas.derivePoolAuthority();
```

### Retrieve underlying pool key

```
const deriveUnderlyingPoolKey = (underlyingMint: PublicKey)
```

### Retrieve stable pool key

```
const deriveStablePoolKey = (stableMint: PublicKey)
```

### Retrieve call option mint

```
const deriveCallOptionMint = (euroMetaKey: PublicKey)
```

### Retrieve call writer mint

```
const deriveCallWriterMint = (euroMetaKey: PublicKey)
```

### Retrieve put option mint

```
const derivePutOptionMint = (euroMetaKey: PublicKey)
```

### Retrieve put writer mint

```
const derivePutWriterMint = (euroMetaKey: PublicKey)
```

### Retrieve pool authority

```
const derivePoolAuthority();
```

### Retrieve staking record

```
const deriveStakingRecord = async (
  programId: PublicKey,
  recordOwner: PublicKey,
  stakePool: PublicKey
)
```

### Retrieve reward record

```
const deriveRewardRecord = async (
  programId: PublicKey,
  rewardPool: PublicKey,
  rewardEpoch: number
)
```

### Retrieve vault account

```
const deriveVaultAccount = async (
  programKey: PublicKey,
  collateralAssetMint: PublicKey,
  quoteAssetMint: PublicKey,
  uniqueSeed: number,
  strategyType: number
)
```

### Retrieve epoch history

```
const deriveEpochHistory = async (
  programKey: PublicKey,
  vaultAccount: PublicKey,
  epoch: number
)
```

### Retrieve vault authority

```
const deriveVaultAuthority = async (
  programKey: PublicKey,
  vaultAccount: PublicKey
)
```

#### Retrieve collateral account

```
const deriveVaultCollateralAccount = async (
  programKey: PublicKey,
  vaultAccount: PublicKey
)
```

### Retrieve vault token mint

```
const deriveVaultTokenMint = async (
  programKey: PublicKey,
  vaultAccount: PublicKey
)
```

### Retrieve vault token account

```
const deriveVaultTokenAccount = async (
  programKey: PublicKey,
  vaultAccount: PublicKey
)
```

### Retrieve withdrawal collateral account

```
const deriveWithdrawalCollateralAccount = async (
  programKey: PublicKey,
  vaultAccount: PublicKey
)
```

### Retrieve deposit receipt

```
const deriveDepositReceipt = async (
  programKey: PublicKey,
  userAuthority: PublicKey,
  vaultAccount: PublicKey,
  epoch: number
)
```

### Retrieve withdrawal receipt

```
const deriveWithdrawalReceipt = async (
  programKey: PublicKey,
  userAuthority: PublicKey,
  vaultAccount: PublicKey,
  epoch: number
)
```

### Retrieve open orders address

```
const deriveOpenOrdersAddress = async (
  serumMarket: PublicKey,
  authority: PublicKey,
  serumDexProgramKey: PublicKey
)
```

### Retrieve market authority

```
const deriveMarketAuthority = async (
  serumMarketKey: PublicKey,
  serumDexProgramKey: PublicKey
)
```

### Retrieve request queue

```
const deriveRequestQueue = (
  optionMintKey: PublicKey,
  priceCurrencyKey: PublicKey
)
```

### Retrieve coin vault

```
const deriveCoinVault = (
  optionMintKey: PublicKey,
  priceCurrencyKey: PublicKey
)
```

### Retrieve PC vault

```
const derivePCVault = (
  optionMintKey: PublicKey,
  priceCurrencyKey: PublicKey
)
```

### Retrieve serum market address

```
const deriveSerumMarketAddress = (
  optionMintKey: PublicKey,
  priceCurrencyKey: PublicKey
)
```

### Retrieve serum vault owner

```
const deriveSerumVaultOwner = async (
  serumMarket: PublicKey,
  serumDexProgramKey: PublicKey
)
```

### Retrieve active markets for vault bidding

```
const getActiveVaultMarkets = async (
    isMainnet = true
)
```

### Example

```
import { vaultBidding } from "psyfi-sdk";

const activeVaultBiddingMarkets = await vaultBidding.getActiveVaultMarkets(true);
```

#### Response Object

```
[
    {
        "isCall": true,
        "amount": 3.8,
        "serumMarketKey": "GAzxTQhujhitUt36TWkPuxxR7o9CN2qPSFMKJrgkZeCn",
        "expirationTimestamp": 1664687098000,
        "strike": 30000,
        "endTimestamp": 1664601637000,
        "collateralKey": "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF",
        "optionMintKey": "BtqTXRHhLLkqM2fibfqg4fRBpGpTXU4x8PajFpzBfoH4",
        "euroMetaAddress": "XsoQc96WEBai5TJpFFUMZEYTSBomo3YZWGZys4bciuU",
        "underlyingMint": "C6kYXcaRUMqeBF5fhg165RWU7AnpT9z92fvKNoMqjmz6",
        "stableMint": "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF"
    },
    {
        "isCall": true,
        "amount": 3.8,
        "serumMarketKey": "BnLsvJa9SmpQXqawKaR7C8mrW4EbGwqkmhfXYfpXWtTB",
        "expirationTimestamp": 1664687098000,
        "strike": 30000,
        "endTimestamp": 1664601637000,
        "euroMetaAddress": "XsoQc96WEBai5TJpFFUMZEYTSBomo3YZWGZys4bciuU",
        "collateralKey": "C6kYXcaRUMqeBF5fhg165RWU7AnpT9z92fvKNoMqjmz6",
        "optionMintKey": "BtqTXRHhLLkqM2fibfqg4fRBpGpTXU4x8PajFpzBfoH4",
        "underlyingMint": "C6kYXcaRUMqeBF5fhg165RWU7AnpT9z92fvKNoMqjmz6",
        "stableMint": "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF"
    },
    {
        "isCall": false,
        "amount": 50,
        "serumMarketKey": "BNw1rt21EZQw5KfZLaAUCAziQ9vecvMh1JNdvdz6TfHW",
        "expirationTimestamp": 1672387300000,
        "strike": 20,
        "endTimestamp": 1672387200000,
        "collateralKey": "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF",
        "optionMintKey": "58nC3yncBnir2p9CDeAPzezR9rfVmmzpWym53svxeTq6",
        "euroMetaAddress": "3CykuF8d1FrQYTfANZzZSCmmQUdkkJFj7ZZzTdxpwS7o",
        "underlyingMint": "So11111111111111111111111111111111111111112",
        "stableMint": "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF"
    }
]
```

### Place bid for an active vault bidding market

```
const placeBid = async (
  euroMetaAddress: string,
  collateralKey: string,
  optionMintKey: string,
  price: number,
  size: number,
  wallet: AnchorWallet,
  isMainnet: boolean,
)
```

### Example

```
import { vaultBidding } from "psyfi-sdk";
import { useAnchorWallet } from '@solana/wallet-adapter-react';

const wallet = useAnchorWallet();

await vaultBidding.placeBid(
   "3CykuF8d1FrQYTfANZzZSCmmQUdkkJFj7ZZzTdxpwS7o", // euroMeta address
   "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF", // collateralKey
   "58nC3yncBnir2p9CDeAPzezR9rfVmmzpWym53svxeTq6", // optionMintKey
   200, // price per contract
   2, // contract quantity
   wallet,
   true // mainnet
)
```

#### Response Object

Calling the function will prompt the user to sign the transaction with their connected wallet
Once the transaction is confirmed, the function returns the transaction signature:

```
   "3Nhc34rD1aiZNj6XHjVezXp9anPumDhm9ZErFSsEp3SfwPgds94Sjnb3ugUzdDjF425KsDxi16sZ1uGh9Dcspbkp"
```

### Cancel all bids for vault bidding market

```
const cancelAllBidsForMarket = async (
  serumMarketKey: string,
  euroMetaAddress: string,
  collateralKey: string,
  optionMintKey: string
  wallet: AnchorWallet,
  isMainnet = true,
)
```

### Example

```
import { vaultBidding } from "psyfi-sdk";
import { useAnchorWallet } from '@solana/wallet-adapter-react';

const wallet = useAnchorWallet();

await vaultBidding.cancelAllBidsForMarket(
   "BNw1rt21EZQw5KfZLaAUCAziQ9vecvMh1JNdvdz6TfHW",
   "3CykuF8d1FrQYTfANZzZSCmmQUdkkJFj7ZZzTdxpwS7o",
   "E6Z6zLzk8MWY3TY8E87mr88FhGowEPJTeMWzkqtL6qkF",
   "58nC3yncBnir2p9CDeAPzezR9rfVmmzpWym53svxeTq6"
   wallet,
   false,
)
```

#### Response Object

Calling the function will prompt the user to sign the transaction with their connected wallet
Once the transaction is confirmed, the function returns the transaction signature:

```
   "3Nhc34rD1aiZNj6XHjVezXp9anPumDhm9ZErFSsEp3SfwPgds94Sjnb3ugUzdDjF425KsDxi16sZ1uGh9Dcspbkp"
```

<!--
### Retrieve user stake positions

```
const getUserStakePosition = async (
  psyStakeProgramKey: PublicKey,
  walletAddress: PublicKey,
  stakePool: PublicKey,
  connection: Connection
)
```

### Example

```
import {
  getVaultsInfo,
  getUserStakePosition,
} from "psyfi-sdk";
import { Connection, PublicKey } from "@solana/web3.js";

const vaults = await getVaultsInfo();
const vault = Object.values(vaults)[0]["sol-call"];

const userWallet = new PublicKey(
  "Fbhqzu1S9x9dik7Sjxt3iWZbUXUU2WSfFyeqGcKuBoR7"
);
const connection = new Connection("https://ssc-dao.genesysgo.net/");

const PSYSTAKE = new PublicKey("pSystkitWgLkzprdAvraP8DSBiXwee715wiSXGJe8yr");
const stakePoolKey = new PublicKey(vault.staking.stakePoolKey);

const stakePosition = await getUserStakePosition(
  PSYSTAKE,
  userWallet,
  stakePoolKey,
  connection
);
```

#### Response Object

```
{
  stakePool: PublicKey(d8e78c3f04077d1df28af446e04940f608d735cc0ed1a02fcbb25b2a8c33ee3e),
  recordOwner: PublicKey(d8e78c3f04077d1df28af446e04940f608d735cc0ed1a02fcbb25b2a8c33ee3e),
  stakedAmount: 0,
  rewardUnits: 0,
  lockUpExpiry: 0,
  lastEpochClaimedVec: [0,0],
  remainingLockupInSeconds: 0,
  recordBump: 253
}
``` -->

<p align="right">(<a href="#top">back to top</a>)</p>
