Tezos refers to its staking process as "baking," and validators on the network are called "bakers."
Tezos supports two participation options: delegation and staking.
- Delegation allows you to assign your wallet to a baker without locking your funds.
- Staking involves locking a fixed amount of XTZ, offering higher rewards but also introducing risks such as slashing.
There is no minimum amount required for delegation or staking. However, both have a 5-6 days activation period before rewards begin to accrue. Staked funds have an unbonding period of approximately 4 days before they can be claimed again.
Reward distribution
There is no limit to the number of bakers (staking nodes) in the Tezos network. As a result, staking rewards vary depending on overall network participation. After the 5-6 days activation period, rewards are calculated and distributed approximately every three days.
- Rewards are sent to the same wallet used for delegation or staking.
- They are automatically added to the wallet’s balance and increase the delegated amount.
Note:
If you are delegating through a third-party baker, they may deduct a fee from the rewards.
Staking XTZ in Fireblocks
Before setting up staking, create a dedicated vault account and name it “XTZ Staking.”
- Delegating: The entire balance of the XTZ wallet is delegated. You can transfer funds to or from the wallet at any time.
- Staking: After delegating a wallet, you can stake a fixed amount of XTZ with the same baker.
Rewards are sent to the delegated/staked wallet and are automatically added to its balance.
Unstaking delay: If you staked XTZ, you must wait approximately 4 days after unstaking before the funds are made available. After this period, call finalizeUnstake()
to make the balance liquid again.
Staking and unstaking XTZ
You can use the Fireblocks Tezos Staking SDK to delegate, stake, unstake, and undelegate XTZ. Install the SDK and use the following commands based on your operation:
Delegate
Assign a baker to manage staking for your wallet.
setDelegate(fireblocks, url, destination, vaultAccountId, reveal, testnet);
-
reveal
must betrue
if this is the wallet’s first on-chain transaction. -
destination
is the baker’s address (tz1...
). -
testnet
istrue
if using Ghostnet or another test network.
Stake
Lock a specific amount of XTZ with a previously delegated baker.
setStake(fireblocks, url, vaultAccountId, stakeAmount, testnet, delegateHash);
-
stakeAmount
is in Tezos (e.g., "5" = 5 XTZ). -
delegateHash
is optional and helps sync with the blockchain if you just calledsetDelegate()
.
Unstake
Unlock a portion of your previously staked XTZ.
setUnstake(fireblocks, url, vaultAccountId, unstakeAmount, testnet, stakeHash);
Undelegate
Remove the current baker from the wallet.
setDelegate(fireblocks, url, null, vaultAccountId, false, testnet, unstakeHash);
Finalize Unstake
Make previously unstaked funds available after the unbonding period.
Example
Use the following script to perform all staking operations in sequence:
import fs from "fs";
import path from "path";
import { FireblocksSDK } from "fireblocks-sdk";
import { setDelegate, setStake, setUnstake, finalizeUnstake } from "./src/xtz-staker";
require("dotenv").config();
const apiSecret = fs.readFileSync(path.resolve(__dirname, process.env.FB_API_SECRET_FILE_PATH), "utf8");
const apiKey = process.env.FB_API_KEY || "";
const fireblocks = new FireblocksSDK(apiSecret, apiKey);
const url = process.env.TEZOS_RPC_URL || "https://rpc.ghostnet.teztnets.com";
const destination = process.env.TEZOS_BAKER_ADDRESS;
const vaultAccountId = process.env.FB_VAULT_ID;
const reveal = process.env.REVEAL_ADDRESS === "true";
const testnet = url.includes("ghostnet");
const stakeAmount = process.env.STAKE_AMOUNT || "0";
async function main() {
const delegateHash = await setDelegate(fireblocks, url, destination, vaultAccountId, reveal, testnet);
const stakeHash = await setStake(fireblocks, url, vaultAccountId, stakeAmount, testnet, delegateHash);
const unstakeHash = await setUnstake(fireblocks, url, vaultAccountId, stakeAmount, testnet, stakeHash);
await setDelegate(fireblocks, url, null, vaultAccountId, false, testnet, unstakeHash);
await finalizeUnstake(fireblocks, url, vaultAccountId, testnet);
}
main().then(() => {
console.log("Tezos staking flow completed.");
}).catch(console.error);
Script parameters
Parameter | Definition |
fireblocks | The initialized FireblocksSDK instance. |
url | Tezos public RPC URL. Example: https://rpc.tzbeta.net/ |
destination | Baker address for delegation. For undelegation, use null. |
vaultAccountId | The Fireblocks vault account that holds the XTZ wallet. |
reveal | Set to true only if this is the wallet’s first outgoing transaction. |
stakeAmount | Amount of XTZ to stake or unstake (in Tezos, e.g., "10" = 10 XTZ). |
testnet | Boolean. Set to true if using Ghostnet or another Tezos testnet. |
delegateHash | Optional hash returned by setDelegate() for transaction polling. |
stakeHash | Optional hash returned by setStake() for transaction polling. |