> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sei.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Governance Precompile Usage

> Learn how to interact with Sei's governance precompile through ethers.js, enabling proposal submission, voting, token deposits, and governance queries to participate in on-chain governance directly from EVM applications.

**Address:** `0x0000000000000000000000000000000000001006`

The Sei governance precompile enables EVM applications to participate in Sei's on-chain governance process. This allows users and smart contracts to submit proposals, vote on them, deposit tokens, and query governance information directly through the EVM interface.

<Info>**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.</Info>

## How Does the Governance Precompile Work?

The governance precompile at address `0x0000000000000000000000000000000000001006` exposes functions like `vote()`, `voteWeighted()`, `deposit()`, and `submitProposal()`.

* **Direct Integration:** EVM contracts and dApps can interact with governance like any other smart contract method.
* **Native Execution:** Governance operations are executed at the chain level for maximum efficiency.
* **Seamless:** No need for separate wallet integrations.

## Use Cases

* **Voting Interfaces:** Create user-friendly governance participation tools.
* **Automated Governance:** Smart contracts that vote based on predetermined strategies.
* **Governance Aggregators:** Build platforms that aggregate and simplify governance participation.

## Sei Governance Overview

Sei governance operates on a structured timeline with specific parameters:

### Governance Process

1. **Proposal Submission:** Submit proposal with minimum 3,500 SEI deposit
2. **Deposit Period:** 2 days to accumulate minimum deposit or reach expedited threshold
3. **Voting Period:** 3 days (1 day for expedited) of active voting once minimum deposit is met
4. **Tallying:** Results calculated based on quorum and voting thresholds

<Info> To find out all about the governance process on Sei, go to the [governance explainer](/learn/general-governance).</Info>

<Warning>
  **Critical Mainnet Considerations:**

  * **High Stakes:** Mainnet governance involves real SEI tokens and binding decisions
  * **Minimum Deposit:** 3500 SEI minimum, 7000 SEI for expedited
  * **Deposit Risk:** Deposits will be burned if your proposal receives >33.4% NoWithVeto votes
  * **Voting Power Required:** Must stake SEI with validators to participate
  * **Time Limits:** Strict 2-day deposit period and 3-day voting period
  * **Real Impact:** Successful proposals can change network parameters
</Warning>

## Functions

The governance precompile exposes the following functions:

### Transaction Functions

```solidity theme={"dark"}
/// Cast a vote on the specified proposal.
/// @param proposalID The ID of the proposal to vote on.
/// @param option The option to vote for. (1=Yes, 2=Abstain, 3=No, 4=NoWithVeto)
/// @return Whether the vote was successfully cast.
function vote(
    uint64 proposalID,
    int32 option
) external returns (bool success);

struct WeightedVoteOption {
    int32 option;   // Vote option (1=Yes, 2=Abstain, 3=No, 4=NoWithVeto)
    string weight;  // Weight as decimal string (e.g., "0.7") - MUST sum to exactly 1.0 across all options
}

/// Cast a weighted vote on a governance proposal (vote splitting)
/// @param proposalID The ID of the proposal to vote on
/// @param options Array of weighted vote options, weights MUST sum to exactly 1.0 or transaction will fail
/// @return success Whether the vote was successfully cast
function voteWeighted(
    uint64 proposalID,
    WeightedVoteOption[] calldata options
) external returns (bool success);

/// Deposit funds into the specified proposal.
/// @param proposalID The ID of the proposal to deposit to.
/// @return Whether the tokens were successfully deposited.
function deposit(
    uint64 proposalID
) payable external returns (bool success);

/// Submit a new governance proposal. Deposit should be provided via msg.value
/// @param proposalJSON JSON string containing proposal details e.g.:
///        {
///          "title": "Proposal Title",
///          "description": "Proposal Description",
///          "type": "Text", // Optional, defaults to "Text" if empty
///          "is_expedited": false // Optional
///        }
/// @return proposalID The ID of the created proposal

function submitProposal(
    string calldata proposalJSON
) payable external returns (uint64 proposalID);
```

## Using the Contract

### Setup

#### Prerequisites

Before getting started, ensure you have:

* **Node.js** (v18 or higher)
* **npm** or **yarn** package manager
* **MetaMask** or compatible EVM wallet configured for Sei Mainnet
* **SEI tokens** for gas and governance deposits (minimum 3,500 SEI for proposals)

#### Install Dependencies

Install the required packages for interacting with Sei precompiles:

```bash theme={"dark"}
# 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

# Install dotenv for managing private keys (optional but recommended)
npm install dotenv
```

#### Import Precompile Components

```typescript theme={"dark"}
// Import Governance precompile address and ABI
// View the entire ABI here: https://github.com/sei-protocol/sei-chain/tree/main/precompiles/gov
import { GOVERNANCE_PRECOMPILE_ABI, GOVERNANCE_PRECOMPILE_ADDRESS } from '@sei-js/precompiles';
import { ethers } from 'ethers';
```

<Info>**Precompile Address:** The governance precompile is deployed at `0x0000000000000000000000000000000000001006`</Info>

#### Get SEI Tokens

Purchase SEI tokens from supported exchanges:

* **Centralized Exchanges:** Binance, Coinbase, KuCoin, Gate.io
* **Decentralized Exchanges:** Astroport, Dragonswap (on Sei)
* **Bridge Options:** Various cross-chain bridges support SEI

<Warning>**Minimum Requirements:** You need at least 3,500 SEI to submit a governance proposal, plus additional tokens for gas and potential additional deposits.</Warning>

### Contract Initialization

Set up your provider, signer, and contract instance:

```typescript theme={"dark"}
// Using MetaMask as the signer and provider (browser environment)
const provider = new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
const signer = await provider.getSigner();

// Or for Node.js environment
const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');
const signer = new ethers.Wallet('YOUR_PRIVATE_KEY', provider);

// Create a contract instance for the governance precompile
const governance = new ethers.Contract(GOVERNANCE_PRECOMPILE_ADDRESS, GOVERNANCE_PRECOMPILE_ABI, signer);
```

## Vote Options

The governance system uses the following vote options:

| Option     | Value | Description                   | Impact                                      |
| ---------- | ----- | ----------------------------- | ------------------------------------------- |
| Yes        | 1     | Vote in favor of the proposal | Proposal passes if threshold met            |
| Abstain    | 2     | Abstain from voting           | Counts toward quorum only                   |
| No         | 3     | Vote against the proposal     | Opposes proposal                            |
| NoWithVeto | 4     | Vote against with veto        | Opposes Proposal & burns deposit if > 33.4% |

### Voting Power

Your voting power is determined by:

* **Staked SEI:** Amount of SEI you have staked with validators
* **Delegation:** SEI delegated to validators counts toward voting power
* **Liquid SEI:** Unstaked SEI does not provide voting power

<Info>**Important:** Only staked SEI provides voting power. You must delegate your tokens to validators to participate in governance voting.</Info>

## Validation Functions

Before making governance transactions, use these helper functions to validate inputs:

```typescript theme={"dark"}
// Validate vote option
function isValidVoteOption(option: number): boolean {
  return option >= 1 && option <= 4;
}

// Validate weighted vote options sum to 1.0 - CRITICAL FOR TRANSACTION SUCCESS
function validateWeightedOptions(options: Array<{ option: number; weight: string }>): boolean {
  const totalWeight = options.reduce((sum, opt) => sum + parseFloat(opt.weight), 0);

  // Check if total weight equals 1.0 (with small tolerance for floating point precision)
  // Note: Sei governance is strict - even small deviations will cause transaction failure
  const isValidTotal = Math.abs(totalWeight - 1.0) < 0.000001;

  // Check if all options are valid
  const allOptionsValid = options.every((opt) => isValidVoteOption(opt.option));

  if (!isValidTotal) {
    console.error(`Weights sum to ${totalWeight}, but MUST equal exactly 1.0`);
  }

  return isValidTotal && allOptionsValid;
}

// Validate proposal JSON structure
function validateProposalJSON(proposalJSON: string): boolean {
  try {
    const proposal = JSON.parse(proposalJSON);
    return proposal.title && proposal.description && typeof proposal.title === 'string' && typeof proposal.description === 'string' && proposal.title.length > 0 && proposal.description.length > 0;
  } catch {
    return false;
  }
}

// Check if deposit meets minimum requirement
function validateDepositAmount(depositAmount: bigint, isExpedited: boolean = false): boolean {
  const MINIMUM_DEPOSIT = ethers.parseUnits('3500', 18); // 3,500 SEI minimum
  const EXPEDITED_DEPOSIT = ethers.parseUnits('7000', 18); // 7,000 SEI for expedited

  const requiredAmount = isExpedited ? EXPEDITED_DEPOSIT : MINIMUM_DEPOSIT;
  return depositAmount >= requiredAmount;
}

// Check if user has sufficient voting power
async function checkVotingPower(userAddress: string): Promise<bigint> {
  // This would typically query staking information
  // Implementation depends on your specific setup
  console.log(`Checking voting power for ${userAddress}`);
  return ethers.parseUnits('0', 18); // Placeholder - implement actual check
}
```

## Step-by-Step Guide: Using the Governance Precompile

### Submit a Proposal

<Info>
  **Important Deposit Requirements:**

  * **Minimum deposit:** 3,500 SEI required for proposal to enter voting period
  * **Expedited processing:** 7,000 SEI if the voting period should only be 1 day long
  * **Deposit period:** 2 days to meet minimum or proposal fails and deposits are burned
  * **Multiple deposits:** Anyone can contribute to reach the minimum threshold
</Info>

```typescript theme={"dark"}
async function submitGovernanceProposal(title: string, description: string, depositAmount: bigint, isExpedited: boolean = false): Promise<bigint> {
  // Validate inputs
  if (!title || !description) {
    throw new Error('Title and description are required');
  }

  if (title.length < 5 || title.length > 200) {
    throw new Error('Title must be between 5 and 200 characters');
  }

  if (description.length < 20 || description.length > 10000) {
    throw new Error('Description must be between 20 and 10,000 characters');
  }

  // Proposal details
  const proposal = {
    title: title.trim(),
    description: description.trim(),
    type: 'Text',
    is_expedited: isExpedited
  };

  // Convert to JSON string and validate
  const proposalJSON = JSON.stringify(proposal);
  if (!validateProposalJSON(proposalJSON)) {
    throw new Error('Invalid proposal JSON structure');
  }

  // Validate deposit amount
  if (!validateDepositAmount(depositAmount, isExpedited)) {
    const required = isExpedited ? '7,000 SEI' : '3,500 SEI';
    const provided = ethers.formatEther(depositAmount);
    throw new Error(`Insufficient deposit. Required: ${required}, Provided: ${provided} SEI`);
  }

  // Check balance before submitting
  const balance = await provider.getBalance(await signer.getAddress());
  const totalCost = depositAmount + ethers.parseUnits('0.1', 18); // Add gas buffer

  if (balance < totalCost) {
    throw new Error(`Insufficient balance. Need ${ethers.formatEther(totalCost)} SEI (including gas)`);
  }

  try {
    console.log('Submitting governance proposal...');
    console.log(`Title: ${title}`);
    console.log(`Deposit: ${ethers.formatEther(depositAmount)} SEI`);
    console.log(`Expedited: ${isExpedited}`);

    const tx = await governance.submitProposal(proposalJSON, {
      value: depositAmount,
      gasLimit: 500000
    });

    console.log('Transaction submitted:', tx.hash);
    console.log('Waiting for confirmation...');

    const receipt = await tx.wait();

    // Extract proposal ID from events
    let proposalID: bigint | null = null;
    for (const log of receipt.logs) {
      try {
        const parsed = governance.interface.parseLog(log);
        if (parsed && parsed.name === 'ProposalSubmitted') {
          proposalID = parsed.args.proposalID;
          break;
        }
      } catch {
        continue;
      }
    }

    if (!proposalID) {
      throw new Error('Could not extract proposal ID from transaction receipt');
    }

    console.log('✅ Proposal submitted successfully!');
    console.log(`Proposal ID: ${proposalID.toString()}`);
    console.log(`Transaction hash: ${receipt.hash}`);
    console.log(`View proposal: https://sei.explorers.guru/proposal/${proposalID.toString()}`);

    return proposalID;
  } catch (error: any) {
    console.error('Failed to submit proposal:', error);

    if (error.message.includes('insufficient funds')) {
      throw new Error('Insufficient funds for proposal deposit and gas fees');
    } else if (error.message.includes('invalid deposit')) {
      throw new Error('Deposit amount does not meet minimum requirements');
    } else {
      throw error;
    }
  }
}

// Usage example
const proposalTitle = 'Increase Block Size Limit';
const proposalDescription = `
This proposal suggests increasing the block size limit from the current value to improve transaction throughput on the Sei network.

## Rationale
Current network usage patterns show we are approaching capacity limits during peak times. Increasing the block size will:

1. Reduce transaction fees during high usage periods
2. Improve user experience with faster confirmation times
3. Support growing ecosystem adoption

## Implementation
The parameter change would be implemented through the existing governance mechanism with a 2-week transition period.

## Risks
- Slightly increased hardware requirements for validators
- Potential centralization concerns (mitigated by current validator distribution)

The benefits significantly outweigh the minimal risks involved.
`.trim();

const depositAmount = ethers.parseUnits('4000', 18); // 4,000 SEI deposit
await submitGovernanceProposal(proposalTitle, proposalDescription, depositAmount, false);
```

### Vote on a Proposal

```typescript theme={"dark"}
// Simple voting with comprehensive validation
async function voteOnProposal(proposalID: bigint, voteOption: number): Promise<void> {
  // Validate vote option
  if (!isValidVoteOption(voteOption)) {
    throw new Error('Invalid vote option. Must be 1 (Yes), 2 (Abstain), 3 (No), or 4 (NoWithVeto)');
  }

  // Check voting power (implement based on your staking setup)
  const userAddress = await signer.getAddress();
  console.log(`Checking voting eligibility for ${userAddress}...`);

  // Verify proposal exists and is in voting period
  try {
    // You would typically query proposal status here
    console.log(`Voting on proposal ${proposalID.toString()}...`);

    const voteOptionNames = {
      1: 'Yes',
      2: 'Abstain',
      3: 'No',
      4: 'NoWithVeto'
    };

    console.log(`Vote option: ${voteOptionNames[voteOption as keyof typeof voteOptionNames]}`);

    const tx = await governance.vote(proposalID, voteOption, {
      gasLimit: 200000
    });

    console.log('Transaction submitted:', tx.hash);
    const receipt = await tx.wait();

    console.log('✅ Vote cast successfully!');
    console.log(`Proposal ID: ${proposalID.toString()}`);
    console.log(`Vote: ${voteOptionNames[voteOption as keyof typeof voteOptionNames]}`);
    console.log(`Transaction hash: ${receipt.hash}`);
    console.log(`View on explorer: https://seiscan.io/tx/${receipt.hash}`);
  } catch (error: any) {
    console.error('Failed to cast vote:', error);

    if (error.message.includes('proposal does not exist')) {
      throw new Error('Proposal does not exist or voting period has ended');
    } else if (error.message.includes('already voted')) {
      throw new Error('You have already voted on this proposal');
    } else if (error.message.includes('insufficient voting power')) {
      throw new Error('No voting power - you must stake SEI to participate in governance');
    } else {
      throw error;
    }
  }
}

// Usage examples
const proposalID = 1n;

// Vote Yes
await voteOnProposal(proposalID, 1);

// Vote No with Veto (burns deposit if >33.4% of votes)
await voteOnProposal(proposalID, 4);
```

### Weighted Voting

<Danger>**Critical Requirement:** Weighted vote options MUST sum to exactly 1.0 or the transaction will fail. The Sei governance module enforces this strictly - even small rounding errors will cause rejection.</Danger>

```typescript theme={"dark"}
// Weighted voting with comprehensive validation
async function castWeightedVote(proposalID: bigint, weightedOptions: Array<{ option: number; weight: string }>): Promise<void> {
  // Comprehensive validation
  if (weightedOptions.length === 0) {
    throw new Error('At least one vote option is required');
  }

  if (weightedOptions.length > 4) {
    throw new Error('Cannot have more than 4 vote options');
  }

  // Validate each option and check for duplicates
  const seenOptions = new Set<number>();
  let totalWeight = 0;

  for (const { option, weight } of weightedOptions) {
    // Validate option
    if (!isValidVoteOption(option)) {
      throw new Error(`Invalid vote option: ${option}. Must be 1-4`);
    }

    // Check for duplicates
    if (seenOptions.has(option)) {
      throw new Error(`Duplicate vote option: ${option}`);
    }
    seenOptions.add(option);

    // Validate weight
    const weightNum = parseFloat(weight);
    if (isNaN(weightNum) || weightNum <= 0 || weightNum > 1) {
      throw new Error(`Invalid weight: ${weight}. Must be number between 0 and 1`);
    }

    totalWeight += weightNum;
  }

  // CRITICAL: Check total weight
  if (Math.abs(totalWeight - 1.0) > 0.000001) {
    throw new Error(`CRITICAL: Total weight must equal exactly 1.0, got ${totalWeight.toFixed(6)}. Transaction will fail.`);
  }

  try {
    console.log('Casting weighted vote...');
    console.log(`Proposal ID: ${proposalID.toString()}`);
    console.log('Vote distribution:');

    const voteOptionNames = { 1: 'Yes', 2: 'Abstain', 3: 'No', 4: 'NoWithVeto' };
    let totalPercent = 0;

    for (const { option, weight } of weightedOptions) {
      const percentage = (parseFloat(weight) * 100).toFixed(1);
      console.log(`  ${percentage}% ${voteOptionNames[option as keyof typeof voteOptionNames]}`);
      totalPercent += parseFloat(percentage);
    }

    console.log(`Total: ${totalPercent.toFixed(1)}%`);

    const tx = await governance.voteWeighted(proposalID, weightedOptions, {
      gasLimit: 300000 // Higher gas limit for weighted voting
    });

    console.log('Transaction submitted:', tx.hash);
    const receipt = await tx.wait();

    console.log('✅ Weighted vote cast successfully!');
    console.log(`Transaction hash: ${receipt.hash}`);
    console.log(`View on explorer: https://seiscan.io/tx/${receipt.hash}`);
  } catch (error: any) {
    console.error('Failed to cast weighted vote:', error);

    if (error.message.includes('weights must sum to 1')) {
      throw new Error('Vote weights must sum to exactly 1.0. Check your weight calculations.');
    } else {
      throw error;
    }
  }
}

// Usage examples

// Example 1: Split decision (60% Yes, 40% Abstain)
const splitVote = [
  { option: 1, weight: '0.6' }, // 60% Yes
  { option: 2, weight: '0.4' } // 40% Abstain
  // Total: 0.6 + 0.4 = 1.0 ✅
];

await castWeightedVote(proposalID, splitVote);

// Example 2: Complex distribution
const complexVote = [
  { option: 1, weight: '0.45' }, // 45% Yes
  { option: 2, weight: '0.25' }, // 25% Abstain
  { option: 3, weight: '0.20' }, // 20% No
  { option: 4, weight: '0.10' } // 10% NoWithVeto
  // Total: 0.45 + 0.25 + 0.20 + 0.10 = 1.0 ✅
];

await castWeightedVote(proposalID, complexVote);

// Example 3: This would FAIL - weights don't sum to 1.0
const badVote = [
  { option: 1, weight: '0.7' },
  { option: 2, weight: '0.2' }
  // Total: 0.7 + 0.2 = 0.9 ❌ WILL FAIL
];
// await castWeightedVote(proposalID, badVote); // Don't run this!
```

### Deposit to a Proposal

```typescript theme={"dark"}
// Add deposit to help proposal reach minimum threshold
async function addDepositToProposal(proposalID: bigint, depositAmount: bigint): Promise<void> {
  if (depositAmount <= 0) {
    throw new Error('Deposit amount must be greater than 0');
  }

  // Check balance
  const userAddress = await signer.getAddress();
  const balance = await provider.getBalance(userAddress);
  const totalCost = depositAmount + ethers.parseUnits('0.05', 18); // Add gas buffer

  if (balance < totalCost) {
    throw new Error(`Insufficient balance. Need ${ethers.formatEther(totalCost)} SEI (including gas), ` + `but have ${ethers.formatEther(balance)} SEI`);
  }

  try {
    console.log('Adding deposit to proposal...');
    console.log(`Proposal ID: ${proposalID.toString()}`);
    console.log(`Deposit amount: ${ethers.formatEther(depositAmount)} SEI`);

    const tx = await governance.deposit(proposalID, {
      value: depositAmount,
      gasLimit: 200000
    });

    console.log('Transaction submitted:', tx.hash);
    const receipt = await tx.wait();

    console.log('✅ Deposit added successfully!');
    console.log(`Proposal ID: ${proposalID.toString()}`);
    console.log(`Amount deposited: ${ethers.formatEther(depositAmount)} SEI`);
    console.log(`Transaction hash: ${receipt.hash}`);
    console.log(`View proposal: https://sei.explorers.guru/proposal/${proposalID.toString()}`);
  } catch (error: any) {
    console.error('Failed to add deposit:', error);

    if (error.message.includes('proposal does not exist')) {
      throw new Error('Proposal does not exist');
    } else if (error.message.includes('deposit period ended')) {
      throw new Error('Deposit period has ended for this proposal');
    } else {
      throw error;
    }
  }
}

// Usage example
const proposalID = 1n;
const additionalDeposit = ethers.parseUnits('1000', 18); // 1,000 SEI
await addDepositToProposal(proposalID, additionalDeposit);
```

## Complete Integration Example

Create a comprehensive governance interaction script:

```javascript title="governance-mainnet-demo.js" theme={"dark"}
const { ethers } = require('ethers');
const { GOVERNANCE_PRECOMPILE_ABI, GOVERNANCE_PRECOMPILE_ADDRESS } = require('@sei-js/precompiles');
require('dotenv').config();

// Validation functions
function isValidVoteOption(option) {
  return option >= 1 && option <= 4;
}

function validateWeightedOptions(options) {
  const totalWeight = options.reduce((sum, opt) => sum + parseFloat(opt.weight), 0);
  const isValidTotal = Math.abs(totalWeight - 1.0) < 0.000001;
  const allOptionsValid = options.every((opt) => isValidVoteOption(opt.option));
  return isValidTotal && allOptionsValid;
}

function validateProposalJSON(proposalJSON) {
  try {
    const proposal = JSON.parse(proposalJSON);
    return proposal.title && proposal.description && typeof proposal.title === 'string' && typeof proposal.description === 'string' && proposal.title.length > 0 && proposal.description.length > 0;
  } catch {
    return false;
  }
}

function validateDepositAmount(depositAmount, isExpedited = false) {
  const MINIMUM_DEPOSIT = ethers.parseUnits('3500', 18); // 3,500 SEI
  const EXPEDITED_DEPOSIT = ethers.parseUnits('7000', 18); // 7,000 SEI
  const required = isExpedited ? EXPEDITED_DEPOSIT : MINIMUM_DEPOSIT;
  return depositAmount >= required;
}

async function main() {
  try {
    // Connect to Sei Mainnet
    console.log('🌐 Connecting to Sei Mainnet...');
    const provider = new ethers.JsonRpcProvider('https://evm-rpc.sei-apis.com');

    // Use your private key from environment variable
    const privateKey = process.env.PRIVATE_KEY;
    if (!privateKey) {
      throw new Error('Please set PRIVATE_KEY in .env file');
    }

    const wallet = new ethers.Wallet(privateKey, provider);
    const userAddress = wallet.address;

    console.log(`👤 Wallet address: ${userAddress}`);

    // Check balance
    const balance = await provider.getBalance(userAddress);
    const balanceEther = ethers.formatEther(balance);
    console.log(`💰 Wallet balance: ${balanceEther} SEI\n`);

    // Verify sufficient balance for mainnet governance
    const minimumRequired = ethers.parseUnits('3600', 18); // 3,600 SEI (3,500 + buffer)
    if (balance < minimumRequired) {
      console.log('❌ Insufficient balance for mainnet governance participation');
      console.log(`   Required: At least 3,600 SEI (3,500 for proposal + 100 buffer)`);
      console.log(`   Current: ${balanceEther} SEI`);
      console.log('   Please acquire more SEI tokens from exchanges or DEXs');
      return;
    }

    // Initialize governance precompile contract
    const governance = new ethers.Contract(GOVERNANCE_PRECOMPILE_ADDRESS, GOVERNANCE_PRECOMPILE_ABI, wallet);

    console.log('🏛️  === Sei Mainnet Governance Demo ===\n');

    // 1. Submit a governance proposal
    console.log('1️⃣  Submitting a governance proposal...');

    const proposal = {
      title: 'Demo: EVM Governance Integration Test',
      description: `This is a demonstration proposal submitted through the governance precompile to showcase seamless EVM-Cosmos governance integration.

## Purpose
This proposal demonstrates:
- EVM smart contract governance participation
- Cross-environment compatibility
- Native governance functionality through precompiles

## Technical Details
- Submitted via governance precompile at ${GOVERNANCE_PRECOMPILE_ADDRESS}
- Using ethers.js for transaction management
- Mainnet deployment with real SEI deposits

## Voting Recommendation
This is a test proposal. Vote according to your preference to test the system.`,
      type: 'Text',
      is_expedited: false
    };

    const proposalJSON = JSON.stringify(proposal);

    // Validate proposal
    if (!validateProposalJSON(proposalJSON)) {
      throw new Error('Invalid proposal JSON structure');
    }

    // Use mainnet-appropriate deposit
    const depositAmount = ethers.parseUnits('3500', 18); // Exactly minimum required

    if (!validateDepositAmount(depositAmount)) {
      throw new Error('Deposit amount insufficient for mainnet');
    }

    try {
      console.log(`   📋 Title: ${proposal.title}`);
      console.log(`   💵 Deposit: ${ethers.formatEther(depositAmount)} SEI`);
      console.log('   🚀 Submitting transaction...');

      const submitTx = await governance.submitProposal(proposalJSON, {
        value: depositAmount,
        gasLimit: 500000,
        gasPrice: ethers.parseUnits('100', 'gwei') // Set appropriate gas price
      });

      console.log(`   📝 Transaction hash: ${submitTx.hash}`);
      console.log('   ⏳ Waiting for confirmation...');

      const submitReceipt = await submitTx.wait();

      // Extract proposal ID safely
      let proposalID = null;
      for (const log of submitReceipt.logs) {
        try {
          const parsed = governance.interface.parseLog(log);
          if (parsed && parsed.name === 'ProposalSubmitted') {
            proposalID = parsed.args.proposalID;
            break;
          }
        } catch {
          continue;
        }
      }

      if (!proposalID) {
        console.log('   ⚠️  Could not extract proposal ID. Check transaction manually.');
        console.log(`   🔗 Transaction: https://seiscan.io/tx/${submitReceipt.hash}`);
        return;
      }

      console.log(`   ✅ Proposal submitted successfully!`);
      console.log(`   🆔 Proposal ID: ${proposalID.toString()}`);
      console.log(`   🔗 View proposal: https://sei.explorers.guru/proposal/${proposalID.toString()}`);

      // 2. Demonstrate voting
      console.log(`\n2️⃣  Voting on proposal ${proposalID.toString()}...`);

      const voteOption = 1; // Yes
      const voteNames = { 1: 'Yes', 2: 'Abstain', 3: 'No', 4: 'NoWithVeto' };

      console.log(`   🗳️  Vote option: ${voteNames[voteOption]}`);
      console.log('   🚀 Submitting vote...');

      const voteTx = await governance.vote(proposalID, voteOption, {
        gasLimit: 200000,
        gasPrice: ethers.parseUnits('100', 'gwei')
      });

      console.log(`   📝 Transaction hash: ${voteTx.hash}`);
      await voteTx.wait();

      console.log('   ✅ Vote cast successfully!');
      console.log(`   🔗 Transaction: https://seiscan.io/tx/${voteTx.hash}`);

      // 3. Demonstrate weighted voting
      console.log(`\n3️⃣  Casting weighted vote on proposal ${proposalID.toString()}...`);

      const weightedOptions = [
        { option: 1, weight: '0.7' }, // 70% Yes
        { option: 2, weight: '0.2' }, // 20% Abstain
        { option: 3, weight: '0.1' } // 10% No
        // CRITICAL: Total = 0.7 + 0.2 + 0.1 = 1.0 ✅
      ];

      if (!validateWeightedOptions(weightedOptions)) {
        throw new Error('CRITICAL: Invalid weighted options - transaction would fail');
      }

      console.log('   📊 Vote distribution:');
      weightedOptions.forEach(({ option, weight }) => {
        const percent = (parseFloat(weight) * 100).toFixed(1);
        console.log(`      ${percent}% ${voteNames[option]}`);
      });

      console.log('   🚀 Submitting weighted vote...');

      const weightedTx = await governance.voteWeighted(proposalID, weightedOptions, {
        gasLimit: 300000,
        gasPrice: ethers.parseUnits('100', 'gwei')
      });

      console.log(`   📝 Transaction hash: ${weightedTx.hash}`);
      await weightedTx.wait();

      console.log('   ✅ Weighted vote cast successfully!');
      console.log(`   🔗 Transaction: https://seiscan.io/tx/${weightedTx.hash}`);

      // 4. Add additional deposit
      console.log(`\n4️⃣  Adding deposit to proposal ${proposalID.toString()}...`);

      const additionalDeposit = ethers.parseUnits('500', 18); // 500 SEI

      console.log(`   💵 Additional deposit: ${ethers.formatEther(additionalDeposit)} SEI`);
      console.log('   🚀 Submitting deposit...');

      const depositTx = await governance.deposit(proposalID, {
        value: additionalDeposit,
        gasLimit: 200000,
        gasPrice: ethers.parseUnits('100', 'gwei')
      });

      console.log(`   📝 Transaction hash: ${depositTx.hash}`);
      await depositTx.wait();

      console.log('   ✅ Additional deposit added successfully!');
      console.log(`   🔗 Transaction: https://seiscan.io/tx/${depositTx.hash}`);

      // Summary
      console.log('\n🎉 === Governance Demo Completed Successfully! ===');
      console.log(`📊 Proposal ID: ${proposalID.toString()}`);
      console.log(`💰 Total deposited: ${ethers.formatEther(depositAmount + additionalDeposit)} SEI`);
      console.log('🔗 View all governance proposals: https://sei.explorers.guru/proposals');
    } catch (error) {
      if (error.message.includes('insufficient funds')) {
        console.log('\n❌ Insufficient funds for governance participation');
        console.log('   Ensure you have enough SEI for deposits and gas fees');
      } else if (error.message.includes('already voted')) {
        console.log('\n⚠️  You have already voted on this proposal');
      } else {
        throw error;
      }
    }
  } catch (error) {
    console.error('\n❌ Error:', error.message);
    console.log('\n🔧 Troubleshooting tips:');
    console.log('1. Ensure PRIVATE_KEY is set in .env file');
    console.log('2. Verify sufficient SEI balance (minimum 3,600 SEI)');
    console.log('3. Check network connectivity to Sei mainnet');
    console.log('4. Confirm wallet has staked SEI for voting power');
    process.exit(1);
  }
}

// Run the demo
main().catch(console.error);
```

### Running the Example

1. **Create a new directory and initialize npm:**

```bash theme={"dark"}
mkdir sei-governance-mainnet
cd sei-governance-mainnet
npm init -y
```

2. **Install dependencies:**

```bash theme={"dark"}
npm install ethers @sei-js/precompiles@^2.1.2 dotenv
```

3. **Create a `.env` file:**

```bash theme={"dark"}
PRIVATE_KEY=your_private_key_here
```

4. **Create the demo file:**
   Copy the complete integration example above into `governance-mainnet-demo.js`

5. **Ensure you have sufficient SEI:**

   * Minimum 3,500 SEI for proposal deposit
   * Additional SEI for gas and optional additional deposits
   * Staked SEI for voting power

6. **Run the script:**

```bash theme={"dark"}
node governance-mainnet-demo.js
```

### Expected Output

```
🌐 Connecting to Sei Mainnet...
👤 Wallet address: 0x742d35Cc6634C0532925a3b844Bc6789e065f3B
💰 Wallet balance: 5000.5 SEI

🏛️  === Sei Mainnet Governance Demo ===

1️⃣  Submitting a governance proposal...
   📋 Title: Demo: EVM Governance Integration Test
   💵 Deposit: 3500.0 SEI
   🚀 Submitting transaction...
   📝 Transaction hash: 0x123...abc
   ⏳ Waiting for confirmation...
   ✅ Proposal submitted successfully!
   🆔 Proposal ID: 42
   🔗 View proposal: https://sei.explorers.guru/proposal/42

2️⃣  Voting on proposal 42...
   🗳️  Vote option: Yes
   🚀 Submitting vote...
   📝 Transaction hash: 0x456...def
   ✅ Vote cast successfully!
   🔗 Transaction: https://seiscan.io/tx/0x456...def

3️⃣  Casting weighted vote on proposal 42...
   📊 Vote distribution:
      70.0% Yes
      20.0% Abstain
      10.0% No
   🚀 Submitting weighted vote...
   📝 Transaction hash: 0x789...ghi
   ✅ Weighted vote cast successfully!
   🔗 Transaction: https://seiscan.io/tx/0x789...ghi

4️⃣  Adding deposit to proposal 42...
   💵 Additional deposit: 500.0 SEI
   🚀 Submitting deposit...
   📝 Transaction hash: 0xabc...123
   ✅ Additional deposit added successfully!
   🔗 Transaction: https://seiscan.io/tx/0xabc...123

🎉 === Governance Demo Completed Successfully! ===
📊 Proposal ID: 42
💰 Total deposited: 4000.0 SEI
🔗 View all governance proposals: https://sei.explorers.guru/proposals
```

## Troubleshooting

### Common Issues and Solutions

#### Insufficient Deposit

```typescript theme={"dark"}
// Check minimum deposit requirement based on proposal type
const MINIMUM_DEPOSIT = ethers.parseUnits('3500', 18); // 3,500 SEI minimum
const EXPEDITED_DEPOSIT = ethers.parseUnits('7000', 18); // 7,000 SEI for expedited

function checkDepositRequirement(depositAmount: bigint, isExpedited: boolean = false): void {
  const requiredAmount = isExpedited ? EXPEDITED_DEPOSIT : MINIMUM_DEPOSIT;
  const networkName = 'mainnet';

  if (depositAmount < requiredAmount) {
    const required = ethers.formatEther(requiredAmount);
    const provided = ethers.formatEther(depositAmount);
    throw new Error(`Deposit too low for ${networkName}${isExpedited ? ' (expedited)' : ''}. Required: ${required} SEI, Provided: ${provided} SEI`);
  }
}
```

#### No Voting Power

```typescript theme={"dark"}
// Check if user has staked SEI for voting power
async function checkVotingEligibility(userAddress: string): Promise<void> {
  console.log('Checking voting eligibility...');

  // Note: You would typically integrate with staking queries here
  // This is a placeholder for the actual implementation

  console.log('⚠️  Reminder: You must have staked SEI to participate in governance voting');
  console.log('   Liquid SEI does not provide voting power');
  console.log('   Delegate your SEI to validators to gain voting power');
  console.log('   Visit: https://dashboard.sei.io/stake to stake your tokens');
}
```

#### Invalid Vote Option

```typescript theme={"dark"}
// Validate vote option with descriptive error
function validateVoteOptionWithDescription(option: number): void {
  const voteOptions = {
    1: 'Yes - Vote in favor of the proposal',
    2: 'Abstain - Neutral vote that counts toward quorum',
    3: 'No - Vote against the proposal',
    4: 'NoWithVeto - Strong opposition that can burn deposits'
  };

  if (!(option in voteOptions)) {
    const validOptions = Object.entries(voteOptions)
      .map(([key, value]) => `${key}: ${value}`)
      .join('\n');

    throw new Error(`Invalid vote option: ${option}\n\nValid options:\n${validOptions}`);
  }
}
```

#### Weighted Vote Validation

```typescript theme={"dark"}
// Comprehensive weighted vote validation with helpful errors
function validateWeightedVoteComprehensive(options: Array<{ option: number; weight: string }>): void {
  if (options.length === 0) {
    throw new Error('At least one vote option is required');
  }

  if (options.length > 4) {
    throw new Error('Cannot have more than 4 vote options');
  }

  let totalWeight = 0;
  const seenOptions = new Set<number>();
  const voteOptionNames = { 1: 'Yes', 2: 'Abstain', 3: 'No', 4: 'NoWithVeto' };

  for (let i = 0; i < options.length; i++) {
    const { option, weight } = options[i];

    // Validate option
    if (option < 1 || option > 4 || !Number.isInteger(option)) {
      throw new Error(
        `Invalid vote option at index ${i}: ${option}. Must be integer 1-4\n` +
          `Valid options: ${Object.entries(voteOptionNames)
            .map(([k, v]) => `${k}=${v}`)
            .join(', ')}`
      );
    }

    // Check for duplicate options
    if (seenOptions.has(option)) {
      throw new Error(`Duplicate vote option: ${option} (${voteOptionNames[option as keyof typeof voteOptionNames]})\n` + `Each vote option can only be used once`);
    }
    seenOptions.add(option);

    // Validate weight
    const weightNum = parseFloat(weight);
    if (isNaN(weightNum)) {
      throw new Error(`Invalid weight at index ${i}: "${weight}" is not a valid number`);
    }

    if (weightNum <= 0) {
      throw new Error(`Invalid weight at index ${i}: ${weight}. Weight must be greater than 0`);
    }

    if (weightNum > 1) {
      throw new Error(`Invalid weight at index ${i}: ${weight}. Weight cannot exceed 1.0`);
    }

    totalWeight += weightNum;
  }

  // Check total weight - CRITICAL for transaction success
  if (Math.abs(totalWeight - 1.0) > 0.000001) {
    const weightSummary = options.map(({ option, weight }) => `${voteOptionNames[option as keyof typeof voteOptionNames]}: ${weight}`).join(', ');

    throw new Error(`CRITICAL: Total weight must equal exactly 1.0, got ${totalWeight.toFixed(6)}\n` + `Current weights: ${weightSummary}\n` + `Sum: ${totalWeight.toFixed(6)}\n` + `Transaction will fail if weights don't sum to 1.0`);
  }
}
```

### Error Code Reference

| Error                       | Cause                                      | Solution                                                    |
| --------------------------- | ------------------------------------------ | ----------------------------------------------------------- |
| `proposal does not exist`   | Invalid proposal ID or proposal expired    | Verify proposal ID and ensure voting period is still active |
| `inactive proposal`         | Voting or deposit period has ended         | Check proposal status and timeline                          |
| `insufficient deposit`      | Deposit below 3,500 SEI                    | Increase deposit to the minimum required amount             |
| `invalid vote option`       | Vote option not 1-4                        | Use a valid option (1-Yes, 2-Abstain, 3-No, 4-NoWithVeto)   |
| `already voted`             | Address has already voted on this proposal | Each address can vote only once per proposal                |
| `weights must sum to 1`     | Weighted votes don’t sum to 1.0            | **CRITICAL —** adjust weights so they total exactly 1.0     |
| `insufficient voting power` | No staked SEI                              | Delegate SEI to validators to gain voting power             |
| `deposit period ended`      | Deposits no longer accepted                | Deposit period closes 2 days after submission               |

<Info>
  **Need Help?** If you encounter issues:

  * **Discord:** [Sei Community Discord](https://discord.gg/sei)
  * **GitHub:** [Sei Protocol Repository](https://github.com/sei-protocol/sei-chain)
  * **Explorer:** [View Proposals on Sei Explorer](https://sei.explorers.guru/proposals)
</Info>
