Staking Precompile
Address: 0x0000000000000000000000000000000000001005
The Sei staking precompile allows EVM applications to interact directly with Sei’s native staking module through standard smart contract calls. This enables delegation, undelegation, redelegation, validator management, and staking queries directly from your dApps without needing separate Cosmos SDK integration.
How Does the Staking Precompile Work?
The staking precompile at address 0x0000000000000000000000000000000000001005
exposes functions like delegate()
, undelegate()
, redelegate()
, and delegation()
.
- Direct Integration: EVM contracts and dApps can call staking functions like any other smart contract method.
- Native Execution: Operations are executed at the Cosmos SDK level for maximum efficiency and security.
- Seamless Bridge: No need for separate wallet integrations or complex cross-chain interactions.
Use Cases
- DeFi Integration: Build liquid staking protocols and yield farming strategies.
- Delegation Services: Create user-friendly interfaces for staking operations.
- Portfolio Management: Automate staking strategies and delegation rebalancing.
- Validator Management: Create and manage validators programmatically.
What You’ll Learn in This Guide
By the end of this guide, you’ll be able to:
- Integrate Staking Operations - Call delegation, undelegation, and redelegation functions directly from your EVM contracts and dApps
- Handle Decimal Precision - Master the critical precision patterns for different operations to avoid common formatting errors
- Manage Validator Operations - Query validators programmatically using the precompile interface
- Build Portfolio Tools - Implement automated rebalancing and delegation tracking for staking management applications
- Navigate Staking Risks - Understand unbonding periods, slashing mechanics, and validator selection for safe staking operations
Functions
The staking precompile exposes the following functions:
Transaction Functions
/// Delegates Sei to the specified validator.
/// @dev This function truncates msg.value to 6 decimal places for interaction with the staking module
/// @param valAddress The Sei address of the validator.
/// @return Whether the delegation was successful.
function delegate(
string memory valAddress
) payable external returns (bool success);
/// Redelegates Sei from one validator to another.
/// @dev The amount should be in 6 decimal precision, not 18. 1 SEI = 1_000_000 uSEI
/// @param srcAddress The Sei address of the validator to move delegations from.
/// @param dstAddress The Sei address of the validator to move delegations to.
/// @param amount The amount of Sei to move from srcAddress to dstAddress.
/// @return Whether the redelegation was successful.
function redelegate(
string memory srcAddress,
string memory dstAddress,
uint256 amount
) external returns (bool success);
/// Undelegates Sei from the specified validator.
/// @dev The amount should be in 6 decimal precision, not 18. 1 SEI = 1_000_000 uSEI
/// @param valAddress The Sei address of the validator to undelegate from.
/// @param amount The amount of Sei to undelegate.
/// @return Whether the undelegation was successful.
function undelegate(
string memory valAddress,
uint256 amount
) external returns (bool success);
Query Functions
struct Delegation {
Balance balance;
DelegationDetails delegation;
}
struct Balance {
uint256 amount;
string denom;
}
struct DelegationDetails {
string delegator_address;
uint256 shares;
uint256 decimals;
string validator_address;
}
/// Queries delegation for a given delegator and validator address.
/// @param delegator The address of the delegator.
/// @param valAddress The Sei address of the validator.
/// @return The delegation information.
/// To calculate the actual amount, divide the shares by decimals.
function delegation(
address delegator,
string memory valAddress
) external view returns (Delegation delegation);
Using the Precompile
Setup
Prerequisites
Before getting started, ensure you have:
- Node.js (v16 or higher)
- npm or yarn package manager
- EVM-compatible wallet
- SEI tokens for gas fees and staking operations
Install Dependencies
Install the required packages for interacting with Sei precompiles:
# Install ethers.js for smart contract interactions
npm install ethers
# Install Sei EVM bindings for precompile addresses and ABIs
npm install @sei-js/precompiles@2.1.2
Import Precompile Components
// Import Staking precompile address and ABI
// View the entire ABI here: https://github.com/sei-protocol/sei-chain/tree/evm/precompiles/staking
import { STAKING_PRECOMPILE_ABI, STAKING_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';
import { ethers } from 'ethers';
0x0000000000000000000000000000000000001005
Contract Initialization
Set up your provider, signer, and contract instance:
// Using EVM-compatible wallet as the signer and provider
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();
// Create a contract instance for the staking precompile
const staking = new ethers.Contract(STAKING_PRECOMPILE_ADDRESS, STAKING_PRECOMPILE_ABI, signer);
Critical: Understanding Decimal Precision
One of the most important concepts to understand when working with the Sei staking precompile:
Mixed Decimal Precision System
The staking precompile operates with different decimal precision for different operations due to bridging EVM and Cosmos standards:
Function | Input/Output | Decimal Precision | Example |
---|---|---|---|
delegate() | msg.value (input) | 18 decimals (wei) | ethers.parseUnits(‘1’, 18) |
undelegate() | amount (input) | 6 decimals (uSEI) |
|
redelegate() | amount (input) | 6 decimals (uSEI) |
|
delegation() | return values (output) | 6 decimals (uSEI) |
|
How This Works in Practice
delegate() Function (Uses 18 decimals):
delegate()
- acceptsmsg.value
in wei (18 decimals)
undelegate() and redelegate() Functions (Use 6 decimals):
undelegate()
- expects amount parameter in 6 decimals (uSEI)redelegate()
- expects amount parameter in 6 decimals (uSEI)
Reading/Query Operations (Return 6 decimals):
delegation()
- returns amounts in 6 decimal precision
Why This Mixed System Exists
- delegate() EVM Compatibility: Uses standard 18-decimal wei format for EVM
msg.value
consistency - Other Operations Cosmos Integration:
undelegate()
andredelegate()
use 6-decimal uSEI precision to match native Cosmos operations - Query Consistency: All query results use 6-decimal precision for consistent reading
Best Practice: Different Conversion for Different Functions
When working with user inputs, use the appropriate conversion for each function:
// Best practice for handling user input amounts
function prepareAmountForDelegate(seiAmount: number): bigint {
// For delegate() - convert to 18 decimals (wei)
const fixedAmount = seiAmount.toFixed(6);
return ethers.parseUnits(fixedAmount, 18);
}
function prepareAmountForUndelegateRedelegate(seiAmount: number): bigint {
// For undelegate() and redelegate() - convert to 6 decimals (uSEI)
return ethers.parseUnits(seiAmount.toFixed(6), 6);
}
// Usage examples
const userInputAmount = 1.23456789; // User enters this
// For delegate()
const delegateAmount = prepareAmountForDelegate(userInputAmount); // 18 decimals
// For undelegate() and redelegate()
const undelegateAmount = prepareAmountForUndelegateRedelegate(userInputAmount); // 6 decimals
Decimal Conversion Helpers
Use these helper functions to avoid precision errors:
// Helper functions for amount conversion
class SeiAmountConverter {
// Convert SEI to wei (18 decimals) - ONLY for delegate()
static seiToWei(seiAmount: number): bigint {
return ethers.parseUnits(seiAmount.toFixed(6), 18);
}
// Convert SEI to uSEI (6 decimals) - for undelegate() and redelegate()
static seiToUsei(seiAmount: number): bigint {
return ethers.parseUnits(seiAmount.toFixed(6), 6);
}
// Convert reading results (6 decimals) to SEI
static useiToSei(useiAmount: number | bigint): number {
return Number(useiAmount) / 1000000;
}
// Convert wei to SEI (18 decimals) - for delegate operations
static weiToSei(weiAmount: bigint): number {
return Number(ethers.formatEther(weiAmount));
}
}
// Usage examples - Use correct decimals for each function
const delegateAmount = SeiAmountConverter.seiToWei(1); // For delegate() - 18 decimals
const undelegateAmount = SeiAmountConverter.seiToUsei(0.5); // For undelegate() - 6 decimals
const redelegateAmount = SeiAmountConverter.seiToUsei(2); // For redelegate() - 6 decimals
Step-by-Step Guide: Using the Staking Precompile
Delegate Tokens
JavaScript
// Sei validator address you want to delegate to (seivaloper... format)
const validatorAddress = 'seivaloper1xyz...';
const amount = 1; // Amount in SEI to delegate
const amountTrimmed = amount.toFixed(6); // Ensure 6 decimal precision for msg.value
// Delegate 1 SEI - Uses 18 decimals for msg.value
const amountToDelegate = ethers.parseUnits(amountTrimmed, 18);
const tx = await staking.delegate(validatorAddress, { value: amountToDelegate });
const receipt = await tx.wait();
console.log('Delegation completed:', receipt);
Undelegate Tokens
JavaScript
// Undelegate 1 SEI from a validator - Uses 6 decimals for amount parameter
const validatorAddress = 'seivaloper1xyz...';
const amount = 1; // Amount in SEI to undelegate
const amountTrimmed = amount.toFixed(6); // Ensure 6 decimal precision
const amountToUndelegate = ethers.parseUnits(amountTrimmed, 6); // 1 SEI in 6 decimals
const tx = await staking.undelegate(validatorAddress, amountToUndelegate);
const receipt = await tx.wait();
console.log('Undelegation started:', receipt);
Redelegate Tokens
JavaScript
// Redelegate 0.5 SEI from one validator to another - Uses 6 decimals for amount parameter
const srcValidator = 'seivaloper1abc...';
const dstValidator = 'seivaloper1xyz...';
const amount = 0.5; // Amount in SEI to redelegate
const amountTrimmed = amount.toFixed(6); // Ensure 6 decimal precision
const amountToRedelegate = ethers.parseUnits(amountTrimmed, 6); // 0.5 SEI in 6 decimals
const tx = await staking.redelegate(srcValidator, dstValidator, amountToRedelegate);
const receipt = await tx.wait();
console.log('Redelegation completed:', receipt);
Redelegation restrictions:
-
Maximum 7 redelegations per validator pair per 21-day period
-
After redelegating from Validator A to Validator B, you cannot redelegate from Validator B to another validator for 21 days
-
Each redelegation has its own 21-day cooldown period
Query a Delegation
JavaScript
// Get your EVM address as the delegator
const delegator = await signer.getAddress();
try {
const delegationInfo = await staking.delegation(delegator, validatorAddress);
console.log('Delegation details:', {
amount: delegationInfo.balance.amount.toString(),
denom: delegationInfo.balance.denom,
shares: delegationInfo.delegation.shares.toString(),
decimals: delegationInfo.delegation.decimals.toString(),
delegator_address: delegationInfo.delegation.delegator_address,
validator_address: delegationInfo.delegation.validator_address
});
// Convert delegation amount from uSEI to SEI for readable display
const delegationAmountSei = ethers.formatUnits(delegationInfo.balance.amount, 6);
console.log('Delegation amount (SEI):', delegationAmountSei);
} catch (error) {
if (error.message.includes('delegation not found') || error.message.includes('no delegation')) {
console.log('No delegation found for this validator');
} else {
console.error('Error querying delegation:', error);
}
}
Advanced Usage Examples
Portfolio Rebalancing
async function rebalanceStaking(
fromValidator: string,
toValidator: string,
amount: number // Amount in SEI
) {
try {
// Convert to 6 decimal precision for redelegate (uses 6 decimals)
const amountIn6Decimals = ethers.parseUnits(amount.toFixed(6), 6);
const tx = await staking.redelegate(fromValidator, toValidator, amountIn6Decimals);
const receipt = await tx.wait();
console.log('Rebalancing completed:', receipt);
return receipt;
} catch (error) {
console.error('Rebalancing failed:', error);
throw error;
}
}
Complete Integration Example
JavaScript
async function stakingExample() {
// Setup
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();
const staking = new ethers.Contract(STAKING_PRECOMPILE_ADDRESS, STAKING_PRECOMPILE_ABI, signer);
const delegator = await signer.getAddress();
const validatorAddress = 'seivaloper1xyz...';
try {
// 1. Check current delegation (with error handling)
console.log('=== Checking Current Delegation ===');
try {
const currentDelegation = await staking.delegation(delegator, validatorAddress);
const currentAmountSei = ethers.formatUnits(currentDelegation.balance.amount, 6);
console.log('Current delegation amount (SEI):', currentAmountSei);
} catch (error) {
if (error.message.includes('delegation not found') || error.message.includes('no delegation')) {
console.log('No existing delegation found for this validator');
} else {
throw error; // Re-throw if it's a different error
}
}
// 2. Delegate additional tokens (uses 18 decimals)
console.log('=== Delegating Tokens ===');
const amount = 1;
const amountTrimmed = amount.toFixed(6); // Ensure 6 decimal precision
const amountToDelegate = ethers.parseUnits(amountTrimmed, 18);
const delegateTx = await staking.delegate(validatorAddress, {
value: amountToDelegate,
gasLimit: 300000
});
await delegateTx.wait();
console.log('Delegation successful:', delegateTx.hash);
// 3. Check updated delegation
const updatedDelegation = await staking.delegation(delegator, validatorAddress);
const updatedAmountSei = ethers.formatUnits(updatedDelegation.balance.amount, 6);
console.log('Updated delegation amount (SEI):', updatedAmountSei);
// 4. Undelegate partial amount (uses 6 decimals)
console.log('=== Undelegating Tokens ===');
const undelegateAmount = ethers.parseUnits('0.5', 6); // 0.5 SEI in 6 decimals
const undelegateTx = await staking.undelegate(validatorAddress, undelegateAmount);
await undelegateTx.wait();
console.log('Undelegation successful:', undelegateTx.hash);
} catch (error) {
console.error('Operation failed:', error);
}
}
Security Considerations & Risks
Unbonding Period
- 21-day lock: Undelegated tokens cannot be transferred or earn rewards for 21 days
- No exceptions: This cannot be canceled once initiated
- Planning: Consider this when managing liquidity needs
Validator Selection Criteria
- Commission Rate: Lower commission means more rewards for you (typically 1-10%)
- Uptime: Check for validators with high uptime (99%+)
Redelegation Complexity
- 7-transaction limit: You can only redelegate from the same validator to the same destination validator 7 times in 21 days
- Serial blocking: After redelegating A→B, you cannot redelegate B→C for 21 days
- Each redelegation starts its own 21-day timer
Troubleshooting
Common Issues and Solutions
Gas-Related Issues
// Set appropriate gas limits for different operations
const delegateTx = await staking.delegate(validatorAddress, {
value: amount,
gasLimit: 300000
});
Error Code Reference
Error | Cause | Solution |
---|---|---|
insufficient funds | Not enough SEI for operation | Check balance and reduce amount |
validator does not exist | Invalid validator address | Verify validator address format |
invalid delegation amount | Amount formatting issue | Use correct decimal precision |
commission rate too high | Commission above max rate | Lower commission rate |
commission change too frequent | Changing commission within 24h | Wait 24 hours between changes |
self delegation too low | Below minimum self-delegation | Increase self-delegation amount |
too many redelegations | Exceeded 7 redelegation limit | Wait for earliest redelegation to expire |
Important Notes
Decimal Precision
- delegate() uses 18 decimals (wei) for msg.value
- undelegate() and redelegate() use 6 decimals (uSEI) for amount parameters
- Query results return amounts in 6 decimal precision
- Best practice: Use appropriate conversion functions for each operation
Validator Addresses
- Use valid Sei validator addresses with
seivaloper1...
prefix - These are Cosmos-format addresses, not EVM addresses
Staking Risks
- Unbonding: 21-day waiting period for undelegated tokens
- Redelegation limits: Complex rules around frequency and serial operations
Commission and Rewards
- Validators keep a commission percentage
- Rewards are distributed proportionally to delegation amounts
- Choose validators wisely based on commission, uptime, and governance participation