Skip to Content

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.

What is a precompile? A precompile is a special smart contract deployed at a fixed address by the Sei protocol itself, that exposes custom native chain logic to EVM-based applications. It acts like a regular contract from the EVM’s perspective, but executes privileged, low-level logic efficiently.

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';
Precompile Address: The staking precompile is deployed at 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:

FunctionInput/OutputDecimal PrecisionExample
delegate()msg.value (input)18 decimals (wei)ethers.parseUnits(‘1’, 18)
undelegate()amount (input)6 decimals (uSEI)

1000000 (represents 1 SEI)

redelegate()amount (input)6 decimals (uSEI)

500000 (represents 0.5 SEI)

delegation()return values (output)6 decimals (uSEI)

1000000 (represents 1 SEI)

How This Works in Practice

delegate() Function (Uses 18 decimals):

  • delegate() - accepts msg.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

  1. delegate() EVM Compatibility: Uses standard 18-decimal wei format for EVM msg.value consistency
  2. Other Operations Cosmos Integration: undelegate() and redelegate() use 6-decimal uSEI precision to match native Cosmos operations
  3. 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

// 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

// 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);
⚠️
IMPORTANT: Undelegated tokens are subject to a 21-day unbonding period during which they cannot be transferred and do not earn rewards.

Redelegate Tokens

// 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

// 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

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

// Set appropriate gas limits for different operations const delegateTx = await staking.delegate(validatorAddress, { value: amount, gasLimit: 300000 });

Error Code Reference

ErrorCauseSolution
insufficient fundsNot enough SEI for operationCheck balance and reduce amount
validator does not existInvalid validator addressVerify validator address format
invalid delegation amountAmount formatting issueUse correct decimal precision
commission rate too highCommission above max rateLower commission rate
commission change too frequentChanging commission within 24hWait 24 hours between changes
self delegation too lowBelow minimum self-delegationIncrease self-delegation amount
too many redelegationsExceeded 7 redelegation limitWait for earliest redelegation to expire

Important Notes

Remember the key rule: delegate() uses 18 decimals, undelegate()/redelegate() use 6 decimals, delegation() returns 6 decimals!

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
Last updated on