Stake Tokens and Assets


Staking is the process of locking up tokens or assets (NFTs) to a specific receiver, often to secure a network, participate in governance, or earn rewards. This guide provides a step-by-step walkthrough of the entire staking lifecycle using the OCAP Client, including creating a stake, revoking it, claiming the assets back, and slashing a stake for punitive reasons.

This process involves a few key methods:

  • stake(): To create a new stake.
  • revokeStake(): To initiate the process of withdrawing your staked items.
  • claimStake(): To finalize the withdrawal and return the items to your account.
  • slashStake(): To allow authorized parties to penalize a staker.

How to Stake#

To begin, you use the stake method to lock your tokens or assets. This action creates a new, unique stake address on the chain that holds your staked items and the rules governing them.

Parameters#

to
string
required
The DID address of the account that will receive the stake.
assets
string[]
An array of asset addresses (NFTs) to be staked.
tokens
object[]
An array of token objects to be staked.
2 subfields
wallet
WalletObject
required
The wallet object of the staker.
locked
boolean
default:false
A boolean indicating if the stake is locked upon creation.
slashers
string[]
An array of DID addresses permitted to slash this stake. Defaults to the receiver's address if not provided.
message
string
An optional note or message for the stake.
nonce
string
An optional nonce to ensure the stake address is unique.

Example#

Staking Tokens and an Asset

// Assume 'client' is an initialized GraphQLClient instance
// and 'stakerWallet' is a valid wallet object.
const receiverAddress = 'z29d5852576b8a8b6f3a8b4b74a3f4a3e2e1d'; // The address of the stake receiver

async function createStake() {
  try {
    const [txHash, stakeAddress] = await client.stake({
      to: receiverAddress,
      tokens: [{
        address: 'z35n6aTUTK8h5nAF43h21A1g84g3C3D7B5E', // Address of the token to stake
        value: 100, // Amount of tokens to stake
      }],
      assets: ['zNKtA1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6'], // Address of the asset/NFT to stake
      message: 'Staking for validator rewards',
      wallet: stakerWallet,
    });

    console.log('Stake transaction sent:', txHash);
    console.log('New stake address created:', stakeAddress);
    return stakeAddress;
  } catch (error) {
    console.error('Error creating stake:', error);
  }
}

Return Value#

The stake method returns a tuple containing the transaction hash and the newly created stakeAddress. This address is crucial for all future interactions with this specific stake, such as revoking or slashing.


How to Revoke a Stake#

Revoking a stake is the process initiated by the staker to retrieve their locked tokens and assets. This transaction does not immediately return the funds; instead, it marks them as available for claiming, subject to any on-chain lock-up periods.

Parameters#

from
string
required
The address of the stake to be revoked (obtained from the 'stake' call).
assets
string[]
An array of asset addresses to revoke from the stake.
tokens
object[]
An array of token objects to revoke.
2 subfields
wallet
WalletObject
required
The staker's wallet object, which must be the original creator of the stake.

Example#

Revoking a Stake

// Assume 'stakeAddress' is the address returned from the previous step
// and 'stakerWallet' is the same wallet used to create the stake.

async function revokeExistingStake(stakeAddress) {
  try {
    const revokeTxHash = await client.revokeStake({
      from: stakeAddress,
      tokens: [{
        address: 'z35n6aTUTK8h5nAF43h21A1g84g3C3D7B5E',
        value: 100,
      }],
      assets: ['zNKtA1B2C3D4E5F6G7H8I9J0K1L2M3N4O5P6'],
      wallet: stakerWallet,
    });

    console.log('Revoke stake transaction sent:', revokeTxHash);
    console.log('IMPORTANT: Save this hash to claim your stake later.');
    return revokeTxHash;
  } catch (error) {
    console.error('Error revoking stake:', error);
  }
}

Return Value#

This function returns the transaction hash of the revoke operation. This hash serves as evidence and is required for the final step of claiming the stake.


How to Claim a Revoked Stake#

After a stake has been successfully revoked, the staker must send a claimStake transaction to move the tokens and assets back into their account. This finalizes the withdrawal process.

Parameters#

from
string
required
The address of the stake.
evidence
string
required
The transaction hash from the 'revokeStake' call, which serves as proof of revocation.
wallet
WalletObject
required
The staker's wallet object.

Example#

Claiming Staked Items

// Assume 'stakeAddress' and 'revokeTxHash' are from the previous steps,
// and 'stakerWallet' is the staker's wallet.

async function claimRevokedStake(stakeAddress, revokeTxHash) {
  try {
    const claimTxHash = await client.claimStake({
      from: stakeAddress,
      evidence: revokeTxHash,
      wallet: stakerWallet,
    });

    console.log('Claim stake transaction sent:', claimTxHash);
    console.log('Your tokens and assets have been returned to your account.');
  } catch (error) {
    console.error('Error claiming stake:', error);
  }
}

Return Value#

The method returns the final transaction hash. Once this transaction is confirmed on the chain, the staked items are returned to the wallet's address.


How to Slash a Stake#

Slashing is a punitive action that can be taken by a designated slasher (usually the stake receiver) against a staker. This typically happens if the staker violates certain rules. The slashed tokens or assets are removed from the stake and sent to a designated vault.

Parameters#

from
string
required
The address of the stake to be slashed.
reason
string
required
A mandatory message explaining why the slash is occurring.
assets
string[]
An array of asset addresses to be slashed from the stake.
tokens
object[]
An array of token objects to be slashed.
2 subfields
wallet
WalletObject
required
The wallet object of an authorized slasher.

Example#

Slashing a Stake

// Assume 'stakeAddress' is the address of the stake to be slashed,
// and 'slasherWallet' is the wallet of an authorized slasher.

async function slashExistingStake(stakeAddress) {
  try {
    const slashTxHash = await client.slashStake({
      from: stakeAddress,
      reason: 'Validator missed signing 10 consecutive blocks.',
      tokens: [{
        address: 'z35n6aTUTK8h5nAF43h21A1g84g3C3D7B5E',
        value: 10, // Slashing 10 tokens as a penalty
      }],
      wallet: slasherWallet,
    });

    console.log('Slash stake transaction sent:', slashTxHash);
  } catch (error) {
    console.error('Error slashing stake:', error);
  }
}

Return Value#

This method returns the transaction hash for the slashing operation.

Summary#

You've now learned the complete lifecycle of staking on the OCAP blockchain: creating a stake with stake, retrieving funds with revokeStake and claimStake, and penalizing bad actors with slashStake. This powerful mechanism is fundamental to many decentralized applications.

To learn more about the items you can stake, see the Manage Tokens and Manage Assets (NFTs) guides.