Overview

The Slashing precompile provides an interface to the Cosmos SDK’s x/slashing module, which is responsible for penalizing validators for misbehavior, such as downtime or double-signing. This precompile allows smart contracts to unjail validators and query slashing-related information, including validator signing info and module parameters. Precompile Address: 0x0000000000000000000000000000000000000806 Related Module: x/slashing

Gas Costs

Gas costs are approximated and may vary based on chain settings.
MethodGas Cost
Transactions2000 + (30 × bytes of input)
Queries1000 + (3 × bytes of input)

Transaction Methods

unjail

Allows a validator to unjail themselves after being jailed for downtime.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SlashingExample {
    address constant SLASHING_PRECOMPILE = 0x0000000000000000000000000000000000000806;
    
    struct SigningInfo {
        address validatorAddress;
        int64 startHeight;
        int64 indexOffset;
        int64 jailedUntil;
        bool tombstoned;
        int64 missedBlocksCounter;
    }
    
    event ValidatorUnjailed(address indexed validator);
    event ValidatorSlashingInfoQueried(address indexed validator, bool isJailed, bool isTombstoned);
    
    function unjailValidator(address validatorAddress) external returns (bool success) {
        require(validatorAddress != address(0), "Invalid validator address");
        
        // Check signing info to prevent unjailing tombstoned validators
        SigningInfo memory info = this.getValidatorSigningInfo(validatorAddress);
        require(!info.tombstoned, "Tombstoned validators cannot be unjailed");
        require(info.jailedUntil > int64(int256(block.timestamp)), "Validator is not jailed");
        
        (bool callSuccess, bytes memory result) = SLASHING_PRECOMPILE.call(
            abi.encodeWithSignature("unjail(address)", validatorAddress)
        );
        
        require(callSuccess, "Unjail call failed");
        success = abi.decode(result, (bool));
        require(success, "Unjail operation failed");
        
        emit ValidatorUnjailed(validatorAddress);
        return success;
    }
    
    function getValidatorSigningInfo(address consAddress) 
        external 
        view 
        returns (SigningInfo memory signingInfo) 
    {
        (bool success, bytes memory result) = SLASHING_PRECOMPILE.staticcall(
            abi.encodeWithSignature("getSigningInfo(address)", consAddress)
        );
        
        require(success, "Signing info query failed");
        signingInfo = abi.decode(result, (SigningInfo));
        return signingInfo;
    }
    
    function canValidatorBeUnjailed(address consAddress) 
        external 
        view 
        returns (bool canUnjail, string memory reason) 
    {
        SigningInfo memory info = this.getValidatorSigningInfo(consAddress);
        
        // CRITICAL: Tombstoned validators can NEVER be unjailed
        if (info.tombstoned) {
            return (false, "PERMANENT_TOMBSTONE: Validator can never be unjailed due to severe infractions (e.g., double-signing)");
        }
        
        if (info.jailedUntil <= int64(int256(block.timestamp))) {
            return (false, "Validator is not currently jailed");
        }
        
        return (true, "Validator can be unjailed");
    }
    
    function getValidatorStatus(address consAddress) 
        external 
        view 
        returns (bool isJailed, bool isTombstoned, int64 missedBlocks) 
    {
        SigningInfo memory info = this.getValidatorSigningInfo(consAddress);
        
        isJailed = info.jailedUntil > int64(int256(block.timestamp));
        isTombstoned = info.tombstoned;
        missedBlocks = info.missedBlocksCounter;
        
        emit ValidatorSlashingInfoQueried(consAddress, isJailed, isTombstoned);
        
        return (isJailed, isTombstoned, missedBlocks);
    }
}

Query Methods

getSigningInfo

Returns the signing information for a specific validator.
import { ethers } from "ethers";

// ABI definition for the function
const precompileAbi = [
  "function getSigningInfo(address consAddress) view returns (tuple(address validatorAddress, int64 startHeight, int64 indexOffset, int64 jailedUntil, bool tombstoned, int64 missedBlocksCounter) signingInfo)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000806";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

// Input: The consensus address of the validator
const consAddress = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"; // Placeholder

async function getSigningInfo() {
  try {
    const signingInfo = await contract.getSigningInfo(consAddress);
    console.log("Signing Info:", JSON.stringify(signingInfo, null, 2));
  } catch (error) {
    console.error("Error fetching signing info:", error);
  }
}

getSigningInfo();

getSigningInfos

Returns the signing information for all validators, with pagination support.
import { ethers } from "ethers";

// ABI definition for the function
const precompileAbi = [
  "function getSigningInfos(tuple(bytes key, uint64 offset, uint64 limit, bool countTotal, bool reverse) pagination) view returns (tuple(address validatorAddress, int64 startHeight, int64 indexOffset, int64 jailedUntil, bool tombstoned, int64 missedBlocksCounter)[] signingInfos, tuple(bytes nextKey, uint64 total) pageResponse)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000806";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

// Input for pagination
const pagination = {
  key: "0x",
  offset: 0,
  limit: 10,
  countTotal: true,
  reverse: false,
};

async function getSigningInfos() {
  try {
    const result = await contract.getSigningInfos(pagination);
    console.log("Signing Infos:", JSON.stringify(result.signingInfos, null, 2));
    console.log("Pagination Response:", result.pageResponse);
  } catch (error) {
    console.error("Error fetching signing infos:", error);
  }
}

getSigningInfos();

getParams

Returns the current parameters for the slashing module.
import { ethers } from "ethers";

// ABI definition for the function
const precompileAbi = [
  "function getParams() view returns (tuple(int64 signedBlocksWindow, tuple(uint256 value, uint8 precision) minSignedPerWindow, int64 downtimeJailDuration, tuple(uint256 value, uint8 precision) slashFractionDoubleSign, tuple(uint256 value, uint8 precision) slashFractionDowntime) params)"
];

// Provider and contract setup
const provider = new ethers.JsonRpcProvider("<RPC_URL>");
const precompileAddress = "0x0000000000000000000000000000000000000806";
const contract = new ethers.Contract(precompileAddress, precompileAbi, provider);

async function getParams() {
  try {
    const params = await contract.getParams();
    console.log("Slashing Parameters:", JSON.stringify(params, null, 2));
  } catch (error) {
    console.error("Error fetching slashing parameters:", error);
  }
}

getParams();

Full Solidity Interface & ABI

Slashing Solidity Interface
// SPDX-License-Identifier: LGPL-3.0-only
pragma solidity >=0.8.17;

import "../common/Types.sol";

/// @dev The ISlashing contract's address.
address constant SLASHING_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000806;

/// @dev The ISlashing contract's instance.
ISlashing constant SLASHING_CONTRACT = ISlashing(SLASHING_PRECOMPILE_ADDRESS);

/// @dev SigningInfo defines a validator's signing info for monitoring their
/// liveness activity.
struct SigningInfo {
    /// @dev Address of the validator
    address validatorAddress;
    /// @dev Height at which validator was first a candidate OR was unjailed
    int64 startHeight;
    /// @dev Index offset into signed block bit array
    int64 indexOffset;
    /// @dev Timestamp until which validator is jailed due to liveness downtime
    int64 jailedUntil;
    /// @dev Whether or not a validator has been tombstoned (killed out of validator set)
    bool tombstoned;
    /// @dev Missed blocks counter (to avoid scanning the array every time)
    int64 missedBlocksCounter;
}

/// @dev Params defines the parameters for the slashing module.
struct Params {
    /// @dev SignedBlocksWindow defines how many blocks the validator should have signed
    int64 signedBlocksWindow;
    /// @dev MinSignedPerWindow defines the minimum blocks signed per window to avoid slashing
    Dec minSignedPerWindow;
    /// @dev DowntimeJailDuration defines how long the validator will be jailed for downtime
    int64 downtimeJailDuration;
    /// @dev SlashFractionDoubleSign defines the percentage of slash for double sign
    Dec slashFractionDoubleSign;
    /// @dev SlashFractionDowntime defines the percentage of slash for downtime
    Dec slashFractionDowntime;
}

/// @author Evmos Team
/// @title Slashing Precompiled Contract
/// @dev The interface through which solidity contracts will interact with slashing.
/// We follow this same interface including four-byte function selectors, in the precompile that
/// wraps the pallet.
/// @custom:address 0x0000000000000000000000000000000000000806
interface ISlashing {
    /// @dev Emitted when a validator is unjailed
    /// @param validator The address of the validator
    event ValidatorUnjailed(address indexed validator);

    /// @dev GetSigningInfo returns the signing info for a specific validator.
    /// @param consAddress The validator consensus address
    /// @return signingInfo The validator signing info
    function getSigningInfo(
        address consAddress
    ) external view returns (SigningInfo memory signingInfo);

    /// @dev GetSigningInfos returns the signing info for all validators.
    /// @param pagination Pagination configuration for the query
    /// @return signingInfos The list of validator signing info
    /// @return pageResponse Pagination information for the response
    function getSigningInfos(
        PageRequest calldata pagination
    ) external view returns (SigningInfo[] memory signingInfos, PageResponse memory pageResponse);

    /// @dev Unjail allows validators to unjail themselves after being jailed for downtime
    /// @param validatorAddress The validator operator address to unjail
    /// @return success true if the unjail operation was successful
    function unjail(address validatorAddress) external returns (bool success);

    /// @dev GetParams returns the slashing module parameters
    /// @return params The slashing module parameters
    function getParams() external view returns (Params memory params);
}
Slashing ABI
{
  "_format": "hh-sol-artifact-1",
  "contractName": "ISlashing",
  "sourceName": "solidity/precompiles/slashing/ISlashing.sol",
  "abi": [
    {
      "anonymous": false,
      "inputs": [
        {
          "indexed": true,
          "internalType": "address",
          "name": "validator",
          "type": "address"
        }
      ],
      "name": "ValidatorUnjailed",
      "type": "event"
    },
    {
      "inputs": [],
      "name": "getParams",
      "outputs": [
        {
          "components": [
            {
              "internalType": "int64",
              "name": "signedBlocksWindow",
              "type": "int64"
            },
            {
              "components": [
                {
                  "internalType": "uint256",
                  "name": "value",
                  "type": "uint256"
                },
                {
                  "internalType": "uint8",
                  "name": "precision",
                  "type": "uint8"
                }
              ],
              "internalType": "struct Dec",
              "name": "minSignedPerWindow",
              "type": "tuple"
            },
            {
              "internalType": "int64",
              "name": "downtimeJailDuration",
              "type": "int64"
            },
            {
              "components": [
                {
                  "internalType": "uint256",
                  "name": "value",
                  "type": "uint256"
                },
                {
                  "internalType": "uint8",
                  "name": "precision",
                  "type": "uint8"
                }
              ],
              "internalType": "struct Dec",
              "name": "slashFractionDoubleSign",
              "type": "tuple"
            },
            {
              "components": [
                {
                  "internalType": "uint256",
                  "name": "value",
                  "type": "uint256"
                },
                {
                  "internalType": "uint8",
                  "name": "precision",
                  "type": "uint8"
                }
              ],
              "internalType": "struct Dec",
              "name": "slashFractionDowntime",
              "type": "tuple"
            }
          ],
          "internalType": "struct Params",
          "name": "params",
          "type": "tuple"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "consAddress",
          "type": "address"
        }
      ],
      "name": "getSigningInfo",
      "outputs": [
        {
          "components": [
            {
              "internalType": "address",
              "name": "validatorAddress",
              "type": "address"
            },
            {
              "internalType": "int64",
              "name": "startHeight",
              "type": "int64"
            },
            {
              "internalType": "int64",
              "name": "indexOffset",
              "type": "int64"
            },
            {
              "internalType": "int64",
              "name": "jailedUntil",
              "type": "int64"
            },
            {
              "internalType": "bool",
              "name": "tombstoned",
              "type": "bool"
            },
            {
              "internalType": "int64",
              "name": "missedBlocksCounter",
              "type": "int64"
            }
          ],
          "internalType": "struct SigningInfo",
          "name": "signingInfo",
          "type": "tuple"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "key",
              "type": "bytes"
            },
            {
              "internalType": "uint64",
              "name": "offset",
              "type": "uint64"
            },
            {
              "internalType": "uint64",
              "name": "limit",
              "type": "uint64"
            },
            {
              "internalType": "bool",
              "name": "countTotal",
              "type": "bool"
            },
            {
              "internalType": "bool",
              "name": "reverse",
              "type": "bool"
            }
          ],
          "internalType": "struct PageRequest",
          "name": "pagination",
          "type": "tuple"
        }
      ],
      "name": "getSigningInfos",
      "outputs": [
        {
          "components": [
            {
              "internalType": "address",
              "name": "validatorAddress",
              "type": "address"
            },
            {
              "internalType": "int64",
              "name": "startHeight",
              "type": "int64"
            },
            {
              "internalType": "int64",
              "name": "indexOffset",
              "type": "int64"
            },
            {
              "internalType": "int64",
              "name": "jailedUntil",
              "type": "int64"
            },
            {
              "internalType": "bool",
              "name": "tombstoned",
              "type": "bool"
            },
            {
              "internalType": "int64",
              "name": "missedBlocksCounter",
              "type": "int64"
            }
          ],
          "internalType": "struct SigningInfo[]",
          "name": "signingInfos",
          "type": "tuple[]"
        },
        {
          "components": [
            {
              "internalType": "bytes",
              "name": "nextKey",
              "type": "bytes"
            },
            {
              "internalType": "uint64",
              "name": "total",
              "type": "uint64"
            }
          ],
          "internalType": "struct PageResponse",
          "name": "pageResponse",
          "type": "tuple"
        }
      ],
      "stateMutability": "view",
      "type": "function"
    },
    {
      "inputs": [
        {
          "internalType": "address",
          "name": "validatorAddress",
          "type": "address"
        }
      ],
      "name": "unjail",
      "outputs": [
        {
          "internalType": "bool",
          "name": "success",
          "type": "bool"
        }
      ],
      "stateMutability": "nonpayable",
      "type": "function"
    }
  ]
}