1.2.269 • Published 1 year ago

test-r-sdk v1.2.269

Weekly downloads
-
License
GPL-3.0
Repository
-
Last release
1 year ago

Raydium SDK

npm

An SDK for building applications on top of Raydium.

Installation

Yarn

$ yarn add @raydium-io/raydium-sdk

npm

$ npm install @raydium-io/raydium-sdk --save

Hosting JSON files

Tokens List

Token Icons

  • /icons/{mint}.png

Liquidity Pools List

Includes all pubkeys that build transaction need

Example of parse pool info

import { Connection, PublicKey } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import {
  TokenAccount,
  SPL_ACCOUNT_LAYOUT,
  LIQUIDITY_STATE_LAYOUT_V4,
} from "@raydium-io/raydium-sdk";
import { OpenOrders } from "@project-serum/serum";
import BN from "bn.js";

async function getTokenAccounts(connection: Connection, owner: PublicKey) {
  const tokenResp = await connection.getTokenAccountsByOwner(owner, {
    programId: TOKEN_PROGRAM_ID,
  });

  const accounts: TokenAccount[] = [];
  for (const { pubkey, account } of tokenResp.value) {
    accounts.push({
      pubkey,
      accountInfo: SPL_ACCOUNT_LAYOUT.decode(account.data),
    });
  }

  return accounts;
}

// raydium pool id can get from api: https://api.raydium.io/v2/sdk/liquidity/mainnet.json
const SOL_USDC_POOL_ID = "58oQChx4yWmvKdwLLZzBi4ChoCc2fqCUWBkwMihLYQo2";
const OPENBOOK_PROGRAM_ID = new PublicKey(
  "srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX"
);

export async function parsePoolInfo() {
  const connection = new Connection({mainnet rpc node}, "confirmed");
  const owner = new PublicKey("VnxDzsZ7chE88e9rB6UKztCt2HUwrkgCTx8WieWf5mM");

  const tokenAccounts = await getTokenAccounts(connection, owner);

  // example to get pool info
  const info = await connection.getAccountInfo(new PublicKey(SOL_USDC_POOL_ID));
  if (!info) return;

  const poolState = LIQUIDITY_STATE_LAYOUT_V4.decode(info.data);
  const openOrders = await OpenOrders.load(
    connection,
    poolState.openOrders,
    OPENBOOK_PROGRAM_ID // OPENBOOK_PROGRAM_ID(marketProgramId) of each pool can get from api: https://api.raydium.io/v2/sdk/liquidity/mainnet.json
  );

  const baseDecimal = 10 ** poolState.baseDecimal.toNumber(); // e.g. 10 ^ 6
  const quoteDecimal = 10 ** poolState.quoteDecimal.toNumber();

  const baseTokenAmount = await connection.getTokenAccountBalance(
    poolState.baseVault
  );
  const quoteTokenAmount = await connection.getTokenAccountBalance(
    poolState.quoteVault
  );

  const basePnl = poolState.baseNeedTakePnl.toNumber() / baseDecimal;
  const quotePnl = poolState.quoteNeedTakePnl.toNumber() / quoteDecimal;

  const openOrdersBaseTokenTotal =
    openOrders.baseTokenTotal.toNumber() / baseDecimal;
  const openOrdersQuoteTokenTotal =
    openOrders.quoteTokenTotal.toNumber() / quoteDecimal;

  const base =
    (baseTokenAmount.value?.uiAmount || 0) + openOrdersBaseTokenTotal - basePnl;
  const quote =
    (quoteTokenAmount.value?.uiAmount || 0) +
    openOrdersQuoteTokenTotal -
    quotePnl;

  const denominator = new BN(10).pow(poolState.baseDecimal);

  const addedLpAccount = tokenAccounts.find((a) =>
    a.accountInfo.mint.equals(poolState.lpMint)
  );

  console.log(
    "SOL_USDC pool info:",
    "pool total base " + base,
    "pool total quote " + quote,

    "base vault balance " + baseTokenAmount.value.uiAmount,
    "quote vault balance " + quoteTokenAmount.value.uiAmount,

    "base tokens in openorders " + openOrdersBaseTokenTotal,
    "quote tokens in openorders  " + openOrdersQuoteTokenTotal,

    "base token decimals " + poolState.baseDecimal.toNumber(),
    "quote token decimals " + poolState.quoteDecimal.toNumber(),
    "total lp " + poolState.lpReserve.div(denominator).toString(),

    "addedLpAmount " +
      (addedLpAccount?.accountInfo.amount.toNumber() || 0) / baseDecimal
  );
}

parsePoolInfo();

Farm/Staking Pools List

Includes all pubkeys that build transaction need

Example of parse farm info

import { Connection, PublicKey } from "@solana/web3.js";
import { Farm } from "@raydium-io/raydium-sdk";
import {
  JsonPairItemInfo,
  FarmPoolsJsonFile,
  FarmPoolJsonInfo,
  TokenInfo,
} from "./types";
import axios from "axios";
import Decimal from "decimal.js";

// raydium farm id can get from api: https://api.raydium.io/v2/sdk/farm-v2/mainnet.json
const SOL_USDC_FARM_ID = "GUzaohfNuFbBqQTnPgPSNciv3aUvriXYjQduRE3ZkqFw";

export async function demoFarm() {
  const connection = new Connection({mainnet rpc node}, "confirmed");
  const owner = new PublicKey("VnxDzsZ7chE88e9rB6UKztCt2HUwrkgCTx8WieWf5mM");

  console.log("fetching farms");
  const { data: farmData } = await axios.get<FarmPoolsJsonFile>(
    "https://api.raydium.io/v2/sdk/farm-v2/mainnet.json"
  );

  console.log("fetching pairs");
  const { data: pairData } = await axios.get<JsonPairItemInfo[]>(
    "https://api.raydium.io/v2/main/pairs"
  );

  const pairApr = Object.fromEntries(
    pairData.map((i) => [
      i.ammId,
      { apr30d: i.apr30d, apr7d: i.apr7d, apr24h: i.apr24h },
    ])
  );

  console.log("fetching liquidity");
  const { data: liquidityData } = await axios.get<{
    official: any[];
    unOfficial: any[];
  }>("https://api.raydium.io/v2/sdk/liquidity/mainnet.json");

  const allLiquidity = [...liquidityData.official, ...liquidityData.unOfficial];

  console.log("fetching token data");
  const { data: tokenData } = await axios.get<{
    official: TokenInfo[];
    unOfficial: TokenInfo[];
  }>("https://api.raydium.io/v2/sdk/token/raydium.mainnet.json");

  const allToken: Map<string, TokenInfo> = [
    ...tokenData.official,
    ...tokenData.unOfficial,
  ].reduce((acc, cur) => {
    acc.set(cur.mint, cur);
    return acc;
  }, new Map());

  console.log("fetching token prices");
  const { data: tokenPrices } = await axios.get<{ [key: string]: number }>(
    "https://api.raydium.io/v2/main/price"
  );

  console.log("fetching chain time");
  const { data: chainTimeData } = await axios.get<{
    chainTime: number;
    offset: number;
  }>("https://api.raydium.io/v2/sdk/token/raydium.mainnet.json");

  const currentBlockChainDate =
    chainTimeData.chainTime * 1000 + chainTimeData.offset * 1000;

  const allFarms: FarmPoolJsonInfo[] = Object.keys(farmData).reduce(
    // @ts-ignore
    (acc, cur) => [...acc.concat(farmData[cur])],
    []
  );

  const farmInfo = allFarms.find((farm) => farm.id === SOL_USDC_FARM_ID)!;
  const pairInfo = pairData.find((p) => p.lpMint === farmInfo.lpMint)!;
  const liquidityInfo = allLiquidity.find((p) => p.lpMint === farmInfo.lpMint)!;

  const farmInfoWithKeys = {
    ...farmInfo,
    id: new PublicKey(farmInfo.id),
    programId: new PublicKey(farmInfo.programId),
    baseMint: new PublicKey(farmInfo.baseMint),
    quoteMint: new PublicKey(farmInfo.quoteMint),
    lpMint: new PublicKey(farmInfo.lpMint),
    authority: new PublicKey(farmInfo.authority),
    lpVault: new PublicKey(farmInfo.lpVault),
    rewardInfos: farmInfo.rewardInfos.map((r) => ({
      ...r,
      rewardMint: new PublicKey(r.rewardMint),
      rewardVault: new PublicKey(r.rewardVault),
    })),
  };

  console.log("decode farm data");
  const parsedFarmInfo = (
    await Farm.fetchMultipleInfoAndUpdate({
      connection,
      pools: [farmInfoWithKeys],
      owner,
      config: { commitment: "confirmed" },
    })
  )[SOL_USDC_FARM_ID];

  const tvl = new Decimal(parsedFarmInfo.lpVault.amount.toString())
    .div(10 ** liquidityInfo.lpDecimals)
    .mul(pairInfo.lpPrice || 0);

  const samples = await connection.getRecentPerformanceSamples(4);
  const slotList = samples.map((item) => item.numSlots);
  const blockSlotCountForSecond =
    slotList.reduce((a, b) => a + b, 0) / slotList.length / 60;

  const rewardsApr = parsedFarmInfo.state.rewardInfos.map((r: any, idx) => {
    if (farmInfo.version === 6) {
      const { rewardPerSecond, rewardOpenTime, rewardEndTime, rewardMint } = r;
      const isRewardBeforeStart =
        rewardOpenTime.toNumber() * 1000 < currentBlockChainDate;
      const isRewardAfterEnd =
        rewardEndTime.toNumber() * 1000 > currentBlockChainDate;
      if (isRewardBeforeStart || isRewardAfterEnd) return 0;

      if (!rewardMint) return 0;
      const rewardPrice = tokenPrices[rewardMint.toString()] || 0;
      if (!rewardPrice) return 0;
      const rewardToken = allToken.get(rewardMint.toString())!;
      if (!rewardToken) return 0;

      const reward = new Decimal(rewardPerSecond.toString())
        .div(10 ** rewardToken.decimals)
        .mul(60 * 60 * 24 * 365)
        .mul(rewardPrice);

      const tvl = new Decimal(parsedFarmInfo.lpVault.amount.toString())
        .div(10 ** liquidityInfo.lpDecimals)
        .mul(pairInfo.lpPrice || 0);

      const apr = reward.div(tvl);

      return apr.toNumber();
    }

    const rewardMint = farmInfo.rewardInfos[idx].rewardMint;
    const rewardPrice = tokenPrices[rewardMint] || 0;
    const rewardToken = allToken.get(rewardMint)!;
    const reward = new Decimal(r.perSlotReward.toString())
      .div(10 ** rewardToken.decimals)
      .mul(blockSlotCountForSecond * 60 * 60 * 24 * 365)
      .mul(rewardPrice);

    const apr = reward.div(tvl);

    return apr.toNumber();
  });

  const totalApr24h = new Decimal(rewardsApr.reduce((acc, cur) => acc + cur, 0))
    .mul(100)
    .add(pairApr[liquidityInfo.id].apr24h);

  const userDeposited = new Decimal(
    parsedFarmInfo.ledger?.deposited.toString() || 0
  ).div(10 ** liquidityInfo.lpDecimals);

  console.log({
    userDeposited: userDeposited.toString(),
    tvl: tvl.toString(),
    totalApr24h: totalApr24h.toString(),
    rewards: rewardsApr
      .filter((apr) => apr > 0)
      .map((apr, idx) => ({
        apr: apr * 100 + "%",
        rewardToken: allToken.get(
          farmInfo.rewardInfos[idx].rewardMint ||
            // @ts-ignore
            parsedFarmInfo.state.rewardInfos[idx].rewardMint.toString()
        )!.symbol,
      })),
  });
}

demoFarm();
types
export interface JsonPairItemInfo {
  ammId: string;
  apr24h: number;
  apr7d: number;
  apr30d: number;
  fee7d: number;
  fee7dQuote: number;
  fee24h: number;
  fee24hQuote: number;
  fee30d: number;
  fee30dQuote: number;
  liquidity: number;
  lpMint: string;
  lpPrice: number | null;
  market: string;
  name: string;
  official: boolean;
  price: number;
  tokenAmountCoin: number;
  tokenAmountLp: number;
  tokenAmountPc: number;
  volume7d: number;
  volume7dQuote: number;
  volume24h: number;
  volume24hQuote: number;
  volume30d: number;
  volume30dQuote: number;
}

export interface APIRewardInfo {
  rewardMint: string;
  rewardVault: string;
  rewardOpenTime: number;
  rewardEndTime: number;
  rewardPerSecond: string | number;
  rewardSender?: string;
  rewardType: "Standard SPL" | "Option tokens";
}

export interface FarmPoolJsonInfo {
  id: string;
  lpMint: string;
  lpVault: string;

  baseMint: string;
  quoteMint: string;
  name: string;

  version: number;
  programId: string;

  authority: string;
  creator?: string;
  rewardInfos: APIRewardInfo[];
  upcoming: boolean;

  rewardPeriodMin?: number; // v6 '7-90 days's     7 * 24 * 60 * 60 seconds
  rewardPeriodMax?: number; // v6 '7-90 days's     90 * 24 * 60 * 60 seconds
  rewardPeriodExtend?: number; // v6 'end before 72h's    72 * 60 * 60 seconds

  local: boolean; // only if it is in localstorage(create just by user)
  category: "stake" | "raydium" | "fusion" | "ecosystem"; // add by UI for unify the interface
}

export type FarmPoolsJsonFile = {
  name: string;
  version: unknown;
  stake: Omit<FarmPoolJsonInfo, "category">[];
  raydium: Omit<FarmPoolJsonInfo, "category">[];
  fusion: Omit<FarmPoolJsonInfo, "category">[];
  ecosystem: Omit<FarmPoolJsonInfo, "category">[];
};

export interface TokenInfo {
  symbol: string;
  name: string;
  mint: string;
  decimals: number;
  extensions: {
    coingeckoId?: string;
  };
  icon: string;
  hasFreeze: number;
}

Program IDs

FunctionVersionMainnet
AMM / Liquidity4675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8
Farm / Staking3EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q
Farm / Staking59KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z
AMM Route1routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS
Serum39xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin

Usage

Marshmallow

Full layout type inference

npm.io npm.io

Development

yarn install && yarn install-peers

Reference

1.2.255

2 years ago

1.2.254

2 years ago

1.2.257

2 years ago

1.2.256

2 years ago

1.2.259

1 year ago

1.2.258

2 years ago

1.2.253

2 years ago

1.2.252

2 years ago

1.2.266

1 year ago

1.2.265

1 year ago

1.2.268

1 year ago

1.2.267

1 year ago

1.2.269

1 year ago

1.2.260

1 year ago

1.2.262

1 year ago

1.2.261

1 year ago

1.2.264

1 year ago

1.2.263

1 year ago

1.2.251

2 years ago

1.2.250

2 years ago

1.2.211

2 years ago

1.2.210

2 years ago

1.2.213

2 years ago

1.2.212

2 years ago

1.2.215

2 years ago

1.2.214

2 years ago

1.2.217

2 years ago

1.2.216

2 years ago

1.2.208

2 years ago

1.2.207

2 years ago

1.2.209

2 years ago

1.2.222

2 years ago

1.2.221

2 years ago

1.2.224

2 years ago

1.2.223

2 years ago

1.2.226

2 years ago

1.2.225

2 years ago

1.2.228

2 years ago

1.2.227

2 years ago

1.2.220

2 years ago

1.2.219

2 years ago

1.2.218

2 years ago

1.2.233

2 years ago

1.2.232

2 years ago

1.2.235

2 years ago

1.2.234

2 years ago

1.2.237

2 years ago

1.2.236

2 years ago

1.2.239

2 years ago

1.2.238

2 years ago

1.2.231

2 years ago

1.2.230

2 years ago

1.2.229

2 years ago

1.2.244

2 years ago

1.2.243

2 years ago

1.2.246

2 years ago

1.2.245

2 years ago

1.2.248

2 years ago

1.2.247

2 years ago

1.2.249

2 years ago

1.2.240

2 years ago

1.2.242

2 years ago

1.2.241

2 years ago

1.2.200

2 years ago

1.2.202

2 years ago

1.2.201

2 years ago

1.2.204

2 years ago

1.2.203

2 years ago

1.2.206

2 years ago

1.2.205

2 years ago

1.2.189

2 years ago

1.2.188

2 years ago

1.2.185

2 years ago

1.2.187

2 years ago

1.2.186

2 years ago

1.2.199

2 years ago

1.2.192

2 years ago

1.2.191

2 years ago

1.2.194

2 years ago

1.2.193

2 years ago

1.2.196

2 years ago

1.2.195

2 years ago

1.2.198

2 years ago

1.2.197

2 years ago

1.2.190

2 years ago

1.2.147

2 years ago

1.2.146

2 years ago

1.2.149

2 years ago

1.2.148

2 years ago

1.2.156

2 years ago

1.2.155

2 years ago

1.2.158

2 years ago

1.2.157

2 years ago

1.2.159

2 years ago

1.2.150

2 years ago

1.2.152

2 years ago

1.2.151

2 years ago

1.2.154

2 years ago

1.2.153

2 years ago

1.2.167

2 years ago

1.2.166

2 years ago

1.2.169

2 years ago

1.2.168

2 years ago

1.2.161

2 years ago

1.2.160

2 years ago

1.2.163

2 years ago

1.2.162

2 years ago

1.2.165

2 years ago

1.2.164

2 years ago

1.2.178

2 years ago

1.2.177

2 years ago

1.2.179

2 years ago

1.2.170

2 years ago

1.2.172

2 years ago

1.2.171

2 years ago

1.2.174

2 years ago

1.2.173

2 years ago

1.2.176

2 years ago

1.2.175

2 years ago

1.2.181

2 years ago

1.2.180

2 years ago

1.2.183

2 years ago

1.2.182

2 years ago

1.2.184

2 years ago

1.2.134

3 years ago

1.2.133

3 years ago

1.2.136

3 years ago

1.2.135

3 years ago

1.2.138

3 years ago

1.2.137

3 years ago

1.2.139

3 years ago

1.2.130

3 years ago

1.2.132

3 years ago

1.2.131

3 years ago

1.2.81

3 years ago

1.2.82

3 years ago

1.2.80

3 years ago

1.2.85

3 years ago

1.2.86

3 years ago

1.2.83

3 years ago

1.2.84

3 years ago

1.2.89

3 years ago

1.2.87

3 years ago

1.2.88

3 years ago

1.2.144

3 years ago

1.2.141

3 years ago

1.2.140

3 years ago

1.2.143

3 years ago

1.2.142

3 years ago

1.2.92

3 years ago

1.2.93

3 years ago

1.2.90

3 years ago

1.2.91

3 years ago

1.2.96

3 years ago

1.2.97

3 years ago

1.2.94

3 years ago

1.2.95

3 years ago

1.2.98

3 years ago

1.2.99

3 years ago

1.2.79

3 years ago

1.2.101

3 years ago

1.2.100

3 years ago

1.2.103

3 years ago

1.2.102

3 years ago

1.2.105

3 years ago

1.2.104

3 years ago

1.2.107

3 years ago

1.2.106

3 years ago

1.2.112

3 years ago

1.2.111

3 years ago

1.2.114

3 years ago

1.2.113

3 years ago

1.2.116

3 years ago

1.2.115

3 years ago

1.2.118

3 years ago

1.2.117

3 years ago

1.2.110

3 years ago

1.2.109

3 years ago

1.2.123

3 years ago

1.2.122

3 years ago

1.2.125

3 years ago

1.2.124

3 years ago

1.2.127

3 years ago

1.2.126

3 years ago

1.2.129

3 years ago

1.2.128

3 years ago

1.2.121

3 years ago

1.2.120

3 years ago

1.2.119

3 years ago

1.2.78

3 years ago

1.2.77

3 years ago

1.2.76

3 years ago

1.2.75

3 years ago

1.2.74

3 years ago

1.2.73

3 years ago

1.2.72

3 years ago

1.2.71

3 years ago

1.2.70

3 years ago

1.2.69

3 years ago

1.2.68

3 years ago

1.2.67

3 years ago

1.2.66

3 years ago

1.2.65

3 years ago

1.2.64

3 years ago

1.2.63

3 years ago

1.2.62

3 years ago

1.2.61

3 years ago

1.2.60

3 years ago

1.2.59

3 years ago

1.2.58

3 years ago

1.2.57

3 years ago

1.2.56

3 years ago

1.2.55

3 years ago

1.2.54

3 years ago

1.2.53

3 years ago

1.2.52

3 years ago

1.2.51

3 years ago

1.2.50

3 years ago

1.2.49

3 years ago

1.2.47

3 years ago

1.2.46

3 years ago

1.2.45

3 years ago

1.2.44

3 years ago

1.2.43

3 years ago

1.2.42

3 years ago

1.2.41

3 years ago

1.2.40

3 years ago

1.2.39

3 years ago

1.2.38

3 years ago

1.2.37

3 years ago

1.2.36

3 years ago

1.2.35

3 years ago

1.2.34

3 years ago

1.2.33

3 years ago

1.2.32

3 years ago

1.2.31

3 years ago

1.2.30

3 years ago

1.2.29

3 years ago

1.2.27

3 years ago

1.2.26

3 years ago

1.2.25

3 years ago

1.2.23

3 years ago

1.2.22

3 years ago

1.2.21

3 years ago

1.2.20

3 years ago

1.2.19

3 years ago

1.2.18

3 years ago

1.2.17

3 years ago

1.2.16

3 years ago

1.2.15

3 years ago

1.2.14

3 years ago

1.2.13

3 years ago

1.2.12

3 years ago

1.2.11

3 years ago

1.2.10

3 years ago

1.2.9

3 years ago

1.2.8

3 years ago

1.2.7

3 years ago

1.2.6

3 years ago

1.2.5

3 years ago

1.2.4

3 years ago

1.2.3

3 years ago

1.2.2

3 years ago

1.1.0-beta.8

3 years ago

1.1.0-beta.7

3 years ago