curl --request POST \
--url https://api.example.com/eth_call{
"result": {}
}Get the current epoch number
curl --request POST \
--url https://api.example.com/eth_call{
"result": {}
}0x0000000000000000000000000000000000001000 (FenineSystem)getCurrentEpoch()const Web3 = require('web3');
const web3 = new Web3('https://rpc.fene.app');
const abi = JSON.parse(await web3.getSystemContractABI());
const contract = new web3.eth.Contract(
abi,
'0x0000000000000000000000000000000000001000'
);
const epoch = await contract.methods.getCurrentEpoch().call();
console.log('Current epoch:', epoch);
// Also calculate manually from block number
const currentBlock = await web3.eth.getBlockNumber();
const EPOCH_BLOCKS = 200;
const calculatedEpoch = Math.floor(currentBlock / EPOCH_BLOCKS);
console.log('Block:', currentBlock);
console.log('Calculated epoch:', calculatedEpoch);
console.log('Match:', epoch == calculatedEpoch);
const currentBlock = await web3.eth.getBlockNumber();
const EPOCH_BLOCKS = 200;
const currentEpoch = Math.floor(currentBlock / EPOCH_BLOCKS);
const blockInEpoch = currentBlock % EPOCH_BLOCKS;
const blocksUntilNextEpoch = EPOCH_BLOCKS - blockInEpoch;
console.log({
currentBlock,
currentEpoch,
blockInEpoch,
blocksUntilNextEpoch,
estimatedTimeUntilNext: (blocksUntilNextEpoch * 3 / 60).toFixed(1) + ' minutes'
});
Monitor Epoch Transitions
async function monitorEpochTransitions() {
let lastEpoch = await contract.methods.getCurrentEpoch().call();
setInterval(async () => {
const currentEpoch = await contract.methods.getCurrentEpoch().call();
if (currentEpoch != lastEpoch) {
console.log('='.repeat(50));
console.log('NEW EPOCH:', currentEpoch);
console.log('='.repeat(50));
// Fetch updated data
const validators = await contract.methods.getActiveValidators().call();
const totalStake = await contract.methods.totalNetworkStake().call();
console.log('Active validators:', validators.length);
console.log('Total stake:', web3.utils.fromWei(totalStake, 'ether'), 'FEN');
lastEpoch = currentEpoch;
// Trigger your application logic
// e.g., refresh dashboard, recalculate rewards, etc.
}
}, 3000); // Check every block (~3s)
}
Calculate Time Until Next Epoch
async function getTimeUntilNextEpoch() {
const currentBlock = await web3.eth.getBlockNumber();
const EPOCH_BLOCKS = 200;
const BLOCK_TIME = 3; // seconds
const currentEpoch = Math.floor(currentBlock / EPOCH_BLOCKS);
const blockInEpoch = currentBlock % EPOCH_BLOCKS;
const blocksRemaining = EPOCH_BLOCKS - blockInEpoch;
const secondsRemaining = blocksRemaining * BLOCK_TIME;
const minutesRemaining = secondsRemaining / 60;
return {
currentEpoch,
currentBlock,
blockInEpoch: `${blockInEpoch}/${EPOCH_BLOCKS}`,
progress: ((blockInEpoch / EPOCH_BLOCKS) * 100).toFixed(1) + '%',
blocksRemaining,
timeRemaining: {
seconds: secondsRemaining,
minutes: minutesRemaining.toFixed(1),
formatted: `${Math.floor(minutesRemaining)}m ${secondsRemaining % 60}s`
}
};
}
Build Epoch History
async function buildEpochHistory(epochCount = 10) {
const currentEpoch = await contract.methods.getCurrentEpoch().call();
const currentBlock = await web3.eth.getBlockNumber();
const history = [];
for (let i = 0; i < epochCount; i++) {
const epoch = parseInt(currentEpoch) - i;
if (epoch < 0) break;
const epochStartBlock = epoch * 200;
const epochEndBlock = epochStartBlock + 199;
// Get block timestamps (if needed)
// const startBlockData = await web3.eth.getBlock(epochStartBlock);
history.push({
epoch,
startBlock: epochStartBlock,
endBlock: epochEndBlock,
isComplete: currentBlock > epochEndBlock,
isCurrent: epoch == currentEpoch
});
}
return history;
}
Schedule Action at Next Epoch
async function scheduleAtNextEpoch(callback) {
const currentBlock = await web3.eth.getBlockNumber();
const EPOCH_BLOCKS = 200;
const nextEpochBlock = Math.ceil(currentBlock / EPOCH_BLOCKS) * EPOCH_BLOCKS;
const blocksToWait = nextEpochBlock - currentBlock;
console.log(`Waiting ${blocksToWait} blocks until next epoch...`);
console.log(`Estimated time: ${(blocksToWait * 3 / 60).toFixed(1)} minutes`);
// Subscribe to new blocks
const subscription = web3.eth.subscribe('newBlockHeaders');
subscription.on('data', async (blockHeader) => {
if (blockHeader.number >= nextEpochBlock) {
console.log('Next epoch reached!');
subscription.unsubscribe();
await callback();
}
});
return subscription;
}
// Usage
await scheduleAtNextEpoch(async () => {
console.log('Refreshing validator data...');
const validators = await contract.methods.getActiveValidators().call();
console.log('Updated validators:', validators);
});
async function getFullEpochInfo() {
const [currentEpoch, currentBlock, constants] = await Promise.all([
contract.methods.getCurrentEpoch().call(),
web3.eth.getBlockNumber(),
web3.getContractConstants()
]);
const EPOCH_BLOCKS = constants.blockEpoch;
const blockInEpoch = currentBlock % EPOCH_BLOCKS;
const epochStartBlock = Math.floor(currentBlock / EPOCH_BLOCKS) * EPOCH_BLOCKS;
const epochEndBlock = epochStartBlock + EPOCH_BLOCKS - 1;
const nextEpochBlock = epochEndBlock + 1;
return {
current: {
epoch: currentEpoch,
block: currentBlock
},
thisEpoch: {
startBlock: epochStartBlock,
endBlock: epochEndBlock,
currentBlock: blockInEpoch,
progress: ((blockInEpoch / EPOCH_BLOCKS) * 100).toFixed(1) + '%'
},
nextEpoch: {
epoch: parseInt(currentEpoch) + 1,
startBlock: nextEpochBlock,
blocksUntil: nextEpochBlock - currentBlock,
estimatedTime: ((nextEpochBlock - currentBlock) * 3 / 60).toFixed(1) + ' minutes'
}
};
}