Skip to main content
POST
eth_call
getDelegatorInfo
curl --request POST \
  --url https://api.example.com/eth_call
{
  "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

to
address
required
0x0000000000000000000000000000000000001000 (FenineSystem)
data
bytes
required
Function selector: 0xa993683f + ABI-encoded (delegator address, validator address)
delegator
address
required
The delegator address to query
validator
address
required
The validator address

Response

status
uint8
Delegator status:
  • 0: NOT_EXIST (never staked)
  • 1: ACTIVE (currently staking)
  • 2: UNSTAKING (withdrawal in progress)
stakeAmount
uint256
Delegator’s stake amount in wei
pendingRewards
uint256
Accumulated pending rewards in wei
joinedAt
uint256
Block number when delegator first staked
stakerIndex
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
  }'

Use Cases

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) + '%'
  };
}
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)
  };
}
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

The stakerIndex 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

getEstimatedDelegatorReward

Preview rewards before claiming

getValidatorStakers

See all delegators (proximity order)

getValidatorInfo

Get validator details