AI prompts
base on An SDK for building applications on top of Raydium. # Raydium SDK
[npm-image]: https://img.shields.io/npm/v/@raydium-io/raydium-sdk.svg?style=flat
[npm-url]: https://www.npmjs.com/package/@raydium-io/raydium-sdk
[![npm][npm-image]][npm-url]
An SDK for building applications on top of Raydium.
## Installation
### Yarn
```bash
$ yarn add @raydium-io/raydium-sdk
```
### npm
```bash
$ npm install @raydium-io/raydium-sdk --save
```
## Hosting JSON files
### Tokens List
- Solana format: https://api.raydium.io/v2/sdk/token/solana.mainnet.json
- Raydium format: https://api.raydium.io/v2/sdk/token/raydium.mainnet.json
### Token Icons
- /icons/{mint}.png
### Liquidity Pools List
**_Includes all pubkeys that build transaction need_**
- https://api.raydium.io/v2/sdk/liquidity/mainnet.json
#### Example of parse pool info
```typescript
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_**
- https://api.raydium.io/v2/sdk/farm/mainnet.json
#### Example of parse farm info
```typescript
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
```typescript
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
| Function | Version | Mainnet |
| --------------- | ------- | -------------------------------------------- |
| AMM / Liquidity | 4 | 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 |
| Farm / Staking | 3 | EhhTKczWMGQt46ynNeRX1WfeagwwJd7ufHvCDjRxjo5Q |
| Farm / Staking | 5 | 9KEPoZmtHUrBbhWN1v1KWLMkkvwY6WLtAVUCPRtRjP4z |
| AMM Route | 1 | routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS |
| Serum | 3 | 9xQeWvG816bUx9EPjHmaT23yvVM2ZWbrrpZb9PusVFin |
## Usage
### Marshmallow
**_Full layout type inference_**
![](snapshots/marshmallow/1.png)
![](snapshots/marshmallow/2.png)
## Development
```
yarn install && yarn install-peers
```
## Reference
- https://github.com/ethers-io/ethers.js/tree/master/packages/bignumber
- https://github.com/pancakeswap/pancake-swap-sdk
- https://github.com/project-serum/serum-ts
- https://yarnpkg.com/advanced/lifecycle-scripts
", Assign "at most 3 tags" to the expected json: {"id":"8676","tags":[]} "only from the tags list I provide: [{"id":77,"name":"3d"},{"id":89,"name":"agent"},{"id":17,"name":"ai"},{"id":54,"name":"algorithm"},{"id":24,"name":"api"},{"id":44,"name":"authentication"},{"id":3,"name":"aws"},{"id":27,"name":"backend"},{"id":60,"name":"benchmark"},{"id":72,"name":"best-practices"},{"id":39,"name":"bitcoin"},{"id":37,"name":"blockchain"},{"id":1,"name":"blog"},{"id":45,"name":"bundler"},{"id":58,"name":"cache"},{"id":21,"name":"chat"},{"id":49,"name":"cicd"},{"id":4,"name":"cli"},{"id":64,"name":"cloud-native"},{"id":48,"name":"cms"},{"id":61,"name":"compiler"},{"id":68,"name":"containerization"},{"id":92,"name":"crm"},{"id":34,"name":"data"},{"id":47,"name":"database"},{"id":8,"name":"declarative-gui "},{"id":9,"name":"deploy-tool"},{"id":53,"name":"desktop-app"},{"id":6,"name":"dev-exp-lib"},{"id":59,"name":"dev-tool"},{"id":13,"name":"ecommerce"},{"id":26,"name":"editor"},{"id":66,"name":"emulator"},{"id":62,"name":"filesystem"},{"id":80,"name":"finance"},{"id":15,"name":"firmware"},{"id":73,"name":"for-fun"},{"id":2,"name":"framework"},{"id":11,"name":"frontend"},{"id":22,"name":"game"},{"id":81,"name":"game-engine "},{"id":23,"name":"graphql"},{"id":84,"name":"gui"},{"id":91,"name":"http"},{"id":5,"name":"http-client"},{"id":51,"name":"iac"},{"id":30,"name":"ide"},{"id":78,"name":"iot"},{"id":40,"name":"json"},{"id":83,"name":"julian"},{"id":38,"name":"k8s"},{"id":31,"name":"language"},{"id":10,"name":"learning-resource"},{"id":33,"name":"lib"},{"id":41,"name":"linter"},{"id":28,"name":"lms"},{"id":16,"name":"logging"},{"id":76,"name":"low-code"},{"id":90,"name":"message-queue"},{"id":42,"name":"mobile-app"},{"id":18,"name":"monitoring"},{"id":36,"name":"networking"},{"id":7,"name":"node-version"},{"id":55,"name":"nosql"},{"id":57,"name":"observability"},{"id":46,"name":"orm"},{"id":52,"name":"os"},{"id":14,"name":"parser"},{"id":74,"name":"react"},{"id":82,"name":"real-time"},{"id":56,"name":"robot"},{"id":65,"name":"runtime"},{"id":32,"name":"sdk"},{"id":71,"name":"search"},{"id":63,"name":"secrets"},{"id":25,"name":"security"},{"id":85,"name":"server"},{"id":86,"name":"serverless"},{"id":70,"name":"storage"},{"id":75,"name":"system-design"},{"id":79,"name":"terminal"},{"id":29,"name":"testing"},{"id":12,"name":"ui"},{"id":50,"name":"ux"},{"id":88,"name":"video"},{"id":20,"name":"web-app"},{"id":35,"name":"web-server"},{"id":43,"name":"webassembly"},{"id":69,"name":"workflow"},{"id":87,"name":"yaml"}]" returns me the "expected json"