Claim Staking Rewards
Until runtime version 1.7.5 (spiritnet-10750
), staking rewards were automatically minted.
In 1.8.0 (spiritnet-10801
) this will change:
Hereafter, the rewards are still accounted to the collators and their delegators in each block.
However, they need to be actively claimed by calling an extrinsic, similar to the pull-based approach on Polkadot.
Since the rewards never expire, one does not need to rush to do so.
This change improves the scalability of our LDPoS by orders of magnitude because it removes the Rewarded
events for a collator and all their delegators in each block.
This reduces the number of taxable events from many thousands per year to any number a user might find suitable.
Please check our blogpost for more details.
How to check the reward amount
Unfortunately, the amount of accumulated rewards are not directly stored on the chain but divided into multiple storage entries. Luckily, you can easily query your current reward status by performing a runtime API call which we created for that specific purpose. Since this is just a simple query, it does not cost any transaction fees.
- Polkadot Apps
- Polkadot JS
In the Polkadot JS Apps (wss://spiritnet.kilt.io, or wss://peregrine.kilt.io) go to Developer -> Runtime calls
.
- Select the
parachainStaking
endpoint. - Select the
getUnclaimedStakingRewards(account)
call. - Select your KILT address (the account: AccountId32 field)
- Submit the runtime call (the Submit Runtime call button). You do not need to sign or pay any fees.
import * as Kilt from '@kiltprotocol/sdk-js'
import { Balance } from '@polkadot/types/interfaces'
export async function getUnclaimedStakingRewards(account: Kilt.KiltAddress) {
const api = Kilt.ConfigService.get('api')
const rewards =
await api.call.staking.getUnclaimedStakingRewards<Balance>(account)
return rewards.toBigInt()
}
How to claim
In order to move the staking rewards into your wallet, you need to call two different extrinsics: increment{Collator, Delegator}Rewards
and claimRewards
.
This can be done sequentially or in a batch.
To save transaction fees, we recommend the latter batched call.
You can either execute this transaction in Polkadot JS Apps or the KILT Stakeboard, which serves as an in-house developed Frontend for all KILT staking activity. Below, we outline the steps for Polkadot JS Apps. The process for KILT Stakeboard is described in detail in the BOTLabs Trusted Entity support hub.
In the Polkadot JS Apps (wss://spiritnet.kilt.io, or wss://peregrine.kilt.io) go to Developer -> Extrinsics -> Submission
.
- Collator
- Delegator
- Polkadot Apps
- Polkadot JS
Prepare claiming
First, you need to convert your reward points into balance.
- Select the collator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the using the selected account field)
- Select the appropriate extrinsic:
parachainStaking -> incrementCollatorRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
Claim
Finally, you can claim your well deserved staking rewards.
- Select the collator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the using the selected account field)
- Select the appropriate extrinsic:
parachainStaking -> claimRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
Recommendation: Batched call
We recommend to execute both extrinsics in a single batch to save on transaction fees:
- Select the collator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the using the selected account field)
- Select the batch extrinsic:
utility -> batch()
- Select the reward increment extrinsic:
parachainStaking -> incrementCollatorRewards()
- Press the
+
button and add the reward claiming extrinsic:parachainStaking -> claimRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
import * as Kilt from '@kiltprotocol/sdk-js'
export async function claimCollatorStakingRewards(
submitterAccount: Kilt.KeyringPair
) {
const api = Kilt.ConfigService.get('api')
const tx = api.tx.utility.batch([
// convert collator participation points into rewards
api.tx.parachainStaking.incrementCollatorRewards(),
// mint rewards for collator address
api.tx.parachainStaking.claimRewards()
])
// boilerplate to sign and send tx to websocket
return new Promise((resolve, reject) =>
tx.signAndSend(submitterAccount, ({ status, dispatchError }) => {
if (status.isFinalized && !dispatchError) {
onSuccess(
submitterAccount.address,
status.asFinalized.toString(),
resolve
)
}
if (dispatchError) {
if (dispatchError.isModule) {
// for module errors, we have the section indexed, lookup
const decoded = api.registry.findMetaError(dispatchError.asModule)
const { docs, name, section } = decoded
const error = new Error(`${section}.${name}: ${docs.join(' ')}`)
onError(error, reject)
} else {
// Other, CannotLookup, BadOrigin, no extra info
const error = new Error(dispatchError.toString())
onError(error, reject)
}
}
})
)
}
// boilerplate handlers
const onSuccess = (
address: string,
txHash: string,
resolve: (res: string) => void
) => {
console.log(
`Claimed collator staking rewards for ${address} with tx hash ${txHash}`
)
resolve(txHash)
}
const onError = (error: Error, reject: (err: Error) => void) => {
console.error(`Failed to claim collator staking rewards due to ${error}`)
reject(error)
}
- Polkadot Apps
- Polkadot JS
Prepare claiming
First, you need to convert your reward points into balance.
- Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the using the selected account field)
- Select the appropriate extrinsic:
parachainStaking -> incrementDelegatorRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
Claim
Finally, you can claim your well deserved staking rewards.
- Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.0001 KILT (the using the selected account field)
- Select the appropriate extrinsic:
parachainStaking -> claimRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
Recommendation: Batched call
We recommend to execute both extrinsics in a single batch to save on transaction fees:
- Select the delegator account for which you want to claim the rewards. It should have enough balance to cover the transaction fee which is around 0.000112 KILT (the using the selected account field)
- Select the batch extrinsic:
utility -> batch()
- Select the reward increment extrinsic:
parachainStaking -> incrementDelegatorRewards()
- Press the
+
button and add the reward claiming extrinsic:parachainStaking -> claimRewards()
- Sign and submit the extrinsic (the Submit Transaction button)
import * as Kilt from '@kiltprotocol/sdk-js'
export async function claimDelegatorStakingRewards(
submitterAccount: Kilt.KeyringPair
) {
const api = Kilt.ConfigService.get('api')
const tx = api.tx.utility.batch([
// convert delegator participation points into rewards
api.tx.parachainStaking.incrementDelegatorRewards(),
// mint rewards for delegator address
api.tx.parachainStaking.claimRewards()
])
// boilerplate to sign and send tx to websocket
return new Promise((resolve, reject) =>
tx.signAndSend(submitterAccount, ({ status, dispatchError }) => {
if (status.isFinalized && !dispatchError) {
onSuccess(
submitterAccount.address,
status.asFinalized.toString(),
resolve
)
}
if (dispatchError) {
if (dispatchError.isModule) {
// for module errors, we have the section indexed, lookup
const decoded = api.registry.findMetaError(dispatchError.asModule)
const { docs, name, section } = decoded
const error = new Error(`${section}.${name}: ${docs.join(' ')}`)
onError(error, reject)
} else {
// Other, CannotLookup, BadOrigin, no extra info
const error = new Error(dispatchError.toString())
onError(error, reject)
}
}
})
)
}
// boilerplate handlers
const onSuccess = (
address: string,
txHash: string,
resolve: (res: string) => void
) => {
console.log(
`Claimed delegator staking rewards for ${address} with tx hash ${txHash}`
)
resolve(txHash)
}
const onError = (error: Error, reject: (err: Error) => void) => {
console.error(`Failed to claim delegator staking rewards due to ${error}`)
reject(error)
}