Staking Interfaces
Welcome to the 0G Chain Staking Interfaces documentation. This guide provides comprehensive information about interacting with the 0G Chain staking system through smart contracts, enabling you to build applications that leverage validator operations and delegations.
Overview
The 0G Chain staking system enables OG token holders to participate in network consensus and earn rewards through two primary mechanisms:
- Becoming a Validator: Run infrastructure to validate transactions and produce blocks
- Delegating to Validators: Stake tokens with existing validators to earn rewards without running infrastructure
The staking system is built on two core smart contract interfaces:
IStakingContract
: Central registry managing validators and global staking parametersIValidatorContract
: Individual validator operations including delegations and reward distribution
Prerequisites
Before working with the staking interfaces:
- Familiarity with Solidity and smart contract development
- Basic knowledge of consensus mechanisms and staking concepts
Quick Start
// Create a validator
IStakingContract staking = IStakingContract(0xea224dBB52F57752044c0C86aD50930091F561B9);
address validator = staking.createAndInitializeValidatorIfNecessary{value: msg.value}(
description, commissionRate, withdrawalFee, pubkey, signature
);
// Delegate to validator
IValidatorContract(validator).delegate{value: msg.value}(msg.sender);
Core Concepts
Validators
Validators process transactions and produce blocks:
- Unique Identity: Identified by 48-byte consensus public key
- Operator Control: Managed by an Ethereum address
- Commission: Set their own reward commission rates
- Self-Delegation: Required minimum stake from operator
Delegations
Token holders earn rewards by delegating to validators:
- Share-Based: Delegations represented as shares in validator pool
- Proportional Rewards: Earnings based on share percentage
- Withdrawal Delay: Undelegation subject to network delay period
Reward Distribution
Rewards flow through multiple layers:
- Community Tax: Applied to all rewards first
- Validator Commission: Taken from remaining rewards
- Delegator Distribution: Proportional to shares held
Contract Interfaces
IStakingContract
0xea224dBB52F57752044c0C86aD50930091F561B9
(Testnet)
Central registry for validators and global parameters.
Validator Management
// Create validator contract
function createValidator(bytes calldata pubkey) external returns (address);
// Initialize validator with self-delegation
function initializeValidator(
Description calldata description,
uint32 commissionRate,
uint96 withdrawalFeeInGwei,
bytes calldata pubkey,
bytes calldata signature
) external payable;
// Create and initialize in one call
function createAndInitializeValidatorIfNecessary(
Description calldata description,
uint32 commissionRate,
uint96 withdrawalFeeInGwei,
bytes calldata pubkey,
bytes calldata signature
) external payable;
Query Functions
function getValidator(bytes memory pubkey) external view returns (address);
function computeValidatorAddress(bytes calldata pubkey) external view returns (address);
function validatorCount() external view returns (uint32);
function maxValidatorCount() external view returns (uint32);
IValidatorContract
Individual validator operations and delegation management.
Delegation Management
// Delegate tokens (msg.value = amount)
function delegate(address delegatorAddress) external payable returns (uint);
// Undelegate shares (msg.value = withdrawal fee)
function undelegate(address withdrawalAddress, uint shares) external payable returns (uint);
// Withdraw validator commission (only validator operator)
function withdrawCommission(address withdrawalAddress) external returns (uint);
The withdrawCommission
function is restricted to the validator operator only - the address that originally created and manages the validator.
Information Queries
function tokens() external view returns (uint); // Total tokens (delegated + rewards)
function delegatorShares() external view returns (uint); // Total shares issued
function getDelegation(address delegator) external view returns (address, uint);
function commissionRate() external view returns (uint32);
function withdrawalFeeInGwei() external view returns (uint96);
The tokens()
function returns the complete validator balance, including both the original delegated amounts and any accumulated rewards that haven't been distributed yet.
Examples
Creating a Validator
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IStakingContract.sol";
contract ValidatorExample {
IStakingContract constant STAKING = IStakingContract(0xea224dBB52F57752044c0C86aD50930091F561B9);
function createValidator(
bytes calldata pubkey,
bytes calldata signature
) external payable {
Description memory desc = Description({
moniker: "My Validator",
identity: "keybase-id",
website: "https://validator.example.com",
securityContact: "security@example.com",
details: "A reliable 0G Chain validator"
});
STAKING.createAndInitializeValidatorIfNecessary{value: msg.value}(
desc,
50000, // 5% commission
1, // 1 Gwei withdrawal fee
pubkey,
signature
);
}
}
Delegation Management
contract DelegationHelper {
IStakingContract constant STAKING = IStakingContract(0xea224dBB52F57752044c0C86aD50930091F561B9);
function delegateToValidator(bytes calldata pubkey) external payable {
address validator = STAKING.getValidator(pubkey);
require(validator != address(0), "Validator not found");
IValidatorContract(validator).delegate{value: msg.value}(msg.sender);
}
function getDelegationInfo(
bytes calldata pubkey,
address delegator
) external view returns (uint shares, uint estimatedTokens) {
address validator = STAKING.getValidator(pubkey);
IValidatorContract v = IValidatorContract(validator);
(, shares) = v.getDelegation(delegator);
uint totalTokens = v.tokens();
uint totalShares = v.delegatorShares();
if (totalShares > 0) {
estimatedTokens = (shares * totalTokens) / totalShares;
}
}
}
Getting Validator Signature
Prerequisites
Your directory structure should look like:
galileo/
├── bin/0gchaind
└── config/
├── genesis.json
├── priv_validator_key.json
└── ...
Step 1: Extract Public Key
# Set your home directory
HOMEDIR=/.tmp/0gchaind
CHAIN_SPEC=devnet
# Generate validator keys
./0gchaind deposit validator-keys --home $HOMEDIR --chaincfg.chain-spec=$CHAIN_SPEC
Output:
Eth/Beacon Pubkey (Compressed 48-byte Hex):
0xaa0f99735a6436d6b7ed763c2eaa8452d753c5152a4fb1e4dc0bd7e33bcfc8cd4fac0e2d6cbab941f423c17728fecc56
Step 2: Compute Validator Address
Use the public key from Step 1 to compute the validator's contract address. Choose your preferred method:
- Foundry Cast
- curl/RPC
Recommended method - simpler syntax and better error handling.
cast call \
0xea224dBB52F57752044c0C86aD50930091F561B9 \
"computeValidatorAddress(bytes)(address)" \
"0xaa0f99735a6436d6b7ed763c2eaa8452d753c5152a4fb1e4dc0bd7e33bcfc8cd4fac0e2d6cbab941f423c17728fecc56" \
--rpc-url https://evmrpc-testnet.0g.ai
Alternative method using direct RPC calls - works without additional tooling.
curl -X POST https://evmrpc-testnet.0g.ai \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"eth_call",
"params":[{
"to": "0xea224dBB52F57752044c0C86aD50930091F561B9",
"data": "0x1ab06aa7000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000aa0f99735a6436d6b7ed763c2eaa8452d753c5152a4fb1e4dc0bd7e33bcfc8cd4fac0e2d6cbab941f423c17728fecc0000000000000000000000000000000000"
}, "latest"],
"id":1
}'
Step 3: Generate Signature
# Generate signature for validator initialization
./0gchaind deposit create-validator \
0x1E776a6b65892EC60537a885c17B820301E05400 \
32000000000 \
$HOMEDIR/config/genesis.json \
--home $HOMEDIR \
--chaincfg.chain-spec=$CHAIN_SPEC
Output:
✅ Deposit message created successfully!
pubkey: 0xaa0f99735a6436d6b7ed763c2eaa8452d753c5152a4fb1e4dc0bd7e33bcfc8cd4fac0e2d6cbab941f423c17728fecc56
signature: 0x123456789000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Data Structures
Description Struct
struct Description {
string moniker; // max 70 chars - Validator display name
string identity; // max 3000 chars - Keybase identity
string website; // max 140 chars - Website URL
string securityContact; // max 140 chars - Security contact
string details; // max 280 chars - Additional details
}
Withdrawal Entry
struct WithdrawEntry {
uint completionHeight; // Block height when withdrawal completes
address delegatorAddress; // Address receiving withdrawal
uint amount; // Amount being withdrawn
}
Configuration Parameters
Parameter | Description |
---|---|
maxValidatorCount | Maximum validators allowed |
minActivationStakesInGwei | Minimum stake for activation |
maxEffectiveStakesInGwei | Maximum effective stake |
communityTaxRate | Tax on all rewards |
minWithdrawabilityDelay | Withdrawal delay blocks |
Troubleshooting
Error: "Validator not found"
The validator hasn't been created yet. Use createValidator()
first:
address validator = staking.createValidator(pubkey);
Error: "DelegationBelowMinimum"
Your delegation amount is below the minimum required. Check:
uint96 minDelegation = staking.effectiveDelegationInGwei();
require(msg.value >= minDelegation * 1 gwei, "Insufficient delegation");
Error: "NotEnoughWithdrawalFee"
Include the withdrawal fee when undelegating:
uint96 fee = validator.withdrawalFeeInGwei();
validator.undelegate{value: fee * 1 gwei}(recipient, shares);
Contract Addresses
Network | Staking Contract |
---|---|
Testnet | 0xea224dBB52F57752044c0C86aD50930091F561B9 |
Resources
- Run Validator Node: Validator Setup Guide
- GitHub Repository: 0G Chain Contracts
- Deploy Contracts: Contract Deployment
Need help? Join our Discord for developer support.