Skip to main content

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.
    • address string (required) — The address of the token contract.
    • value number (required) — The amount of tokens to stake.
  • 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

javascript
// 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.
    • address string (required) — The address of the token contract.
    • value number (required) — The amount of tokens to revoke.
  • wallet WalletObject (required) — The staker's wallet object, which must be the original creator of the stake.

Example

Revoking a Stake

javascript
// 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

javascript
// 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.
    • address string (required) — The address of the token contract.
    • value number (required) — The amount of tokens to slash.
  • wallet WalletObject (required) — The wallet object of an authorized slasher.

Example

Slashing a Stake

javascript
// 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.