Token Staking (SPL)
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:
- A project
- A SPL token to stake
Why use token staking?
Staking is a great way to measure and reward user loyalty and engagement. Here are some use-cases for staking:
- Get rewards over time: Instead of simply holding a token, players can stake it to earn rewards over time.
- Staking can give users voting rights on development decisions.
- Increase a player's yield in play-to-earn (P2E) games. Example: A staked token multiplier could increase in-game earnings, making farming more efficient.
Staking instructions
Create staking pool
- JavaScript
- GraphQL
const {
createCreateSplStakingPoolTransaction: {
tx: transactions, // The transaction response, you'll need to sign and send this transaction
splStakingPoolAddress, // The address of the staking pool when it's created
},
} = await client.createCreateSplStakingPoolTransaction({
project: projectAddress.toString(),
stakeTokenMint: tokenAddress.toString(), // Token's mint address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
multipliers: [ // Optional, if you want to add multipliers, these multipliers increase the rewards for your users based on the conditions you set
{ // Provide either minAmount or minDuration or both
value: "10",
type: {
minAmount: "1000",
}
},
{
value: "3",
type: {
minDuration: "60",
}
}
],
metadata: { // Staking pool metadata
name: "Token Staking", // Staking pool name
maxStakeDurationSecs: "7200", // Maximum staking duration in seconds
minStakeDurationSecs: "7200", // Minimum stake duration in seconds
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
}
});
query createCreateSplStakingPoolTransaction($project: String!, $stakeTokenMint: String!, $metadata: CreateSplStakingPoolMetadataInput!, $authority: String!, $delegateAuthority: String, $multipliers: SplMultiplierInput, $payer: String) {
createCreateStakingPoolTransaction(project: $project, stakeTokenMint: $stakeTokenMint, metadata: $metadata, authority: $authority, delegateAuthority: $delegateAuthority, multipliers: $multipliers, payer: $payer) {
tx {
transactions
blockhash
lastValidBlockHeight
}
splStakingPoolAddress
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"stakeTokenMint": "pubkey", // Token'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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"metadata": {
"name": "string", // Staking pool name
"maxStakeDurationSecs": "bigint", // Maximum rewards duration in seconds, send as a string
"minStakeDurationSecs": "bigint", // Minimum stake duration in seconds, send as a string
"startTime": "bigint", // Staking pool start time, UNIX second format send as a string
"endTime": "bigint" // Staking pool endtime, 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
{
"value": "10",
"type": {
// Use any combination of these: minAmount, minDuration
"minAmount": "1000",
"minDuration": "60"
}
}
]
}
Create staking pool tree
- JavaScript
- GraphQL
const {
createCreateSplStakingPoolTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
treeAddress, // The address of the staking pool tree when it's created
},
} = await client.createCreateSplStakingPoolTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
treeConfig: {
// Provide either the basic or advanced configuration, we recommend using the basic configuration if you don't know the exact values of maxDepth, maxBufferSize, and canopyDepth (the basic configuration will automatically configure these values for you)
basic: {
numAssets: 100000, // The desired number of profiles this tree will be able to store
},
// Uncomment the following config if you want to configure your own profile tree (also comment out the above config)
// advanced: {
// maxDepth: 20,
// maxBufferSize: 64,
// canopyDepth: 14,
// }
});
query createCreateSplStakingPoolTransaction($project: String!, $splStakingPool: String!, $authority: String!, $delegateAuthority: String, $treeConfig: TreeSetupConfig!, $payer: String) {
createCreateStakingPoolTransaction(project: $project, splStakingPool: $splStakingPool, authority: $authority, treeConfig: $treeConfig, delegateAuthority: $delegateAuthority, payer: $payer) {
tx {
transactions
blockhash
lastValidBlockHeight
}
splStakingPoolAddress
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token'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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"treeConfig": {
// Provide either the basic or advanced configuration, we recommend using the basic configuration if you don't know the exact values of maxDepth, maxBufferSize, and canopyDepth (the basic configuration will automatically configure these values for you)
"basic": {
"numAssets": int // The desired number of profiles this tree will be able to store
},
// Use the following config if you want to configure your own profile tree (also remove the above basic config)
// "advanced": {
// "canopyDepth": int, // The depth of the canopy
// "maxBufferSize": int, // The maximum buffer size
// "maxDepth": int // The maximum depth of the tree
// }
}
}
Update staking pool
- JavaScript
- GraphQL
const {
createUpdateSplStakingPoolTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createUpdateSplStakingPoolTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
metadata: { // Staking pool metadata
name: "Updated Token Staking", // Staking pool name
maxStakeDurationSecs: "7200", // Maximum staking duration in seconds
minStakeDurationSecs: "7200", // Minimum stake duration in seconds
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
}
});
query createUpdateSplStakingPoolTransaction($project: String!, $splStakingPool: String!, $metadata: CreateSplStakingPoolMetadataInput!, $authority: String!, $delegateAuthority: String, $payer: String) {
createUpdateSplStakingPoolTransaction(project: $project, splStakingPool: $splStakingPool, metadata: $metadata, authority: $authority, delegateAuthority: $delegateAuthority, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token'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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"metadata": {
"name": "string", // Staking pool name
"maxStakeDurationSecs": "bigint", // Maximum rewards duration in seconds, send as a string
"minStakeDurationSecs": "bigint", // Minimum stake duration in seconds, send as a string
"startTime": "bigint", // Staking pool start time, UNIX second format send as a string
"endTime": "bigint" // Staking pool endtime, UNIX second format send as a string
},
}
Add or remove multipliers
- JavaScript
- GraphQL
const {
createAddRemoveSplMultipliersTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createAddRemoveSplMultipliersTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
add: [ // Multipliers to add
{
value: "10",
type: {
minAmount: "1000",
}
},
{
value: "3",
type: {
minDuration: "60",
}
}
],
remove: [0, 3] // Indices of multipliers to remove
});
query createAddRemoveSplMultipliersTransaction($project: String!, $splStakingPool: String!, $authority: String!, $add: [AddSplMultiplierMetadataInput!], $remove: [Int!], $delegateAuthority: String, $payer: String) {
createAddRemoveSplMultipliersTransaction(project: $project, splStakingPool: $splStakingPool, authority: $authority, add: $add, remove: $remove, delegateAuthority: $delegateAuthority, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token'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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"add": [ // Multipliers to add
{
"value": "10",
"type": {
"minAmount": "1000"
}
},
{
"value": "3",
"type": {
"minDuration": "60"
}
}
],
"remove": [0, 3] // Indices of multipliers to remove
}
Create rewards pool
- JavaScript
- GraphQL
const {
createSplRewardPoolTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createSplRewardPoolTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
rewardTokenMint: rewardTokenMint.toString(), // Reward token's mint address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
rewardConfig: {
ApyConfig: {
rewardsDuration: "10", // Rewards duration in seconds in string format
rewardsPerDuration: "10000000000", // Rewards per duration in string format
}
}
});
query createSplRewardPoolTransaction($project: String!, $splStakingPool: String!, $authority: String!, $rewardTokenMint: String!, $rewardConfig: CreateSplRewardPoolArgsInpu! $delegateAuthority: String, $payer: String) {
createSplRewardPoolTransaction(project: $project, splStakingPool: $splStakingPool, authority: $authority, rewardTokenMint: $rewardTokenMint, rewardConfig: $rewardConfig, delegateAuthority: $delegateAuthority, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token's pubkey address in string format
"rewardTokenMint": "pubkey", // Reward token's mint 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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"rewardConfig": {
"ApyConfig": {
"rewardsDuration": "10", // Rewards duration in seconds in string format
"rewardsPerDuration": "10000000000" // Rewards per duration in string format
}
}
}
Add or remove rewards from reward pool
- JavaScript
- GraphQL
const {
createAddRemoveRewardsFromRewardPoolTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createAddRemoveRewardsFromRewardPoolTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
rewardTokenMint: rewardTokenMint.toString(), // Reward token's mint address in string format
authority: adminPublicKey.toString(), // Authority's pubkey address in string format
delegateAuthority: delegateAuthority.toString(), // Optional, delegate authority's pubkey address in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
action: {
add: "10000000000", // Amount of rewards to add in string format
remove: "10000000000" // Amount of rewards to remove in string format
}
});
query createAddRemoveRewardsFromRewardPoolTransaction($project: String!, $splStakingPool: String!, $authority: String!, $rewardTokenMint: String!, $action: AddRemoveRewardsFromRewardPoolActionInput!, $delegateAuthority: String, $payer: String) {
createAddRemoveRewardsFromRewardPoolTransaction(project: $project, splStakingPool: $splStakingPool, authority: $authority, rewardTokenMint: $rewardTokenMint, action: $action, delegateAuthority: $delegateAuthority, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token's pubkey address in string format
"rewardTokenMint": "pubkey", // Reward token's mint 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
"payer": "pubkey", // Optional, fee payer's pubkey address in string format
"action": {
"add": "10000000000", // Amount of rewards to add in string format
"remove": "10000000000" // Amount of rewards to remove in string format
}
}
Stake tokens
- JavaScript
- GraphQL
const {
createStakeSplTokensTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createStakeSplTokensTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
staker: stakerPublicKey.toString(), // Staker's pubkey address in string format
amount: "10000000000", // Amount of tokens to stake in string format
lockPeriodSecs: "10", // Lock period in seconds in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
});
query createStakeSplTokensTransaction($project: String!, $splStakingPool: String!, $staker: String!, $amount: String!, $lockPeriodSecs: String!, $payer: String) {
createStakeSplTokensTransaction(project: $project, splStakingPool: $splStakingPool, staker: $staker, amount: $amount, lockPeriodSecs: $lockPeriodSecs, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token's pubkey address in string format
"staker": "pubkey", // Staker's pubkey address in string format
"amount": "10000000000", // Amount of tokens to stake in string format
"lockPeriodSecs": "10", // Lock period in seconds in string format
"payer": "pubkey" // Optional, fee payer's pubkey address in string format
}
Fetch stake receipts
- JavaScript
- GraphQL
const {
splStakingRecipients
} = await client.findSplStakingRecipients({
addresses: [stakerAddress.toString()], // Array of staker account addresses in string format
projects: [projectAddress.toString()], // Array of project address in string format
splStakingPools: [stakingPoolAddress.toString()], // Array of staking pool address in string format
stakers: [stakerPublicKey.toString()], // Array of staker pubkey addresses in string format
includeProof: true, // Optional, include proof of the transaction
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
});
query findSplStakingRecipients($addresses: [String!], $projects: [String!], $splStakingPools: [String!], $stakers: [String!], $includeProof: Boolean, $payer: String) {
findSplStakingRecipients(addresses: $addresses, projects: $projects, splStakingPools: $splStakingPools, stakers: $stakers, includeProof: $includeProof, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"addresses": ["pubkey"], // Array of staker account addresses in string format
"projects": ["pubkey"], // Array of project address in string format
"splStakingPools": ["pubkey"], // Array of staking pool address in string format
"stakers": ["pubkey"], // Array of staker pubkey addresses in string format
"includeProof": true, // Optional, include proof of the transaction
"payer": "pubkey" // Optional, fee payer's pubkey address in string format
}
Claim rewards
- JavaScript
- GraphQL
const {
createClaimSplRewardsTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createClaimSplRewardsTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
staker: stakerPublicKey.toString(), // Staker's pubkey address in string format
stakingReciept: stakingReceipt.toString(), // Staking receipt in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
});
query createClaimSplRewardsTransaction($project: String!, $splStakingPool: String!, $staker: String!, $stakingReciept: String!, $payer: String) {
createClaimSplRewardsTransaction(project: $project, splStakingPool: $splStakingPool, staker: $staker, stakingReciept: $stakingReciept, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token's pubkey address in string format
"staker": "pubkey", // Staker's pubkey address in string format
"stakingReciept": "pubkey", // Staking receipt in string format
"payer": "pubkey" // Optional, fee payer's pubkey address in string format
}
Unstake tokens
- JavaScript
- GraphQL
const {
createUnstakeSplTokensTransaction: {
tx: transaction, // The transaction response, you'll need to sign and send this transaction
},
} = await client.createUnstakeSplTokensTransaction({
project: projectAddress.toString(),
splStakingPool: stakingPoolAddress.toString(), // Staking pool address in string format
staker: stakerPublicKey.toString(), // Staker's pubkey address in string format
stakingReciept: stakingReceipt.toString(), // Staking receipt in string format
payer: payerPublicKey.toString(), // Optional, fee payer's pubkey address in string format
});
query createUnstakeSplTokensTransaction($project: String!, $splStakingPool: String!, $staker: String!, $stakingReciept: String!, $payer: String) {
createUnstakeSplTokensTransaction(project: $project, splStakingPool: $splStakingPool, staker: $staker, stakingReciept: $stakingReciept, payer: $payer) {
tx {
transaction
blockhash
lastValidBlockHeight
}
}
}
Provide the accompanying data like so:
{
"project": "pubkey", // Project's pubkey address in string format
"splStakingPool": "pubkey", // Token's pubkey address in string format
"staker": "pubkey", // Staker's pubkey address in string format
"stakingReciept": "pubkey", // Staking receipt in string format
"payer": "pubkey" // Optional, fee payer's pubkey address in string format
}