Staking

Validator operations, delegation management, and staking functionality

Overview

The Staking precompile provides a comprehensive interface to the Ontomir SDK's x/staking module, enabling smart contracts to engage in staking activities. This includes creating and managing validators, delegating and undelegating tokens, and querying a wide range of staking-related information, such as validator details, delegation records, and staking pool status.

Precompile Address: 0x0000000000000000000000000000000000000800

Gas Costs

Gas costs are approximated and may vary based on the complexity of the staking operation and chain settings.

Method
Gas Cost

Transactions

2000 + (30 × bytes of input)

Queries

1000 + (3 × bytes of input)

Transaction Methods

createValidator

Creates a new validator.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { struct Description { string moniker; string identity; string website; string securityContact; string details; } struct CommissionRates { uint256 rate; uint256 maxRate; uint256 maxChangeRate; } function createValidator( Description memory description, CommissionRates memory commissionRates, uint256 minSelfDelegation, address validatorAddress, string memory pubkey, uint256 value ) external returns (bool success);

}

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event ValidatorCreated(address indexed validatorAddress, string moniker, uint256 value); error InvalidInput(); error InsufficientValue(); error StakingOperationFailed(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function createNewValidator( IStaking.Description calldata description, IStaking.CommissionRates calldata commissionRates, uint256 minSelfDelegation, string calldata pubkey, uint256 value ) external payable returns (bool success) { if (msg.value < value) revert InsufficientValue(); if (bytes(description.moniker).length == 0) revert InvalidInput(); if (bytes(pubkey).length == 0) revert InvalidInput(); try staking.createValidator( description, commissionRates, minSelfDelegation, msg.sender, pubkey, value ) returns (bool result) { if (!result) revert StakingOperationFailed(); emit ValidatorCreated(msg.sender, description.moniker, value); return result; } catch { revert StakingOperationFailed(); } }

}

editValidator

Edits an existing validator's parameters.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { struct Description { string moniker; string identity; string website; string securityContact; string details; } function editValidator( Description memory description, uint256 commissionRate, uint256 minSelfDelegation ) external returns (bool success);

}

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event ValidatorUpdated(address indexed validatorAddress, string moniker); error InvalidInput(); error StakingOperationFailed(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function updateValidator( IStaking.Description calldata description, uint256 commissionRate, uint256 minSelfDelegation ) external returns (bool success) { if (bytes(description.moniker).length == 0) revert InvalidInput(); try staking.editValidator(description, commissionRate, minSelfDelegation) returns (bool result) { if (!result) revert StakingOperationFailed(); emit ValidatorUpdated(msg.sender, description.moniker); return result; } catch { revert StakingOperationFailed(); } }

}

delegate

Delegates tokens to a validator.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { function delegate(address delegatorAddress, string memory validatorAddress, uint256 amount) external returns (bool success); }

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event DelegationSuccess(address indexed delegator, string indexed validator, uint256 amount); error InvalidAmount(); error InvalidValidator(); error StakingOperationFailed(); error InsufficientBalance(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function delegateTokens(string calldata validatorAddress, uint256 amount) external payable { if (amount == 0) revert InvalidAmount(); if (msg.value != amount) revert InsufficientBalance(); if (bytes(validatorAddress).length == 0) revert InvalidValidator(); try staking.delegate(msg.sender, validatorAddress, amount) returns (bool success) { if (!success) revert StakingOperationFailed(); emit DelegationSuccess(msg.sender, validatorAddress, amount); } catch { revert StakingOperationFailed(); } }

}

undelegate

Undelegates tokens from a validator.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { function beginUnbonding(address delegatorAddress, string memory validatorAddress, uint256 amount) external returns (int64 completionTime); }

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event UndelegationStarted(address indexed delegator, string indexed validator, uint256 amount, int64 completionTime); error InvalidAmount(); error InvalidValidator(); error StakingOperationFailed(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function undelegateTokens(string calldata validatorAddress, uint256 amount) external returns (int64 completionTime) { if (amount == 0) revert InvalidAmount(); if (bytes(validatorAddress).length == 0) revert InvalidValidator(); try staking.beginUnbonding(msg.sender, validatorAddress, amount) returns (int64 completion) { completionTime = completion; emit UndelegationStarted(msg.sender, validatorAddress, amount, completionTime); return completionTime; } catch { revert StakingOperationFailed(); } } // Helper function to calculate days until completion function getDaysUntilCompletion(int64 completionTime) external view returns (uint256 days) { if (completionTime <= int64(block.timestamp)) { return 0; } return uint256(uint64(completionTime - int64(block.timestamp))) / 86400; }

}

redelegate

Redelegates tokens from one validator to another.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { function beginRedelegate( address delegatorAddress, string memory validatorSrcAddress, string memory validatorDstAddress, uint256 amount ) external returns (int64 completionTime); }

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event RedelegationStarted( address indexed delegator, string indexed srcValidator, string indexed dstValidator, uint256 amount, int64 completionTime ); error InvalidValidator(); error InvalidAmount(); error SameValidator(); error StakingOperationFailed(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function redelegateTokens( string calldata srcValidatorAddress, string calldata dstValidatorAddress, uint256 amount ) external returns (int64 completionTime) { if (bytes(srcValidatorAddress).length == 0) revert InvalidValidator(); if (bytes(dstValidatorAddress).length == 0) revert InvalidValidator(); if (amount == 0) revert InvalidAmount(); if (keccak256(bytes(srcValidatorAddress)) == keccak256(bytes(dstValidatorAddress))) { revert SameValidator(); } try staking.beginRedelegate(msg.sender, srcValidatorAddress, dstValidatorAddress, amount) returns (int64 completion) { completionTime = completion; emit RedelegationStarted(msg.sender, srcValidatorAddress, dstValidatorAddress, amount, completionTime); return completionTime; } catch { revert StakingOperationFailed(); } }

}

cancelUnbondingDelegation

Cancels an unbonding delegation.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { function cancelUnbondingDelegation( address delegatorAddress, string memory validatorAddress, uint256 amount, int64 creationHeight ) external returns (bool success); }

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event UnbondingCancelled( address indexed delegator, string indexed validator, uint256 amount, int64 creationHeight ); error InvalidHeight(); error InvalidAmount(); error InvalidValidator(); error StakingOperationFailed(); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function cancelUnbonding( string calldata validatorAddress, uint256 amount, int64 creationHeight ) external returns (bool success) { if (creationHeight <= 0) revert InvalidHeight(); if (amount == 0) revert InvalidAmount(); if (bytes(validatorAddress).length == 0) revert InvalidValidator(); try staking.cancelUnbondingDelegation(msg.sender, validatorAddress, amount, creationHeight) returns (bool result) { if (!result) revert StakingOperationFailed(); emit UnbondingCancelled(msg.sender, validatorAddress, amount, creationHeight); return result; } catch { revert StakingOperationFailed(); } }

}

Query Methods

validator

Queries information about a specific validator.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile (matches ~/repos/evm ABI) interface IStaking { struct Validator { string operatorAddress; string consensusPubkey; bool jailed; uint8 status; // BondStatus enum as uint8 uint256 tokens; uint256 delegatorShares; // uint256 string description; // string, not a nested struct int64 unbondingHeight; int64 unbondingTime; // int64 uint256 commission; // uint256 uint256 minSelfDelegation; } function validator(address validatorAddress) external view returns (Validator memory);

}

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event ValidatorQueried(address indexed validatorAddress, string operatorAddress, uint256 tokens); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function getValidator(address validatorAddress) external view returns (IStaking.Validator memory validator) { validator = staking.validator(validatorAddress); return validator; } function getValidatorInfo(address validatorAddress) external returns (string memory operatorAddress, uint256 tokens, bool jailed) { IStaking.Validator memory validator = staking.validator(validatorAddress); operatorAddress = validator.operatorAddress; tokens = validator.tokens; jailed = validator.jailed; emit ValidatorQueried(validatorAddress, operatorAddress, tokens); return (operatorAddress, tokens, jailed); }

}

validators

Queries validators with optional status filtering and pagination.

```javascript Ethers.js expandable lines import { ethers } from "ethers";

// ABI definition for the function const precompileAbi = [ "function validators(string memory status, tuple(bytes key, uint64 offset, uint64 limit, bool countTotal, bool reverse) pageRequest) view returns (tuple(string operatorAddress, string consensusPubkey, bool jailed, uint32 status, uint256 tokens, string delegatorShares, tuple(string moniker, string identity, string website, string securityContact, string details) description, int64 unbondingHeight, uint256 unbondingTime, tuple(tuple(string rate, string maxRate, string maxChangeRate) commissionRates, uint256 updateTime) commission, uint256 minSelfDelegation)[] validators, tuple(bytes nextKey, uint64 total) pageResponse)" ];

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

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

async function getValidators() { try { const result = await contract.validators(status, pagination); console.log("Validators:", JSON.stringify(result.validators, null, 2)); console.log("Pagination Response:", result.pageResponse); } catch (error) { console.error("Error fetching validators:", error); } }

getValidators();

delegation

Queries the delegation amount between a delegator and a validator.

```javascript Ethers.js expandable lines import { ethers } from "ethers";

// ABI definition for the function const precompileAbi = [ "function delegation(address delegatorAddress, string memory validatorAddress) view returns (uint256 shares, tuple(string denom, uint256 amount) balance)" ];

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

// Inputs const delegatorAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Example delegator const validatorAddress = "Ontomirvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pw4xyrql"; // Example validator

async function getDelegation() { try { const [shares, balance] = await contract.delegation(delegatorAddress, validatorAddress); console.log("Delegation Shares:", shares.toString()); console.log("Balance:", balance); } catch (error) { console.error("Error fetching delegation:", error); } }

getDelegation();

unbondingDelegation

Queries unbonding delegation information.

```javascript Ethers.js expandable lines import { ethers } from "ethers";

// ABI definition for the function const precompileAbi = [ "function unbondingDelegation(address delegatorAddress, string validatorAddress) view returns (tuple(string delegatorAddress, string validatorAddress, tuple(int64 creationHeight, int64 completionTime, uint256 initialBalance, uint256 balance, uint64 unbondingId, int64 unbondingOnHoldRefCount)[] entries) unbondingDelegation)" ];

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

// Inputs const delegatorAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Example delegator const validatorAddress = "Ontomirvaloper10jmp6sgh4cc6zt3e8gw05wavvejgr5pw4xyrql"; // Example validator

async function getUnbondingDelegation() { try { const unbonding = await contract.unbondingDelegation(delegatorAddress, validatorAddress); console.log("Unbonding Delegation:", JSON.stringify(unbonding, null, 2)); } catch (error) { console.error("Error fetching unbonding delegation:", error); } }

getUnbondingDelegation();

redelegation

Queries a specific redelegation.

```solidity Solidity expandable lines // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

// Interface for the Staking precompile interface IStaking { struct RedelegationEntry { int64 creationHeight; int64 completionTime; uint256 initialBalance; uint256 sharesDst; uint64 unbondingId; int64 unbondingOnHoldRefCount; } struct Redelegation { string delegatorAddress; string validatorSrcAddress; string validatorDstAddress; RedelegationEntry[] entries; } function redelegation( address delegatorAddress, string memory validatorSrcAddress, string memory validatorDstAddress ) external view returns (Redelegation memory);

}

contract StakingExample { address constant STAKING_PRECOMPILE = 0x0000000000000000000000000000000000000800; IStaking public immutable staking; event RedelegationQueried( address indexed delegator, string srcValidator, string dstValidator, uint256 entriesCount ); constructor() { staking = IStaking(STAKING_PRECOMPILE); } function getRedelegation( address delegatorAddress, string calldata srcValidatorAddress, string calldata dstValidatorAddress ) external view returns (IStaking.Redelegation memory redelegation) { redelegation = staking.redelegation(delegatorAddress, srcValidatorAddress, dstValidatorAddress); return redelegation; } function getRedelegationInfo( address delegatorAddress, string calldata srcValidatorAddress, string calldata dstValidatorAddress ) external returns (uint256 entriesCount, bool hasActiveRedelegations) { IStaking.Redelegation memory redelegation = staking.redelegation( delegatorAddress, srcValidatorAddress, dstValidatorAddress ); entriesCount = redelegation.entries.length; hasActiveRedelegations = entriesCount > 0; // Check if any redelegations are still active for (uint256 i = 0; i < redelegation.entries.length; i++) { if (redelegation.entries[i].completionTime > int64(int256(block.timestamp))) { hasActiveRedelegations = true; break; } } emit RedelegationQueried(delegatorAddress, srcValidatorAddress, dstValidatorAddress, entriesCount); return (entriesCount, hasActiveRedelegations); } // Check if redelegation is complete function isRedelegationComplete(RedelegationOutput memory redelegation) external view returns (bool) { for (uint i = 0; i < redelegation.entries.length; i++) { if (redelegation.entries[i].completionTime > int64(block.timestamp)) { return false; } } return true; }

}

redelegations

Queries redelegations with optional filters.

```javascript Ethers.js expandable lines import { ethers } from "ethers";

// ABI definition for the function const precompileAbi = [ "function redelegations(address delegatorAddress, string srcValidatorAddress, string dstValidatorAddress, tuple(bytes key, uint64 offset, uint64 limit, bool countTotal, bool reverse) pageRequest) view returns (tuple(tuple(string delegatorAddress, string validatorSrcAddress, string validatorDstAddress, tuple(int64 creationHeight, int64 completionTime, uint256 initialBalance, uint256 sharesDst)[] entries) redelegation, tuple(tuple(int64 creationHeight, int64 completionTime, uint256 initialBalance, uint256 sharesDst) redelegationEntry, uint256 balance)[] entries)[] redelegations, tuple(bytes nextKey, uint64 total) pageResponse)" ];

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

// Inputs const delegatorAddress = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; // Example delegator const srcValidatorAddress = ""; // Empty string for all const dstValidatorAddress = ""; // Empty string for all const pagination = { key: "0x", offset: 0, limit: 10, countTotal: true, reverse: false, };

async function getRedelegations() { try { const result = await contract.redelegations(delegatorAddress, srcValidatorAddress, dstValidatorAddress, pagination); console.log("Redelegations:", JSON.stringify(result.redelegations, null, 2)); console.log("Pagination Response:", result.pageResponse); } catch (error) { console.error("Error fetching redelegations:", error); } }

getRedelegations();

Note: The pool() and params() functions are not currently available in this staking precompile implementation. The available query methods are limited to delegation-specific functions shown above.

Full Solidity Interface & ABI