Skip to content

Commit

Permalink
add route swap demo
Browse files Browse the repository at this point in the history
  • Loading branch information
cruzshia committed Jun 17, 2024
1 parent a8328fa commit 50f0d05
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 16 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
src/config.ts
**/*.todo
**/*.todo
src/test/**/*
src/data/**/*
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
"description": "Raydium SDK V2 demo.",
"license": "GPL-3.0",
"dependencies": {
"@raydium-io/raydium-sdk-v2": "0.1.14-alpha",
"@raydium-io/raydium-sdk-v2": "0.1.15-alpha",
"@solana/spl-token": "^0.4.6",
"@types/jsonfile": "^6.1.4",
"bs58": "^5.0.0",
"decimal.js": "^10.4.3",
"jsonfile": "^6.1.0",
"node-cron": "^3.0.3",
"ts-node": "^10.9.1",
"typescript": "^5.3.3"
Expand Down
2 changes: 2 additions & 0 deletions src/amm/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ export const swap = async () => {
...poolInfo,
baseReserve: pool.baseReserve,
quoteReserve: pool.quoteReserve,
status: pool.status.toNumber(),
version: 4,
},
amountIn: new BN(amountIn),
mintIn: poolInfo.mintA.address, // swap mintB -> mintA, use: poolInfo.mintB.address
Expand Down
68 changes: 68 additions & 0 deletions src/cache/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { AmmPool, ClmmPool } from '@raydium-io/raydium-sdk-v2'
import { PublicKey } from '@solana/web3.js'
import jsonfile from 'jsonfile'

const filePath = './src/data/pool_data.json'

export const readCachePoolData = (cacheTime?: number) => {
let cacheData: { time: number; ammPools: AmmPool[]; clmmPools: ClmmPool[] } = {
time: 0,
ammPools: [],
clmmPools: [],
}
try {
console.log('reading cache pool data')
const data = jsonfile.readFileSync(filePath) as { time: number; ammPools: AmmPool[]; clmmPools: ClmmPool[] }
if (Date.now() - data.time > (cacheTime ?? 1000 * 60 * 10)) {
console.log('cache data expired')
return cacheData
}
cacheData.time = data.time
cacheData.ammPools = data.ammPools.map((p) => ({
...p,
id: new PublicKey(p.id),
mintA: new PublicKey(p.mintA),
mintB: new PublicKey(p.mintB),
}))
cacheData.clmmPools = data.clmmPools.map((p) => ({
...p,
id: new PublicKey(p.id),
mintA: new PublicKey(p.mintA),
mintB: new PublicKey(p.mintB),
}))
console.log('read cache pool data success')
} catch {
console.log('cannot read cache pool data')
}

return {
ammPools: cacheData.ammPools,
clmmPools: cacheData.clmmPools,
}
}

export const writeCachePoolData = (data: { ammPools: AmmPool[]; clmmPools: ClmmPool[] }) => {
console.log('caching all pool basic info..')
jsonfile
.writeFile(filePath, {
time: Date.now(),
ammPools: data.ammPools.map((p) => ({
id: p.id.toBase58(),
version: p.version,
mintA: p.mintA.toBase58(),
mintB: p.mintB.toBase58(),
})),
clmmPools: data.clmmPools.map((p) => ({
id: p.id.toBase58(),
version: p.version,
mintA: p.mintA.toBase58(),
mintB: p.mintB.toBase58(),
})),
})
.then(() => {
console.log('cache pool data success')
})
.catch((e) => {
console.log('cache pool data failed', e)
})
}
117 changes: 117 additions & 0 deletions src/trade/routeSwap.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import {
WSOLMint,
RAYMint,
USDCMint,
toFeeConfig,
toApiV3Token,
Router,
TokenAmount,
Token,
} from '@raydium-io/raydium-sdk-v2'
import { NATIVE_MINT, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token'
import { initSdk, txVersion } from '../config'
import { readCachePoolData, writeCachePoolData } from '../cache/utils'

async function routeSwap() {
const raydium = await initSdk()
await raydium.fetchChainTime()

const inputAmount = '100'
const SOL = NATIVE_MINT // or WSOLMint
const [inputMint, outputMint] = [SOL, USDCMint]
const [inputMintStr, outputMintStr] = [inputMint.toBase58(), outputMint.toBase58()]

// strongly recommend cache all pool data, it will reduce lots of data fetching time
// code below is a simple way to cache it, you can implement it with any other ways
let poolData = readCachePoolData() // initial cache time is 10 mins(1000 * 60 * 10), if wants to cache longer, set bigger number in milliseconds
if (poolData.ammPools.length === 0) {
console.log('fetching all pool basic info, this might take a while (more than 30 seconds)..')
poolData = await raydium.tradeV2.fetchRoutePoolBasicInfo()
writeCachePoolData(poolData)
}

console.log('computing swap route..')
const routes = raydium.tradeV2.getAllRoute({
inputMint,
outputMint,
...poolData,
})

const {
routePathDict,
mintInfos,
ammPoolsRpcInfo,
ammSimulateCache,
clmmPoolsRpcInfo,
computeClmmPoolInfo,
computePoolTickData,
} = await raydium.tradeV2.fetchSwapRoutesData({
routes,
inputMint,
outputMint,
})

console.log('calculating available swap routes...')
const r = raydium.tradeV2.getAllRouteComputeAmountOut({
inputTokenAmount: new TokenAmount(
new Token({
mint: inputMintStr,
decimals: mintInfos[inputMintStr].decimals,
isToken2022: mintInfos[inputMintStr].programId.equals(TOKEN_2022_PROGRAM_ID),
}),
inputAmount
),
directPath: routes.directPath.map((p) => ammSimulateCache[p.id.toBase58()] || computeClmmPoolInfo[p.id.toBase58()]),
routePathDict,
simulateCache: ammSimulateCache,
tickCache: computePoolTickData,
mintInfos: mintInfos,
outputToken: toApiV3Token({
...mintInfos[outputMintStr],
programId: mintInfos[outputMintStr].programId.toBase58(),
address: outputMintStr,
extensions: {
feeConfig: toFeeConfig(mintInfos[outputMintStr].feeConfig),
},
}),
chainTime: Math.floor(raydium.chainTimeData?.chainTime ?? Date.now() / 1000),
slippage: 0.005,
epochInfo: await raydium.connection.getEpochInfo(),
})

console.log('best swap route:', {
input: r[0].amountIn.amount.toExact(),
output: r[0].amountOut.amount.toExact(),
swapType: r[0].routeType,
route: r[0].poolInfoList.map((p) => p.id).join(' -> '),
})

console.log('fetching swap route pool keys..')
const poolKeys = await raydium.tradeV2.computePoolToPoolKeys({
pools: r[0].poolInfoList,
ammRpcData: ammPoolsRpcInfo,
clmmRpcData: clmmPoolsRpcInfo,
})

console.log('build swap tx..')
const { execute } = await raydium.tradeV2.swap({
routeProgram: Router,
txVersion,
swapInfo: r[0],
swapPoolKeys: poolKeys,
ownerInfo: {
associatedOnly: true,
checkCreateATAOwner: true,
},
computeBudgetConfig: {
units: 600000,
microLamports: 100000,
},
})

console.log('execute tx..')
const { txIds } = await execute({ sequentially: true })
console.log('txIds:', txIds)
}
/** uncomment code below to execute */
routeSwap()
Loading

0 comments on commit 50f0d05

Please sign in to comment.