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.