Overview
Decentralized Exchanges (DEXs) on Solana generate significant transaction volume and complex interactions that can be challenging to analyze.
In this Function example, we will get the DEX analytics data by aggregating key metrics across major DEX protocols, including Phoenix, Raydium, and Jupiter.
Sample Function
The following is the code for the Function to get the Solana DEX analytics data in JavaScript Node.js v20
runtime using the Programs with logs dataset:
// Initialize the main function
function main(params) {
const dataset = params.metadata.dataset
const network = params.metadata.network
// Define relevant DEX program IDs found in the data
const DEX_PROGRAMS = {
PHOENIX: 'PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY',
RAYDIUM_CLM: '675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8',
JUPITER: 'JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4',
}
let metrics = {
message: `DEX analysis from the ${dataset} dataset on the ${network} network.`,
blockTime: 0,
slot: 0,
// Program-specific metrics - standardized across all DEXs
programs: {
[DEX_PROGRAMS.PHOENIX]: {
name: 'Phoenix',
invocations: 0,
transactions: 0,
valueChange: 0,
uniqueUsers: new Set(),
successfulTxs: 0,
failedTxs: 0,
},
[DEX_PROGRAMS.RAYDIUM_CLM]: {
name: 'Raydium CLM',
invocations: 0,
transactions: 0,
valueChange: 0,
uniqueUsers: new Set(),
successfulTxs: 0,
failedTxs: 0,
},
[DEX_PROGRAMS.JUPITER]: {
name: 'Jupiter',
invocations: 0,
transactions: 0,
valueChange: 0,
uniqueUsers: new Set(),
successfulTxs: 0,
failedTxs: 0,
},
},
// Aggregated metrics
totalDexTransactions: 0,
totalValueChange: 0,
}
// Process each transaction
if (!Array.isArray(params.data?.[0])) {
return metrics
}
const transactions = params.data[0]
transactions.forEach(tx => {
// Update block info
metrics.blockTime = tx.blockTime
metrics.slot = tx.slot
// Track which DEX programs were involved in this transaction
const involvedPrograms = new Set()
// Analyze program invocations
tx.programInvocations?.forEach(invocation => {
const programId = invocation.programId
if (metrics.programs[programId]) {
const program = metrics.programs[programId]
program.invocations++
involvedPrograms.add(programId)
// Track value changes
const accounts = invocation.instruction.accounts || []
const valueChange = accounts.reduce((sum, acc) => {
return sum + (acc.postBalance - acc.preBalance)
}, 0)
program.valueChange += valueChange
metrics.totalValueChange += valueChange
// Track unique users from accounts
accounts.forEach(acc => {
program.uniqueUsers.add(acc.pubkey)
})
}
})
// For each involved program in this transaction
involvedPrograms.forEach(programId => {
const program = metrics.programs[programId]
program.transactions++
metrics.totalDexTransactions++
// Look for program-specific success in the logs
let programSuccess = false
if (Array.isArray(tx.logs)) {
const programLogs = tx.logs.filter(
log =>
log.includes(programId) ||
(programId === DEX_PROGRAMS.PHOENIX && log.includes('Phoenix')) ||
(programId === DEX_PROGRAMS.JUPITER && log.includes('Jupiter')) ||
(programId === DEX_PROGRAMS.RAYDIUM_CLM && log.includes('ray_log'))
)
programSuccess = programLogs.some(
log =>
log.includes('success') ||
log.includes('succeeded') ||
(programId === DEX_PROGRAMS.PHOENIX &&
log.includes('market events')) ||
(programId === DEX_PROGRAMS.JUPITER && log.includes('Route')) ||
(programId === DEX_PROGRAMS.RAYDIUM_CLM && log.includes('ray_log'))
)
}
if (programSuccess) {
program.successfulTxs++
} else {
program.failedTxs++
}
})
})
// Calculate final metrics
for (const [programId, data] of Object.entries(metrics.programs)) {
// Calculate user counts
data.uniqueUserCount = data.uniqueUsers.size
delete data.uniqueUsers
// Calculate transaction share
data.transactionShare =
metrics.totalDexTransactions > 0
? ((data.transactions / metrics.totalDexTransactions) * 100).toFixed(
2
) + '%'
: '0%'
// Format value changes to be more readable
data.valueChange = (data.valueChange / 1e9).toFixed(4) + ' SOL'
// Add success rate
data.successRate =
data.transactions > 0
? ((data.successfulTxs / data.transactions) * 100).toFixed(2) + '%'
: '0%'
}
metrics.totalValueChange =
(metrics.totalValueChange / 1e9).toFixed(4) + ' SOL'
return metrics
}
Request
We will invoke the function with the following cURL command. A few notes:
- Replace the YOUR_API_KEY with your own QuickNode API key - follow this guide for creating an API key.
- Replace the FUNCTION_ID with the ID of your Function - you can find this in the URL when viewing your Function in the QuickNode Dashboard.
- Use the block_number parameter to specify the block number you want to analyze. You can also omit this property for the function to run against the latest block.
curl -X POST "https://api.quicknode.com/functions/rest/v1/functions/FUNCTION_ID/call?result_only=true" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"network": "solana-mainnet",
"dataset": "programs_with_logs",
"block_number": 309999709
}'
Response
Resulting in the following response:
{
"message": "DEX analysis from the programs_with_logs dataset on the solana-mainnet network.",
"blockTime": 1735247138,
"slot": 309999709,
"programs": {
"PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY": {
"name": "Phoenix",
"invocations": 42,
"transactions": 17,
"valueChange": "-0.0005 SOL",
"successfulTxs": 17,
"failedTxs": 0,
"uniqueUserCount": 86,
"transactionShare": "5.86%",
"successRate": "100.00%"
},
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8": {
"name": "Raydium CLM",
"invocations": 41,
"transactions": 41,
"valueChange": "-0.0648 SOL",
"successfulTxs": 41,
"failedTxs": 0,
"uniqueUserCount": 236,
"transactionShare": "14.14%",
"successRate": "100.00%"
},
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4": {
"name": "Jupiter",
"invocations": 235,
"transactions": 232,
"valueChange": "2.4327 SOL",
"successfulTxs": 232,
"failedTxs": 0,
"uniqueUserCount": 679,
"transactionShare": "80.00%",
"successRate": "100.00%"
}
},
"totalDexTransactions": 290,
"totalValueChange": "2.3673 SOL"
}
Learn more about QuickNode Functions.
We ❤️ Feedback!
Let us know if you have any feedback or requests for new topics. We'd love to hear from you.