Below are the common methods to track updates in liquidity reserve balances:
For production environments, itโs highly recommended to use a paid Mirror Node provider for commercial and high-traffic purposes. While Hederaโs public mirror node offers free REST API and JSON API endpoints, they have global rate limits. These are best suited for development or low rate usage scenarios.
Polling Sync Events for all Pools
โฝ No gas cost
Whenever the reserve values for a pool contract are updated, either due to liquidity changes or a swap, a Sync event is emitted from the contract, containing the updated reserve values for the token pair. The following code demonstrates how to listen for Sync events for all pools using REST API or JSON RPC.
Listening to โSyncโ events without specifying an address in the filter data will return logs for all pools on SaucerSwap, as well as other DEXs on Hedera that share the same โtopic0โ hash signature for the โSyncโ event. To identify and filter specific pools, extract the poolโs EVM address from the log.
Resources:
import * as ethers from 'ethers'; //V6
//Set one of Hedera's JSON RPC Relay as the provider
const provider = new ethers.JsonRpcProvider(hederaJsonRelayUrl, '', {
batchMaxCount: 1, //workaround for V6
});
//load ABI data containing the Sync event
const abiInterface = new ethers.Interface(abi);
const filter = {
topics: [interfaces.getEvent('Sync')!.topicHash], //topic0 filter
fromBlock: fromBlock,
toBlock: toBlock,
};
const logs = await provider.getLogs(filter);
for (const log of logs) {
const parsedLog = interfaces.parseLog({ topics: log.topics.slice(), data: log.data });
const {reserve0, reserve1} = parsedLog!.args; //reserve values in smallest unit
const poolAddress = log.address;
console.log(`Pool: ${poolAddress}, reserve0: ${reserve0}, reserve1: ${reserve1}`);
});
Resources:
import * as ethers from 'ethers'; //V6
//Set one of Hedera's JSON RPC Relay as the provider
const provider = new ethers.JsonRpcProvider(hederaJsonRelayUrl, '', {
batchMaxCount: 1, //workaround for V6
});
//load ABI data containing the Sync event
const abiInterface = new ethers.Interface(abi);
const filter = {
topics: [interfaces.getEvent('Sync')!.topicHash], //topic0 filter
fromBlock: fromBlock,
toBlock: toBlock,
};
const logs = await provider.getLogs(filter);
for (const log of logs) {
const parsedLog = interfaces.parseLog({ topics: log.topics.slice(), data: log.data });
const {reserve0, reserve1} = parsedLog!.args; //reserve values in smallest unit
const poolAddress = log.address;
console.log(`Pool: ${poolAddress}, reserve0: ${reserve0}, reserve1: ${reserve1}`);
});
Resources:
import * as ethers from 'ethers'; //V6
//load ABI data containing the Sync event
const interfaces = new ethers.Interface(abi);
let params = `timestamp=gte:${unixFrom}×tamp=lte:${unixTo}`;
params += `&topic0=${interfaces.getEvent('Sync')!.topicHash}`;
const url = `${mirrorNodeBaseUrl}/api/v1/contracts/results/logs?${params}`;
const response = await axios.get(url);
const logs = response.data.logs;
for (const log of logs) {
const {reserve0, reserve1} = interfaces.decodeEventLog('Sync', log.data);
console.log(`Pair: ${log.address}, reserve0: ${reserve0}, reserve1: ${reserve1}`);
}
Polling Sync Events for a Pool
โฝ No gas cost
Whenever the reserve values for a pool contract are updated, either due to liquidity changes or a swap, a Sync event is emitted from the contract, containing the updated reserve values for the token pair. The following code demonstrates how to listen for Sync events for a specific pool using REST API or JSON RPC.
Resources:
import * as ethers from 'ethers'; //V6
//Set one of Hedera's JSON RPC Relay as the provider
const provider = new ethers.JsonRpcProvider(hederaJsonRelayUrl, '', {
batchMaxCount: 1, //workaround for V6
});
//load ABI data containing the Sync event
const interfaces = new ethers.Interface(abi);
const filter = {
topics: [interfaces.getEvent('Sync')!.topicHash], //topic0 filter
fromBlock: fromBlock,
toBlock: toBlock,
address: poolEvmAddress, //pool address starting with 0x
};
const logs = await provider.getLogs(filter);
for (const log of logs) {
const parsedLog = interfaces.parseLog({ topics: log.topics.slice(), data: log.data });
const {reserve0, reserve1} = parsedLog!.args; //reserve values in smallest unit
const poolAddress = log.address;
console.log(`reserve0: ${reserve0}, reserve1: ${reserve1}`);
});
Resources:
import * as ethers from 'ethers'; //V6
//Set one of Hedera's JSON RPC Relay as the provider
const provider = new ethers.JsonRpcProvider(hederaJsonRelayUrl, '', {
batchMaxCount: 1, //workaround for V6
});
//load ABI data containing the Sync event
const interfaces = new ethers.Interface(abi);
const filter = {
topics: [interfaces.getEvent('Sync')!.topicHash], //topic0 filter
fromBlock: fromBlock,
toBlock: toBlock,
address: poolEvmAddress, //pool address starting with 0x
};
const logs = await provider.getLogs(filter);
for (const log of logs) {
const parsedLog = interfaces.parseLog({ topics: log.topics.slice(), data: log.data });
const {reserve0, reserve1} = parsedLog!.args; //reserve values in smallest unit
const poolAddress = log.address;
console.log(`reserve0: ${reserve0}, reserve1: ${reserve1}`);
});
Resources:
import * as ethers from 'ethers'; //V6
//load ABI data containing the Sync event
const interfaces = new ethers.Interface(abi);
let params = `timestamp=gte:${unixFrom}×tamp=lte:${unixTo}`;
params += `&topic0=${interfaces.getEvent('Sync')!.topicHash}`;
const url = `${mirrorNodeBaseUrl}/api/v1/contracts/${contractIdEvm}/results/logs?${params}`;
const response = await axios.get(url);
const logs = response.data.logs;
for (const log of logs) {
const {reserve0, reserve1} = interfaces.decodeEventLog('Sync', log.data);
console.log(`reserve0: ${reserve0}, reserve1: ${reserve1}`);
}