getDelegatorInfo
curl --request POST \
--url https://api.example.com/eth_callimport requests
url = "https://api.example.com/eth_call"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/eth_call', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/eth_call",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/eth_call"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/eth_call")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/eth_call")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body{
"status": {},
"stakeAmount": {},
"pendingRewards": {},
"joinedAt": {},
"stakerIndex": {}
}eth_* Methods
getDelegatorInfo
Get information about a delegator’s stake with a specific validator
POST
eth_call
getDelegatorInfo
curl --request POST \
--url https://api.example.com/eth_callimport requests
url = "https://api.example.com/eth_call"
response = requests.post(url)
print(response.text)const options = {method: 'POST'};
fetch('https://api.example.com/eth_call', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/eth_call",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/eth_call"
req, _ := http.NewRequest("POST", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/eth_call")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/eth_call")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
response = http.request(request)
puts response.read_body{
"status": {},
"stakeAmount": {},
"pendingRewards": {},
"joinedAt": {},
"stakerIndex": {}
}Overview
Queries the FenineSystem contract to get detailed information about a delegator’s stake with a specific validator, including stake amount, pending rewards, and position in the proximity chain.Contract Call Details
address
required
0x0000000000000000000000000000000000001000 (FenineSystem)bytes
required
Function selector:
0xa993683f + ABI-encoded (delegator address, validator address)address
required
The delegator address to query
address
required
The validator address
Response
uint8
Delegator status:
0: NOT_EXIST (never staked)1: ACTIVE (currently staking)2: UNSTAKING (withdrawal in progress)
uint256
Delegator’s stake amount in wei
uint256
Accumulated pending rewards in wei
uint256
Block number when delegator first staked
uint256
Position in validator’s proximity chain (0-based)
Examples
# Replace addresses (without 0x prefix)
curl -X POST https://rpc.fene.app \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_call",
"params": [{
"to": "0x0000000000000000000000000000000000001000",
"data": "0xa993683f000000000000000000000000<DELEGATOR_ADDRESS>000000000000000000000000<VALIDATOR_ADDRESS>"
}, "latest"],
"id": 1
}'
const Web3 = require('web3');
const web3 = new Web3('https://rpc.fene.app');
const delegatorAddress = '0x1111111111111111111111111111111111111111';
const validatorAddress = '0x2222222222222222222222222222222222222222';
// Using contract instance
const abi = JSON.parse(await web3.getSystemContractABI());
const contract = new web3.eth.Contract(
abi,
'0x0000000000000000000000000000000000001000'
);
const info = await contract.methods.getDelegatorInfo(
delegatorAddress,
validatorAddress
).call();
const DC_STATUS = ['NOT_EXIST', 'ACTIVE', 'UNSTAKING'];
console.log({
status: DC_STATUS[info.status],
stakeAmount: web3.utils.fromWei(info.stakeAmount, 'ether') + ' FEN',
pendingRewards: web3.utils.fromWei(info.pendingRewards, 'ether') + ' FEN',
joinedAt: `Block #${info.joinedAt}`,
proximityPosition: info.stakerIndex,
isActive: info.status == 1
});
const { ethers } = require('ethers');
const provider = new ethers.JsonRpcProvider('https://rpc.fene.app');
const delegatorAddress = '0x1111111111111111111111111111111111111111';
const validatorAddress = '0x2222222222222222222222222222222222222222';
const abiJson = await provider.send('fenine_getSystemContractABI', []);
const abi = JSON.parse(abiJson);
const contract = new ethers.Contract(
'0x0000000000000000000000000000000000001000',
abi,
provider
);
const [status, stakeAmount, pendingRewards, joinedAt, stakerIndex] =
await contract.getDelegatorInfo(delegatorAddress, validatorAddress);
const DC_STATUS = ['NOT_EXIST', 'ACTIVE', 'UNSTAKING'];
console.log({
status: DC_STATUS[status],
stakeAmount: ethers.formatEther(stakeAmount) + ' FEN',
pendingRewards: ethers.formatEther(pendingRewards) + ' FEN',
joinedAt: `Block #${joinedAt}`,
proximityPosition: Number(stakerIndex)
});
from web3 import Web3
w3 = Web3(Web3.HTTPProvider('https://rpc.fene.app'))
delegator_address = '0x1111111111111111111111111111111111111111'
validator_address = '0x2222222222222222222222222222222222222222'
# Using contract (assuming you have ABI)
system_contract = w3.eth.contract(
address='0x0000000000000000000000000000000000001000',
abi=system_abi
)
result = system_contract.functions.getDelegatorInfo(
delegator_address,
validator_address
).call()
status, stake_amount, pending_rewards, joined_at, staker_index = result
DC_STATUS = ['NOT_EXIST', 'ACTIVE', 'UNSTAKING']
print(f'Status: {DC_STATUS[status]}')
print(f'Stake: {Web3.from_wei(stake_amount, "ether")} FEN')
print(f'Pending: {Web3.from_wei(pending_rewards, "ether")} FEN')
print(f'Joined at block: {joined_at}')
print(f'Proximity position: {staker_index}')
Use Cases
Delegator Dashboard
Delegator Dashboard
async function getDelegatorDashboard(delegatorAddress, validatorAddress) {
const info = await contract.methods.getDelegatorInfo(
delegatorAddress,
validatorAddress
).call();
if (info.status == 0) {
return { isStaked: false };
}
// Get validator info for context
const vaInfo = await contract.methods.getValidatorInfo(validatorAddress).call();
// Calculate stake age
const currentBlock = await web3.eth.getBlockNumber();
const stakeAge = currentBlock - info.joinedAt;
const stakeDays = (stakeAge * 3) / (60 * 60 * 24); // 3s blocks
// Get estimated rewards
const estimate = await contract.methods.getEstimatedDelegatorReward(
delegatorAddress,
validatorAddress
).call();
return {
isStaked: true,
status: ['NOT_EXIST', 'ACTIVE', 'UNSTAKING'][info.status],
stake: web3.utils.fromWei(info.stakeAmount, 'ether'),
pendingRewards: web3.utils.fromWei(info.pendingRewards, 'ether'),
estimatedAfterTax: web3.utils.fromWei(estimate.afterTax, 'ether'),
proximityPosition: parseInt(info.stakerIndex),
stakeDays: stakeDays.toFixed(1),
validatorCommission: (vaInfo.commissionRate / 100) + '%'
};
}
Check Unstake Availability
Check Unstake Availability
async function canWithdraw(delegatorAddress, validatorAddress) {
const info = await contract.methods.getDelegatorInfo(
delegatorAddress,
validatorAddress
).call();
if (info.status != 2) { // Not UNSTAKING
return {
canWithdraw: false,
reason: info.status == 0 ? 'Never staked' : 'Not unstaking yet'
};
}
const currentBlock = await web3.eth.getBlockNumber();
const constants = await web3.getContractConstants();
const unlockBlock = parseInt(info.unstakeBlock) + parseInt(constants.delegatorLockPeriod);
if (currentBlock >= unlockBlock) {
return {
canWithdraw: true,
amount: web3.utils.fromWei(info.stakeAmount, 'ether')
};
}
const blocksLeft = unlockBlock - currentBlock;
const hoursLeft = (blocksLeft * 3) / 3600;
return {
canWithdraw: false,
reason: `Lock period active`,
blocksRemaining: blocksLeft,
hoursRemaining: hoursLeft.toFixed(1)
};
}
Analyze Staking History
Analyze Staking History
async function getStakingHistory(delegatorAddress) {
// Get all active validators
const validators = await contract.methods.getActiveValidators().call();
const stakingHistory = [];
for (const vaAddr of validators) {
const info = await contract.methods.getDelegatorInfo(
delegatorAddress,
vaAddr
).call();
if (info.status != 0) { // Has staked
const vaInfo = await contract.methods.getValidatorInfo(vaAddr).call();
stakingHistory.push({
validator: vaAddr,
status: ['NOT_EXIST', 'ACTIVE', 'UNSTAKING'][info.status],
stake: web3.utils.fromWei(info.stakeAmount, 'ether'),
pending: web3.utils.fromWei(info.pendingRewards, 'ether'),
joinedAt: info.joinedAt,
position: info.stakerIndex
});
}
}
return stakingHistory;
}
Proximity Position
ThestakerIndex field indicates your position in the validator’s proximity chain:
// Example
const info = await contract.methods.getDelegatorInfo(myAddress, validatorAddress).call();
const position = parseInt(info.stakerIndex);
console.log(`You are at position ${position}`);
console.log(`You receive proximity rewards from ${Math.min(position + 1, 8)} delegators below you`);
console.log(`You pay proximity rewards to ${Math.min(position, 8)} delegators above you`);
Status Lifecycle
NOT_EXIST (0)
↓ stakeToValidator()
ACTIVE (1)
↓ unstakeDelegator()
UNSTAKING (2)
↓ withdrawDelegatorStake()
NOT_EXIST (0) ← Can re-stake
Related Methods
getEstimatedDelegatorReward
Preview rewards before claiming
getValidatorStakers
See all delegators (proximity order)
getValidatorInfo
Get validator details
⌘I