Staking
Pre-requisites
Please make sure that you've followed our getting started guide and set up your development environment.
You'll also need the following:
In order to stake, your users will need to have created a profile for your project. They'll also need eligible characters that can stake (more on this below).
Overview
Staking is very similar to missions in the way that it allows users to earn rewards.
The difference is that when characters are staked in a staking pool, they're locked until a user unstakes them. During that time, these characters earn rewards based on the staking pool's reward distribution mechanism.
Create staking pool
- JavaScript
- GraphQL
- C#
import { LockTypeEnum } from "@honeycomb-protocol/edge-client";
const {
createCreateStakingPoolTransaction: {
transactions, // The transaction response, you'll need to sign and send this transaction
stakingPoolAddress, // The address of the staking pool when it's created
multipliersAddress, // The address of the multipliers when they're created (if you've added any)
},
} = await client.createCreateStakingPoolTransaction({
project: projectAddress.toString(),
resource: resourceAddress.toString(), // Resource's pubkey address in string format, your users will earn rewards in the form of this resource
authority: adminPublicKey.toString(),
delegateAuthority: delegateAuthority.toString(),
payer: payerPublicKey.toString(),
multiplier: { // Optional, if you want to add multipliers, these multipliers increase the rewards for your users based on the conditions you set
decimals: 2,
multipliers: [
// Provide one of these per multiplier: collection, creator, minNftCount, minStakeDuration
{
value: "10",
type: {
collection: collection.toString(),
}
},
{
value: "5",
type: {
creator: creatorPublicKey.toString(),
}
},
{
value: "2",
type: {
minNftCount: "1",
}
},
{
value: "3",
type: {
minStakeDuration: "1",
}
}
]
},
metadata: { // Staking pool metadata
name: "Staking", // Staking pool name
rewardsPerDuration: "1", // Rewards per duration
rewardsDuration: "3600", // Rewards duration in seconds, 3600 means rewards can be collected every hour
maxRewardsDuration: "7200", // Maximum rewards duration in seconds
minStakeDuration: "7200", // Minimum stake duration in seconds before rewards can be claimed
cooldownDuration: "0", // Rewards cooldown
resetStakeDuration: "0", // Reset stake duration
startTime: Date.now().toString(), // Staking pool start time, UNIX second format send as a string
endTime: null, // Staking pool endtime, UNIX second format send as a string, send null if you don't want to set an end time
lockType: LockTypeEnum.Freeze, // Character lock type for the staking pool, send either Freeze or Custody
}
});
query CreateCreateStakingPoolTransaction($project: String!, $resource: String!, $metadata: CreateStakingPoolMetadataInput!, $authority: String!, $delegateAuthority: String, $multiplier: InitStakingMultiplierMetadataInput) {
createCreateStakingPoolTransaction(project: $project, resource: $resource, metadata: $metadata, authority: $authority, delegateAuthority: $delegateAuthority, multiplier: $multiplier) {
transactions {
transactions
blockhash
lastValidBlockHeight
}
stakingPoolAddress
multipliersAddress
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"resource": "pubkey", // Resource's pubkey address in string format
"authority": "pubkey", // Authority's pubkey address in string format
"payer": "pubkey", // Optional, fee payer's pubkey address in string format,
"delegateAuthority": "pubkey", // Optional, delegate authority's pubkey address in string format
"metadata": {
"cooldownDuration": "bigint", // Duration in seconds, UNIX format, send as a string (example: 1 week = 604800 seconds)
"endTime": "bigint", // Staking pool endtime, UNIX second format send as a string
"lockType": "Freeze/Custody", // Character lock type for the staking pool, send either Freeze or Custody
"maxRewardsDuration": "bigint", // Maximum rewards duration in seconds, send as a string
"minStakeDuration": "bigint", // Minimum stake duration in seconds, send as a string
"name": "string", // Staking pool name
"resetStakeDuration": "bigint", // Reset stake duration in seconds, send as a string
"rewardsDuration": "bigint", // Rewards duration in seconds, send as a string
"rewardsPerDuration": int, // Rewards per duration, send as a string
"startTime": "bigint" // Staking pool start time, UNIX second format send as a string
},
"multiplier": { // Optional, if you want to add multipliers, these multipliers increase the rewards for your users based on the conditions you set
"decimals": 2,
"multipliers": [
{
"value": "10",
"type": {
// Use any combination of these: collection, creator, minNftCount, minStakeDuration
"collection": "pubkey",
"creator": "pubkey",
"minNftCount": "1",
"minStakeDuration": "1",
}
}
]
}
}
var createStakingPoolTransaction = await Client.CreateCreateStakingPoolTransaction(new CreateCreateStakingPoolTransactionParams
{
Project = projectAddress.ToString(),
Resource = resourceAddress.ToString(), // Resource's pubkey address in string format
Authority = adminPublicKey.ToString(),
DelegateAuthority = delegateAuthority.ToString(),
Payer = payerPublicKey.ToString(),
Multiplier = new InitStakingMultiplierMetadataInput
{
Decimals = 2,
Multipliers = new List<AddMultiplierMetadataInput>
{
new AddMultiplierMetadataInput
{
Value = "10",
Type = new MultiplierTypeInput
{
Collection = collection.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = "5",
Type = new MultiplierTypeInput
{
Creator = creatorPublicKey.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = "2",
Type = new MultiplierTypeInput
{
MinNftCount = "1",
}
},
new AddMultiplierMetadataInput
{
Value = "3",
Type = new MultiplierTypeInput
{
MinStakeDuration = "1",
}
}
}
},
Metadata = new CreateStakingPoolMetadataInput
{
Name = "Staking", // Staking pool name
RewardsPerDuration = "1", // Rewards per duration
RewardsDuration = "3600", // Rewards duration in seconds
MaxRewardsDuration = "7200", // Maximum rewards duration in seconds
MinStakeDuration = "7200", // Minimum stake duration in seconds
CooldownDuration = "0", // Rewards cooldown
ResetStakeDuration = false, // Reset stake duration
StartTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), // Staking pool start time in UNIX seconds
EndTime = null, // Staking pool endtime in UNIX seconds, null if not set
LockType = LockTypeEnum.Freeze // Lock type for the staking pool
}
});
var transactions = createStakingPoolTransaction.Transactions; // Transaction response, to be signed and sent
var stakingPoolAddress = createStakingPoolTransaction.StakingPoolAddress; // Address of the staking pool
var multipliersAddress = createStakingPoolTransaction.MultipliersAddress; // Address of the multipliers
Update staking pool
The create staking pool function will create a new pool, but your users won't be able to stake in it until you update it with a character model. Here's how you can do so.
- JavaScript
- GraphQL
- C#
import { LockTypeEnum } from "@honeycomb-protocol/edge-client";
const {
createUpdateStakingPoolTransaction: txResponse // This is the transaction response, you'll need to sign and send this transaction
} = await client.createUpdateStakingPoolTransaction({
project: projectAddress.toString(),
authority: adminPublicKey.toString(),
resource: resourceAddress.toString(), // Optional, only use if you want to change the resource
delegateAuthority: delegateAuthority.toString(), // Optional, only use if you want to change the delegate authority
stakingPool: stakingPoolAddress.toString(),
characterModel: characterModelAddress.toString(), // Optional, but you'll need to initially provide this if you want to allow characters to stake in this pool
payer: payerPublicKey.toString(), // Optional, tx payer pubkey
metadata: { // Optional, all of the properties in this object are also optional
cooldownDuration: "0", // Duration in seconds, UNIX format, send as a string (example: 1 week = 604800 seconds)
endTime: null, // Staking pool endtime, UNIX second format send as a string, send null if you don't want to set an end time
lockType: LockTypeEnum.Freeze, // Character lock type for the staking pool, send either Freeze or Custody
maxRewardsDuration: "9600", // Maximum rewards duration in seconds, send as a string
minStakeDuration: "3600", // Minimum stake duration in seconds, send as a string
name: "New name", // Staking pool name
resetStakeDuration: "86400", // Reset stake duration in seconds, send as a string
rewardsDuration: "3600", // Rewards duration in seconds, send as a string
rewardsPerDuration: "100", // Rewards per duration, send as a string
startTime: Date.now().toString(), // Staking pool start time, UNIX second format send as a string
}
});
query CreateUpdateStakingPoolTransaction($project: String!, $stakingPool: String!, $authority: String!, $metadata: UpdateStakingPoolMetadataInput, $characterModel: String, $resource: String, $delegateAuthority: String, $payer: String) {
createUpdateStakingPoolTransaction(project: $project, stakingPool: $stakingPool, authority: $authority, metadata: $metadata, characterModel: $characterModel, resource: $resource, delegateAuthority: $delegateAuthority, payer: $payer) {
transaction
blockhash
lastValidBlockHeight
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"stakingPool": "pubkey", // Staking pool's pubkey address in string format
"authority": "pubkey", // Authority's pubkey address in string format
"resource": "pubkey", // Optional, resource's pubkey address in string format
"delegateAuthority": "pubkey", // Optional, delegate authority's pubkey address in string format
"characterModel": "pubkey", // Optional, character model's pubkey address in string format
"payer": "pubkey", // Optional, tx payer's pubkey address in string format
"metadata": {
"cooldownDuration": "int", // Duration in seconds, UNIX format, send as a string (example: 1 week = 604800 seconds)
"endTime": "int", // Staking pool endtime, UNIX second format send as a string
"lockType": "Freeze", // Character lock type for the staking pool, send either Freeze or Custody
"maxRewardsDuration": "int", // Maximum rewards duration in seconds, send as a string
"minStakeDuration": "int", // Minimum stake duration in seconds, send as a string
"name": "string", // Staking pool name
"resetStakeDuration": "int", // Reset stake duration in seconds, send as a string
"rewardsDuration": "int", // Rewards duration in seconds, send as a string
"rewardsPerDuration": int, // Rewards per duration, send as a string
"startTime": "int" // Staking pool start time, UNIX second format send as a string
}
}
using HplEdgeClient.Enums; // Import the lock type enum
var updateStakingPoolParams = new CreateUpdateStakingPoolTransactionParams
{
Project = projectAddress.ToString(), // Project address
Authority = adminPublicKey.ToString(), // Authority public key
Resource = resourceAddress.ToString(), // Optional: resource address
DelegateAuthority = delegateAuthority.ToString(), // Optional: delegate authority public key
StakingPool = stakingPoolAddress.ToString(), // Staking pool address
CharacterModel = characterModelAddress.ToString(), // Optional: character model address
Payer = payerPublicKey.ToString(), // Optional: transaction payer public key
Metadata = new StakingPoolMetadataInput // Optional: metadata object
{
CooldownDuration = "0", // Duration in seconds, UNIX format
EndTime = null, // Staking pool end time, send null if not setting an end time
LockType = LockTypeEnum.Freeze, // Lock type for the staking pool
MaxRewardsDuration = "9600", // Maximum rewards duration in seconds
MinStakeDuration = "3600", // Minimum stake duration in seconds
Name = "New name", // Staking pool name
ResetStakeDuration = "86400", // Reset stake duration in seconds
RewardsDuration = "3600", // Rewards duration in seconds
RewardsPerDuration = "100", // Rewards per duration
StartTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), // Staking pool start time
}
};
// Create update staking pool transaction
var txResponse = await Client.CreateUpdateStakingPoolTransaction(updateStakingPoolParams);
// Extract transaction response
var transactionResponse = txResponse.CreateUpdateStakingPoolTransaction; // The transaction response
Create multipliers
- JavaScript
- GraphQL
- C#
const {
createInitMultipliersTransaction: {
tx, // The transaction response, you'll need to sign and send this transaction
multipliersAddress, // The address of the multipliers when they're created
},
} = await client.createInitMultipliersTransaction({
project: projectAddress.toString(),
authority: adminPublicKey.toString(),
stakingPool: stakingPoolAddress.toString(),
multipliers: [
{
value: "10",
type: {
collection: collection.toString(),
},
},
{
value: "5",
type: {
creator: creatorPublicKey.toString(),
},
},
{
value: "2",
type: {
minNftCount: "1",
},
},
{
value: "3",
type: {
minStakeDuration: "1", // Minimum stake duration in seconds
},
}
],
decimals: 3,
});
query CreateBurnResourceTransaction($resource: String!, $params: BurnResourceInput!, $authority: String!, $payer: String, $project: String!, $stakingPool: String!, $decimals: Int!, $multipliers: [AddMultiplierMetadataInput]!, $createInitMultipliersTransactionAuthority2: String!, $delegateAuthority: String, $createInitMultipliersTransactionPayer2: String) {
createBurnResourceTransaction(resource: $resource, params: $params, authority: $authority, payer: $payer) {
transaction
blockhash
lastValidBlockHeight
}
createInitMultipliersTransaction(project: $project, stakingPool: $stakingPool, decimals: $decimals, multipliers: $multipliers, authority: $createInitMultipliersTransactionAuthority2, delegateAuthority: $delegateAuthority, payer: $createInitMultipliersTransactionPayer2) {
tx {
transaction
blockhash
lastValidBlockHeight
}
multipliersAddress
}
}
Add the accompanying data:
{
"project": "pubkey", // Project's pubkey address in string format
"authority": "pubkey", // Authority's pubkey address in string format
"payer": "pubkey", // Optional, tx payer's pubkey address in string format
"delegateAuthority": "pubkey", // Optional, delegate authority's pubkey address in string format
"stakingPool": "pubkey", // Staking pool's pubkey address in string format
"decimals": int, // Number of decimals
"multipliers": [
{
"value": "int", // Multiplier value, send as a string
"type": {
// Send only one of these per multiplier object
"minStakeDuration": "int", // Minimum stake duration in seconds, send as a string
"minNftCount": "int", // Minimum NFT count, send as a string
"creator": "pubkey", // Creator's pubkey address in string format
"collection": "pubkey" // Collection's pubkey address in string format
}
}
],
}
var initMultipliersTransaction = await Client.CreateInitMultipliersTransaction(new CreateInitMultipliersTransactionParams
{
Project = projectAddress.ToString(),
Authority = adminPublicKey.ToString(),
StakingPool = stakingPoolAddress.ToString(),
Multipliers = new List<AddMultiplierMetadataInput>
{
new AddMultiplierMetadataInput
{
Value = "10",
Type = new MultiplierTypeInput
{
Collection = collection.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = "5",
Type = new MultiplierTypeInput
{
Creator = creatorPublicKey.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = "2",
Type = new MultiplierTypeInput
{
MinNftCount = "1",
}
},
new AddMultiplierMetadataInput
{
Value = "3",
Type = new MultiplierTypeInput
{
MinStakeDuration = "1", // Minimum stake duration in seconds
}
}
},
Decimals = 3
});
var tx = initMultipliersTransaction.Tx; // Transaction response, to be signed and sent
var multipliersAddress = initMultipliersTransaction.MultipliersAddress; // Address of the multipliers
Add multipliers
- JavaScript
- GraphQL
- C#
const {
createAddMultiplierTransaction: txResponse // This is the transaction response, you'll need to sign and send this transaction
} = await client.createAddMultiplierTransaction({
project: projectAddress,
authority: adminPublicKey.toString(),
multiplier: multipliersAddress.toString(), // Existing multipliers address
payer: payerPublicKey.toString(), // Optional, tx payer pubkey
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority pubkey
metadata: [
// Specify any multipliers you want to add here
{
value: "10",
type: {
collection: collection.toString(),
},
},
{
value: "5",
type: {
creator: creatorPublicKey.toString(),
},
},
{
value: "2",
type: {
minNftCount: "1",
},
},
{
value: "3",
type: {
minStakeDuration: "1",
},
}
],
});
query CreateAddMultiplierTransaction($project: String!, $multiplier: String!, $metadata: AddMultiplierMetadataInput!, $authority: String!, $delegateAuthority: String, $payer: String) {
createAddMultiplierTransaction(project: $project, multiplier: $multiplier, metadata: $metadata, authority: $authority, delegateAuthority: $delegateAuthority, payer: $payer) {
transaction
blockhash
lastValidBlockHeight
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"multiplier": "pubkey", // Multiplier's pubkey address in string format
"authority": "pubkey", // Authority's pubkey address in string format
"delegateAuthority": "pubkey", // Optional, delegate authority's pubkey address in string format
"payer": "pubkey", // Optional, tx payer's pubkey address in string format
"metadata": [
// Specify any multipliers you want to add here
{
"value": "10",
"type": {
"collection": "pubkey",
},
},
{
"value": "5",
"type": {
"creator": "pubkey",
},
},
{
"value": "2",
"type": {
"minNftCount": "1",
},
},
{
"value": "3",
"type": {
"minStakeDuration": "1",
},
}
]
}
var addMultiplierParams = new CreateAddMultiplierTransactionParams
{
Project = projectAddress, // Project address
Authority = adminPublicKey.ToString(), // Authority public key
Multiplier = multipliersAddress.ToString(), // Existing multipliers address
Payer = payerPublicKey.ToString(), // Optional: transaction payer public key
DelegateAuthority = delegateAuthority.ToString(), // Optional: delegate authority public key
Metadata = new List<AddMultiplierMetadataInput>
{
new AddMultiplierMetadataInput
{
Value = 10,
Type = new MultiplierTypeInput
{
Collection = collection.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = 5,
Type = new MultiplierTypeInput
{
Creator = creatorPublicKey.ToString(),
}
},
new AddMultiplierMetadataInput
{
Value = 2,
Type = new MultiplierTypeInput
{
MinNftCount = 1,
}
},
new AddMultiplierMetadataInput
{
Value = 3,
Type = new MultiplierTypeInput
{
MinStakeDuration = 1,
}
}
}
};
// Create add multiplier transaction
var txResponse = await Client.CreateAddMultiplierTransaction(addMultiplierParams); // The transaction response
Stake characters
- JavaScript
- GraphQL
- C#
const {
createStakeCharactersTransactions: txResponse // This is the transaction response, you'll need to sign and send this transaction
} = await client.createStakeCharactersTransactions({
project: projectAddress.toString(),
stakingPool: stakingPoolAddress.toString(),
characterModel: characterModelAddress.toString(),
characterAddresses: [
characterAddress.toString(),
],
feePayer: payerPublicKey.toString(),
});
query CreateStakeCharactersTransactions($characterAddresses: [String!]!, $project: String!, $characterModel: String!, $stakingPool: String!, $feePayer: String) {
createStakeCharactersTransactions(characterAddresses: $characterAddresses, project: $project, characterModel: $characterModel, stakingPool: $stakingPool, feePayer: $feePayer) {
transactions
blockhash
lastValidBlockHeight
}
}
Provide the accompanying data:
{
"characterAddresses": ["pubkey"], // Array of character addresses
"project": "pubkey", // Project's pubkey address in string format
"characterModel": "pubkey", // Character model's pubkey address in string format
"stakingPool": "pubkey", // Staking pool's pubkey address in string format
"feePayer": "pubkey"
}
var stakeCharactersParams = new CreateStakeCharactersTransactionsParams
{
Project = projectAddress.ToString(), // Project address
StakingPool = stakingPoolAddress.ToString(), // Staking pool address
CharacterModel = characterModelAddress.ToString(), // Character model address
CharacterAddresses = new List<string>
{
characterAddress.ToString() // Character address
},
FeePayer = payerPublicKey.ToString() // Fee payer public key
};
// Create stake characters transactions
var txResponse = await Client.CreateStakeCharactersTransactions(stakeCharactersParams); // This will return the transaction response
Claim staking rewards
- JavaScript
- GraphQL
- C#
const {
createClaimStakingRewardsTransactions: txResponse // This is the transaction response, you'll need to sign and send this transaction
} = await client.createClaimStakingRewardsTransactions({
characterAddresses: [
characterAddress.toString(),
],
characterModel: characterModelAddress.toString(),
feePayer: payerPublicKey.toString(),
});
query CreateClaimStakingRewardsTransactions($characterAddresses: [String!]!, $characterModel: String!, $feePayer: String) {
createClaimStakingRewardsTransactions(characterAddresses: $characterAddresses, characterModel: $characterModel, feePayer: $feePayer) {
transactions
blockhash
lastValidBlockHeight
}
}
Provide the accompanying data like so:
{
"characterAddresses": ["pubkey"], // Array of character addresses
"characterModel": "pubkey", // Character model's pubkey address in string format
"feePayer": "pubkey"
}
var claimStakingRewardsParams = new CreateClaimStakingRewardsTransactionsParams
{
CharacterAddresses = new List<string>
{
characterAddress.ToString() // Character address
},
CharacterModel = characterModelAddress.ToString(), // Character model address
FeePayer = payerPublicKey.ToString() // Fee payer public key
};
// Create claim staking rewards transactions
var txResponse = await Client.CreateClaimStakingRewardsTransactions(claimStakingRewardsParams); // The transaction response
Unstake characters
- JavaScript
- GraphQL
- C#
const {
createUnstakeCharactersTransactions: txResponse // This is the transaction response, you'll need to sign and send this transaction
} = await client.createUnstakeCharactersTransactions({
characterAddresses: [
characterAddress.toString(),
],
characterModel: characterModelAddress.toString(),
feePayer: payerPublicKey.toString(),
});
query CreateUnstakeCharactersTransactions($characterAddresses: [String!]!, $characterModel: String!, $feePayer: String) {
createUnstakeCharactersTransactions(characterAddresses: $characterAddresses, characterModel: $characterModel, feePayer: $feePayer) {
transactions
blockhash
lastValidBlockHeight
}
}
Provide the accompanying data like so:
{
"characterAddresses": ["pubkey"], // Array of character addresses
"characterModel": "pubkey", // Character model's pubkey address in string format
"feePayer": "pubkey"
}
var unstakeCharactersParams = new CreateUnstakeCharactersTransactionsParams
{
CharacterAddresses = new List<string>
{
characterAddress.ToString() // Character address
},
CharacterModel = characterModelAddress.ToString(), // Character model address
FeePayer = payerPublicKey.ToString() // Fee payer public key
};
// Create unstake characters transactions
var txResponse = await Client.CreateUnstakeCharactersTransactions(unstakeCharactersParams); // The transaction response