/Docs/Smart Contracts/Staking Contracts

Staking Contracts

The Ramestta staking system is built on a set of smart contracts deployed on the Polygon network. These contracts manage validator registration, delegation, rewards distribution, and the overall security of the network.

Contract Architecture

The staking contracts follow a proxy-upgradeable pattern for maintainability:

  • StakeManager - Main staking logic and validator management
  • ValidatorShare - Individual validator delegation pools
  • StakingInfo - Events and indexing for staking data
  • SlashingManager - Handles validator slashing
  • StakingNFT - ERC721 tokens representing validator positions

Deployed Addresses

Polygon Mainnet (Chain ID: 137)

â„šī¸Important
All staking operations happen on Polygon Mainnet, not on Ramestta. Validators stake RAMA tokens on Polygon to secure the Ramestta network.
ContractAddressDescription
StakeManagerProxy0xc032E6C4D196CBf4CceddbA1d18661F7DD57f659Main staking contract (proxy)
StakeManager (impl)0x710c591d0862d33F1dBfC8555778F23709aEA53cImplementation contract
StakeManagerExtension0xdb8Bf95B4B10c25c4eE3335d8B4d236988d53E85Extension logic
ValidatorShare0x2A53F2bb6023C262F34Ad936f10105fED67d13BBDelegation share template
ValidatorShareFactory0xD7379c8BBFBEBc743cfa0ebF398c80b39c937802Creates ValidatorShare contracts
StakingInfo0x06FB27902B00a4CCF3850783dAB763364BF8654AStaking events & indexing
StakingNFT0x108E6890F660Dbe4f3554DC43769B4D734555981Validator position NFTs
SlashingManager0xae032F1be5d139a679d975dB379E27aF2107D7D7Slashing logic
RAMA Token0x55a5CC06801bBa4C030568f1A7ee1c753FDcbe36Native staking token

StakeManager Contract

The StakeManager is the core contract handling all staking operations.

Key Functions

Staking Functionssolidity
// Stake tokens to become a validator
function stake(
    uint256 amount,
    uint256 heimdallFee,
    bool acceptDelegation,
    bytes calldata signerPubkey
) external;

// Unstake tokens (starts unbonding period)
function unstake(uint256 validatorId) external;

// Claim staked tokens after unbonding
function unstakeClaim(uint256 validatorId) external;

// Restake rewards
function restake(uint256 validatorId, uint256 amount, bool restakeRewards) external;

// Withdraw rewards
function withdrawRewards(uint256 validatorId) external;

// Update commission rate
function updateCommissionRate(uint256 validatorId, uint256 newCommissionRate) external;

// Update signer address
function updateSigner(uint256 validatorId, bytes calldata signerPubkey) external;

View Functions

Read Functionssolidity
// Get validator info
function validators(uint256 validatorId) external view returns (
    uint256 amount,
    uint256 reward,
    uint256 activationEpoch,
    uint256 deactivationEpoch,
    uint256 jailEndEpoch,
    address signer,
    address contractAddress,
    uint256 commissionRate,
    uint256 lastCommissionUpdate,
    uint256 delegatorsReward,
    uint256 delegatedAmount,
    uint256 initialRewardPerStake
);

// Get total staked
function totalStaked() external view returns (uint256);

// Get current epoch
function currentEpoch() external view returns (uint256);

// Check if validator is active
function isActiveValidator(uint256 validatorId) external view returns (bool);

ValidatorShare Contract

Each validator has a ValidatorShare contract that manages delegations.

Delegation Functionssolidity
// Buy voucher (delegate)
function buyVoucher(uint256 _amount, uint256 _minSharesToMint) external returns (uint256);

// Sell voucher (request unbond)
function sellVoucher_new(uint256 claimAmount, uint256 maximumSharesToBurn) external;

// Unstake claim (withdraw after unbonding)
function unstakeClaimTokens_new(uint256 unbondNonce) external returns (uint256);

// Withdraw rewards
function withdrawRewards() external;

// Restake rewards
function restake() external returns (uint256, uint256);

// Get liquid rewards
function getLiquidRewards(address user) external view returns (uint256);

// Get total stake
function getTotalStake(address user) external view returns (uint256, uint256);

Contract ABIs

Import ABIstypescript
import { 
  STAKE_MANAGER_ABI,
  VALIDATOR_SHARE_ABI,
  STAKING_INFO_ABI,
  SLASHING_MANAGER_ABI
} from '@ramestta/contracts';

// Or import from JSON
import StakeManagerABI from '@ramestta/contracts/abis/StakeManager.json';
import ValidatorShareABI from '@ramestta/contracts/abis/ValidatorShare.json';

Usage Examples

Check Validator Info

Read Validator Datatypescript
import { ethers } from 'ethers';
import { STAKE_MANAGER_ABI, CONTRACT_ADDRESSES } from '@ramestta/contracts';

const provider = new ethers.JsonRpcProvider('https://polygon-rpc.com');

const stakeManager = new ethers.Contract(
  CONTRACT_ADDRESSES.polygon.STAKE_MANAGER,
  STAKE_MANAGER_ABI,
  provider
);

// Get validator info
const validatorId = 1;
const validator = await stakeManager.validators(validatorId);

console.log('Validator Info:', {
  stakedAmount: ethers.formatEther(validator.amount),
  pendingRewards: ethers.formatEther(validator.reward),
  commissionRate: validator.commissionRate.toString() + '%',
  signer: validator.signer,
  delegatedAmount: ethers.formatEther(validator.delegatedAmount),
  isActive: validator.deactivationEpoch.toString() === '0'
});

Delegate to Validator

Delegate Tokenstypescript
import { ethers } from 'ethers';
import { 
  VALIDATOR_SHARE_ABI, 
  ERC20_ABI,
  CONTRACT_ADDRESSES 
} from '@ramestta/contracts';

async function delegateToValidator(
  signer: ethers.Signer,
  validatorShareAddress: string,
  amount: bigint
) {
  // First approve RAMA tokens
  const ramaToken = new ethers.Contract(
    CONTRACT_ADDRESSES.polygon.RAMA_TOKEN,
    ERC20_ABI,
    signer
  );
  
  const approveTx = await ramaToken.approve(validatorShareAddress, amount);
  await approveTx.wait();
  console.log('Approved RAMA tokens');
  
  // Buy voucher (delegate)
  const validatorShare = new ethers.Contract(
    validatorShareAddress,
    VALIDATOR_SHARE_ABI,
    signer
  );
  
  const minShares = 1; // Minimum shares to receive
  const delegateTx = await validatorShare.buyVoucher(amount, minShares);
  const receipt = await delegateTx.wait();
  
  console.log('Delegated successfully:', receipt.hash);
  return receipt;
}

// Usage
const amount = ethers.parseEther('1000'); // 1000 RAMA
await delegateToValidator(signer, '0x...validatorShareAddress', amount);

Claim Delegation Rewards

Claim Rewardstypescript
async function claimDelegationRewards(
  signer: ethers.Signer,
  validatorShareAddress: string
) {
  const validatorShare = new ethers.Contract(
    validatorShareAddress,
    VALIDATOR_SHARE_ABI,
    signer
  );
  
  // Check pending rewards
  const userAddress = await signer.getAddress();
  const rewards = await validatorShare.getLiquidRewards(userAddress);
  console.log('Pending rewards:', ethers.formatEther(rewards), 'RAMA');
  
  if (rewards > 0n) {
    const tx = await validatorShare.withdrawRewards();
    const receipt = await tx.wait();
    console.log('Rewards claimed:', receipt.hash);
    return receipt;
  }
  
  console.log('No rewards to claim');
  return null;
}

Unbond Delegation

Unbond and Withdrawtypescript
async function unbondDelegation(
  signer: ethers.Signer,
  validatorShareAddress: string,
  amount: bigint
) {
  const validatorShare = new ethers.Contract(
    validatorShareAddress,
    VALIDATOR_SHARE_ABI,
    signer
  );
  
  // Get current shares
  const userAddress = await signer.getAddress();
  const [totalStake, shares] = await validatorShare.getTotalStake(userAddress);
  
  // Calculate shares to burn
  const sharesToBurn = (shares * amount) / totalStake;
  
  // Request unbond (starts 21-day unbonding period)
  const tx = await validatorShare.sellVoucher_new(amount, sharesToBurn);
  const receipt = await tx.wait();
  
  console.log('Unbonding started:', receipt.hash);
  console.log('Tokens available after ~21 days');
  
  return receipt;
}

// After unbonding period, claim tokens
async function claimUnbondedTokens(
  signer: ethers.Signer,
  validatorShareAddress: string,
  unbondNonce: number
) {
  const validatorShare = new ethers.Contract(
    validatorShareAddress,
    VALIDATOR_SHARE_ABI,
    signer
  );
  
  const tx = await validatorShare.unstakeClaimTokens_new(unbondNonce);
  const receipt = await tx.wait();
  
  console.log('Tokens claimed:', receipt.hash);
  return receipt;
}

Events

EventDescriptionParameters
StakedNew stake addedsigner, validatorId, amount, total
UnstakedValidator unstakeduser, validatorId, amount
StakeUpdateStake amount changedvalidatorId, newAmount
RewardClaimedRewards withdrawnvalidatorId, amount
ShareMintedDelegation addedvalidatorId, user, amount, tokens
ShareBurnedDelegation removedvalidatorId, user, amount, tokens
SlashedValidator slashedvalidatorId, amount
âš ī¸Gas Costs
Staking operations are on Polygon and require POL for gas. Keep some POL in your wallet for transaction fees.
✅SDK Recommended
For easier staking operations, use the @ramestta/staking-sdk which handles all the complexity for you.

Found an issue with this page? Report on GitHub