Staking (RUJI, bRUNE, TCY)

Technical documentation for wallets, portfolio apps, staking dashboards, and user-facing apps integrating staking markets powered by the Rujira staking contract.

This guide is scoped to user-owned staking positions. It does not cover protocol/operator revenue setup, revenue converter administration, or contract sudo messages.

Overview

The Rujira staking contract is generic. A deployed staking market can be configured for RUJI, bRUNE, TCY, or another supported bond token. Each market has its own contract address and config.

A staking market supports two user paths:

Path
User sends
User receives
Reward behavior

Account staking

The market's bond_denom

Account staking position (non-transferable)

Rewards accrue as revenue_denom and are claimed manually.

Liquid staking

The market's bond_denom

Liquid staking receipt tokens (transferable)

Rewards are converted into more bond_denom, increasing the value of each receipt token.

Always query the staking contract config before building transactions. The contract tells you which token to stake through bond_denom and which reward token account stakers can claim through revenue_denom.

Existing Staking Markets

Use this table as an integration hint, not as the source of truth. The live contract config should still be queried before every staking flow.

Market
Bond denom
Typical display
Liquid receipt denom
Receipt display

RUJI staking

x/ruji

RUJI

x/staking-x/ruji

sRUJI

bRUNE staking

x/brune

bRUNE

x/staking-x/brune

ybRUNE

TCY staking

tcy

TCY

x/staking-tcy

sTCY

The bank metadata for x/ruji, x/brune, and the liquid receipt denoms uses 8 display decimals. The tcy supply exists on chain, but the bank metadata endpoint may not return a base metadata object for tcy; clients should use the chain/app asset registry or a maintained token list as a display fallback.

Who This Guide Is For

Integrator
Typical integration

Wallets

Show RUJI balance, account stake, pending revenue, liquid receipt balance, and sign bond/claim/withdraw/unbond transactions.

Portfolio apps

Display account positions, pending rewards, liquid share positions, and pool status.

Staking UIs

Provide standard staking and auto-compounding staking flows.

Card or repayment apps

Let users claim staking revenue and then use the claimed funds in the app's own repayment flow.

Prerequisites

  • The user needs a THOR/Rujira app-layer address.

  • The user needs the staking bond_denom; for RUJI staking this is x/ruji.

  • Account staking rewards are paid in revenue_denom, which should be read from contract config.

  • Liquid staking receipt token denom is derived from the bond denom: x/staking-<bond_denom>.

  • All Uint128 amounts are strings in JSON.

Useful references:

Architecture

Do not call settle directly. It is an internal self-call used by the staking contract after revenue conversion.

Contract Address and Config

The current staking contract addresses should be read from official deployment data. If static addresses are needed in a downstream guide, verify them first against the Rujira deployment page and look for the relevant rujira-staking instances.

Model staking markets by contract address:

Query config before rendering the staking UI:

Example response shape:

Field
Meaning for user integrations

bond_denom

Token users bond into this staking market. Examples: x/ruji, x/brune, tcy.

revenue_denom

Token account stakers claim as rewards.

revenue_converter

Converter used internally to compound liquid staking rewards. Wallet UIs should display or ignore this, not execute it.

fee

Optional protocol fee on distributable revenue, shaped as [percentage, recipient].

Do not hardcode the reward token from product copy. Different staking markets can pay different revenue_denom assets, and the live config is the source of truth for transaction builders.

Staking Concepts

Account Staking vs. Liquid Staking

Account staking and liquid staking use the same bond token, but they behave differently.

Concept
Account staking
Liquid staking

Execute namespace

account

liquid

User sends

bond_denom

bond_denom

User receives

Stored account position

Receipt token balance

Rewards

Claimed manually as revenue_denom

Converted into more bond_denom in the pool

Exit

account.withdraw

liquid.unbond with receipt token funds

Liquid Receipt Denom

The liquid receipt denom is:

Examples:

Bond denom
Receipt denom

x/ruji

x/staking-x/ruji

x/brune

x/staking-x/brune

tcy

x/staking-tcy

Derive this from config in code:

Do not assume the receipt denom from the display symbol. Use the bank denom.

Revenue Distribution Timing

Revenue distribution is lazy. Sending revenue_denom to the staking contract does not immediately update every account. The contract distributes pending revenue at the start of the next account or liquid staking execute.

For UI, this means:

  • status shows the current stored state plus raw undistributed revenue.

  • account.pending_revenue can change after any staking action triggers distribution.

  • Re-query status, account, and bank balances after every staking transaction.

Query Integration

Query Status

Response shape:

Field
Meaning

account_bond

Total bond_denom bonded in account staking.

assigned_revenue

Total revenue_denom already assigned to account stakers but not yet claimed.

liquid_bond_shares

Total liquid receipt shares issued.

liquid_bond_size

Total bond_denom backing the liquid staking pool.

undistributed_revenue

revenue_denom currently in the contract but not yet distributed.

For liquid staking display, the simple pool ratio is:

If liquid_bond_shares is zero, show the ratio as zero or unavailable.

Query Account

Response shape:

account only works for addresses that have an account staking record. If the query returns not found, show a zero account position:

There is no account-list query and no pagination in the staking contract.

Account Staking Integration

Account staking is the standard staking path where the user bonds the market token and manually claims rewards.

Bond

Funds:

Use config.bond_denom for the funds denom. Send only the bond denom.

If the account already has pending rewards, bond claims those rewards first and sends them to the user before increasing the bonded amount.

Claim

Claim is nonpayable. Send no funds.

If there are claimable rewards, the contract sends revenue_denom to the user. If the user already has an account staking record and rewards are zero, the transaction can still complete and emit a zero-amount claim event. If the user has never bonded, do not offer claim; there is no account record yet.

Withdraw

Partial withdraw:

Full withdraw:

Withdraw is nonpayable. Send no funds.

Withdraw requires an existing account staking record. It always claims pending rewards first. The payout can include both bond_denom and revenue_denom.

TypeScript Example: Account Bond

TypeScript Example: Claim and Use Rewards

This is the wallet/user flow a card or repayment app should use. The staking contract claims rewards to the user first; the app then uses the user's resulting revenue_denom balance in its own repayment flow.

Liquid Staking Integration

Liquid staking is the auto-compounding path. The user bonds the market token and receives receipt tokens. As revenue is converted into more bond_denom, the pool size grows and each receipt token represents more underlying bond token.

Bond

Funds:

The contract mints receipt tokens to the user. Derive the receipt denom from config:

Unbond

Funds:

Liquid unbond burns receipt tokens and returns the user's proportional bond_denom. The returned amount depends on the current pool ratio and is floor-rounded by share-pool math.

TypeScript Example: Liquid Bond and Unbond

Events

CosmWasm event types usually appear in indexed transaction logs with a wasm- prefix.

Account staking events:

Event
Attributes

account.bond

owner, amount

account.claim

owner, amount

account.withdraw

owner, amount, rewards

Liquid staking events:

Event
Attributes

liquid.bond

owner, amount, shares

liquid.unbond

owner, shares, returned

Internal settlement event:

settle has a returned attribute and is emitted by the contract's internal revenue-conversion flow. User interfaces can index it, but users should not build or sign settle messages.

Use events for fast UI updates, but re-query contract state and bank balances after the transaction is indexed.

UI and UX Checklist

  • Show account staking and liquid staking as separate modes.

  • Query config first and use its bond_denom and revenue_denom.

  • Display the bond token from bank metadata or a maintained token registry. Do not hardcode a single staking denom.

  • For TCY, handle metadata fallback because tcy may not return a base bank metadata object even though the denom exists on chain.

  • For account staking, show bonded and pending_revenue.

  • For account staking, explain that rewards are claimable manually in revenue_denom.

  • For liquid staking, show receipt token balance and estimated underlying bond_denom.

  • For liquid staking, explain that rewards compound by increasing pool value, not by sending revenue directly to the user.

  • For card or repayment apps, claim rewards first, then use the user's claimed balance in the app repayment flow.

  • Prevent users from attaching funds to claim or withdraw.

  • Prevent users from sending config.bond_denom to liquid.unbond; it requires the receipt token.

  • Refresh status, account, and bank balances after every transaction.

Common Errors and Gotchas

Issue
Why it happens
Integrator fix

Wrong funds denom on bond

Account and liquid bond require bond_denom.

Query config and send only config.bond_denom.

Claim sent with funds

account.claim is nonpayable.

Send no funds.

Withdraw sent with funds

account.withdraw is nonpayable.

Send no funds.

Liquid unbond sends the bond token

liquid.unbond burns receipt tokens, not bond tokens.

Send x/staking-<bond_denom> funds.

Account query fails for a new user

The account record does not exist until the user bonds.

Treat not found as zero bonded and zero pending revenue.

Claim or withdraw fails for a new user

There is no account staking record yet.

Disable claim and withdraw until the user has an account position.

Pending rewards look stale

Distribution runs lazily during staking executes.

Re-query after transactions and explain update timing.

User expects liquid rewards as the account reward token

Liquid rewards are converted into more bond token value.

Show pool ratio and receipt-token underlying value.

Tiny liquid bond mints zero shares

Share math floors issuance.

Block very small deposits or explain the failure.

Unbond amount exceeds receipt balance

Share pool rejects over-unbonding.

Check the user's receipt token balance before signing.

Message Reference

Queries

Executes

Do not use this internal message in wallet or user integrations:

Last updated