Pagtataya
Kumuha ng Mga Kasalukuyang Validator
Maaari nating i-stake ang SOL at makakuha ng mga reward para sa pagtulong sa pag-secure ng network. Para i-stake, itinatalaga namin ang SOL sa mga validator na nagpoproseso naman ng mga transaksyon.
import { clusterApiUrl, Connection } from "@solana/web3.js";
(async () => {
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
// Get all validators, categorized by current (i.e. active) and deliquent (i.e. inactive)
const { current, delinquent } = await connection.getVoteAccounts();
console.log("current validators: ", current);
console.log("all validators: ", current.concat(delinquent));
})();
solana validators
Gumawa ng Stake Account
Ang lahat ng mga instruction sa staking ay pinangangasiwaan ng Stake Program. Upang magsimula, gumawa kami ng Stake Account na ginawa at pinamamahalaan nang iba kaysa sa karaniwang [system account](accounts.md#create-a-system -account). Sa partikular, dapat nating itakda ang Stake Authority
at Withdrawal Authority
ng account.
import {
clusterApiUrl,
Connection,
Keypair,
LAMPORTS_PER_SOL,
StakeProgram,
Authorized,
sendAndConfirmTransaction,
Lockup,
} from "@solana/web3.js";
(async () => {
// Setup our connection and wallet
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const wallet = Keypair.generate();
// Fund our wallet with 1 SOL
const airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature);
// Create a keypair for our stake account
const stakeAccount = Keypair.generate();
// Calculate how much we want to stake
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space
);
const amountUserWantsToStake = LAMPORTS_PER_SOL / 2; // This is can be user input. For now, we'll hardcode to 0.5 SOL
const amountToStake = minimumRent + amountUserWantsToStake;
// Setup a transaction to create our stake account
// Note: `StakeProgram.createAccount` returns a `Transaction` preconfigured with the necessary `TransactionInstruction`s
const createStakeAccountTx = StakeProgram.createAccount({
authorized: new Authorized(wallet.publicKey, wallet.publicKey), // Here we set two authorities: Stake Authority and Withdrawal Authority. Both are set to our wallet.
fromPubkey: wallet.publicKey,
lamports: amountToStake,
lockup: new Lockup(0, 0, wallet.publicKey), // Optional. We'll set this to 0 for demonstration purposes.
stakePubkey: stakeAccount.publicKey,
});
const createStakeAccountTxId = await sendAndConfirmTransaction(
connection,
createStakeAccountTx,
[
wallet,
stakeAccount, // Since we're creating a new stake account, we have that account sign as well
]
);
console.log(`Stake account created. Tx Id: ${createStakeAccountTxId}`);
// Check our newly created stake account balance. This should be 0.5 SOL.
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
// Verify the status of our stake account. This will start as inactive and will take some time to activate.
let stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
})();
// Setup a transaction to create our stake account
// Note: `StakeProgram.createAccount` returns a `Transaction` preconfigured with the necessary `TransactionInstruction`s
const createStakeAccountTx = StakeProgram.createAccount({
authorized: new Authorized(wallet.publicKey, wallet.publicKey), // Here we set two authorities: Stake Authority and Withdrawal Authority. Both are set to our wallet.
fromPubkey: wallet.publicKey,
lamports: amountToStake,
lockup: new Lockup(0, 0, wallet.publicKey), // Optional. We'll set this to 0 for demonstration purposes.
stakePubkey: stakeAccount.publicKey,
});
const createStakeAccountTxId = await sendAndConfirmTransaction(
connection,
createStakeAccountTx,
[
wallet,
stakeAccount, // Since we're creating a new stake account, we have that account sign as well
]
);
console.log(`Stake account created. Tx Id: ${createStakeAccountTxId}`);
// Check our newly created stake account balance. This should be 0.5 SOL.
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
// Verify the status of our stake account. This will start as inactive and will take some time to activate.
let stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
Delegate Stake
Kapag napondohan ang isang stake account, maaaring italaga ito ng Stake Authority
sa isang validator. Ang bawat stake account ay maaari lamang italaga sa isang validator sa isang pagkakataon. Bilang karagdagan, ang lahat ng mga token sa account ay dapat na italaga o hindi itinalaga. Kapag na-delegate, kailangan ng ilang panahon para maging aktibo ang isang stake account.
import {
clusterApiUrl,
Connection,
Keypair,
LAMPORTS_PER_SOL,
StakeProgram,
Authorized,
sendAndConfirmTransaction,
Lockup,
PublicKey,
} from "@solana/web3.js";
(async () => {
// Setup our connection and wallet
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const wallet = Keypair.generate();
// Fund our wallet with 1 SOL
const airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature);
// Create a keypair for our stake account
const stakeAccount = Keypair.generate();
// Calculate how much we want to stake
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space
);
const amountUserWantsToStake = LAMPORTS_PER_SOL / 2; // This is can be user input. For now, we'll hardcode to 0.5 SOL
const amountToStake = minimumRent + amountUserWantsToStake;
// Setup a transaction to create our stake account
// Note: `StakeProgram.createAccount` returns a `Transaction` preconfigured with the necessary `TransactionInstruction`s
const createStakeAccountTx = StakeProgram.createAccount({
authorized: new Authorized(wallet.publicKey, wallet.publicKey), // Here we set two authorities: Stake Authority and Withdrawal Authority. Both are set to our wallet.
fromPubkey: wallet.publicKey,
lamports: amountToStake,
lockup: new Lockup(0, 0, wallet.publicKey), // Optional. We'll set this to 0 for demonstration purposes.
stakePubkey: stakeAccount.publicKey,
});
const createStakeAccountTxId = await sendAndConfirmTransaction(
connection,
createStakeAccountTx,
[
wallet,
stakeAccount, // Since we're creating a new stake account, we have that account sign as well
]
);
console.log(`Stake account created. Tx Id: ${createStakeAccountTxId}`);
// Check our newly created stake account balance. This should be 0.5 SOL.
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
// Verify the status of our stake account. This will start as inactive and will take some time to activate.
let stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// To delegate our stake, we first have to select a validator. Here we get all validators and select the first active one.
const validators = await connection.getVoteAccounts();
const selectedValidator = validators.current[0];
const selectedValidatorPubkey = new PublicKey(selectedValidator.votePubkey);
// With a validator selected, we can now setup a transaction that delegates our stake to their vote account.
const delegateTx = StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
votePubkey: selectedValidatorPubkey,
});
const delegateTxId = await sendAndConfirmTransaction(connection, delegateTx, [
wallet,
]);
console.log(
`Stake account delegated to ${selectedValidatorPubkey}. Tx Id: ${delegateTxId}`
);
// Check in on our stake account. It should now be activating.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
})();
// With a validator selected, we can now setup a transaction that delegates our stake to their vote account.
const delegateTx = StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
votePubkey: selectedValidatorPubkey,
});
const delegateTxId = await sendAndConfirmTransaction(connection, delegateTx, [
wallet,
]);
console.log(
`Stake account delegated to ${selectedValidatorPubkey}. Tx Id: ${delegateTxId}`
);
// Check in on our stake account. It should now be activating.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
Kumuha ng Delegator ng mga Validator
Maaaring na-stakes ng maraming account sa isang partikular na validator account. Para makuha ang lahat ng staker, gagamitin namin ang getProgramAccounts
o getParsedProgramAccounts
API. Sumangguni sa guides section para sa higit pang impormasyon. Ang mga stake account ay 200 bytes ang haba at ang Voter Public Key ay nagsisimula sa 124 bytes. Sanggunian
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
(async () => {
const STAKE_PROGRAM_ID = new PublicKey(
"Stake11111111111111111111111111111111111111"
);
const VOTE_PUB_KEY = "27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x";
const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
const accounts = await connection.getParsedProgramAccounts(STAKE_PROGRAM_ID, {
filters: [
{
dataSize: 200, // number of bytes
},
{
memcmp: {
offset: 124, // number of bytes
bytes: VOTE_PUB_KEY, // base58 encoded string
},
},
],
});
console.log(`Accounts for program ${STAKE_PROGRAM_ID}: `);
console.log(
`Total number of delegators found for ${VOTE_PUB_KEY} is: ${accounts.length}`
);
if (accounts.length)
console.log(`Sample delegator:`, JSON.stringify(accounts[0]));
/*
// Output
Accounts for program Stake11111111111111111111111111111111111111:
Total number of delegators found for 27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x is: 184
Sample delegator:
{
"account": {
"data": {
"parsed": {
"info": {
"meta": {
"authorized": {
"staker": "3VDVh3rHTLkNJp6FVYbuFcaihYBFCQX5VSBZk23ckDGV",
"withdrawer": "EhYXq3ANp5nAerUpbSgd7VK2RRcxK1zNuSQ755G5Mtxx"
},
"lockup": {
"custodian": "3XdBZcURF5nKg3oTZAcfQZg8XEc5eKsx6vK8r3BdGGxg",
"epoch": 0,
"unixTimestamp": 1822867200
},
"rentExemptReserve": "2282880"
},
"stake": {
"creditsObserved": 58685367,
"delegation": {
"activationEpoch": "208",
"deactivationEpoch": "18446744073709551615",
"stake": "433005300621",
"voter": "27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x",
"warmupCooldownRate": 0.25
}
}
},
"type": "delegated"
},
"program": "stake",
"space": 200
},
"executable": false,
"lamports": 433012149261,
"owner": {
"_bn": "06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000"
},
"rentEpoch": 264
},
"pubkey": {
"_bn": "0dc8b506f95e52c9ac725e714c7078799dd3268df562161411fe0916a4dc0a43"
}
}
*/
})();
const STAKE_PROGRAM_ID = new PublicKey(
"Stake11111111111111111111111111111111111111"
);
const VOTE_PUB_KEY = "27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x";
const connection = new Connection(clusterApiUrl("mainnet-beta"), "confirmed");
const accounts = await connection.getParsedProgramAccounts(STAKE_PROGRAM_ID, {
filters: [
{
dataSize: 200, // number of bytes
},
{
memcmp: {
offset: 124, // number of bytes
bytes: VOTE_PUB_KEY, // base58 encoded string
},
},
],
});
console.log(`Accounts for program ${STAKE_PROGRAM_ID}: `);
console.log(
`Total number of delegators found for ${VOTE_PUB_KEY} is: ${accounts.length}`
);
if (accounts.length)
console.log(`Sample delegator:`, JSON.stringify(accounts[0]));
/*
// Output
Accounts for program Stake11111111111111111111111111111111111111:
Total number of delegators found for 27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x is: 184
Sample delegator:
{
"account": {
"data": {
"parsed": {
"info": {
"meta": {
"authorized": {
"staker": "3VDVh3rHTLkNJp6FVYbuFcaihYBFCQX5VSBZk23ckDGV",
"withdrawer": "EhYXq3ANp5nAerUpbSgd7VK2RRcxK1zNuSQ755G5Mtxx"
},
"lockup": {
"custodian": "3XdBZcURF5nKg3oTZAcfQZg8XEc5eKsx6vK8r3BdGGxg",
"epoch": 0,
"unixTimestamp": 1822867200
},
"rentExemptReserve": "2282880"
},
"stake": {
"creditsObserved": 58685367,
"delegation": {
"activationEpoch": "208",
"deactivationEpoch": "18446744073709551615",
"stake": "433005300621",
"voter": "27MtjMSAQ2BGkXNuJEJkxFyCJT8dugGAaHJ9T7Gc6x4x",
"warmupCooldownRate": 0.25
}
}
},
"type": "delegated"
},
"program": "stake",
"space": 200
},
"executable": false,
"lamports": 433012149261,
"owner": {
"_bn": "06a1d8179137542a983437bdfe2a7ab2557f535c8a78722b68a49dc000000000"
},
"rentEpoch": 264
},
"pubkey": {
"_bn": "0dc8b506f95e52c9ac725e714c7078799dd3268df562161411fe0916a4dc0a43"
}
}
*/
I-deactivate ang Stake
Sa anumang oras pagkatapos maitalaga ang isang stake account, maaaring piliin ng Stake Authority
na i-deactivate ang account. Maaaring tumagal ng ilang panahon upang makumpleto ang pag-deactivate, at kinakailangan bago mabawi ang anumang SOL.
import {
clusterApiUrl,
Connection,
Keypair,
LAMPORTS_PER_SOL,
StakeProgram,
Authorized,
sendAndConfirmTransaction,
Lockup,
PublicKey,
} from "@solana/web3.js";
(async () => {
// Setup our connection and wallet
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const wallet = Keypair.generate();
// Fund our wallet with 1 SOL
const airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature);
// Create a keypair for our stake account
const stakeAccount = Keypair.generate();
// Calculate how much we want to stake
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space
);
const amountUserWantsToStake = LAMPORTS_PER_SOL / 2; // This is can be user input. For now, we'll hardcode to 0.5 SOL
const amountToStake = minimumRent + amountUserWantsToStake;
// Setup a transaction to create our stake account
// Note: `StakeProgram.createAccount` returns a `Transaction` preconfigured with the necessary `TransactionInstruction`s
const createStakeAccountTx = StakeProgram.createAccount({
authorized: new Authorized(wallet.publicKey, wallet.publicKey), // Here we set two authorities: Stake Authority and Withdrawal Authority. Both are set to our wallet.
fromPubkey: wallet.publicKey,
lamports: amountToStake,
lockup: new Lockup(0, 0, wallet.publicKey), // Optional. We'll set this to 0 for demonstration purposes.
stakePubkey: stakeAccount.publicKey,
});
const createStakeAccountTxId = await sendAndConfirmTransaction(
connection,
createStakeAccountTx,
[
wallet,
stakeAccount, // Since we're creating a new stake account, we have that account sign as well
]
);
console.log(`Stake account created. Tx Id: ${createStakeAccountTxId}`);
// Check our newly created stake account balance. This should be 0.5 SOL.
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
// Verify the status of our stake account. This will start as inactive and will take some time to activate.
let stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// To delegate our stake, we first have to select a validator. Here we get all validators and select the first active one.
const validators = await connection.getVoteAccounts();
const selectedValidator = validators.current[0];
const selectedValidatorPubkey = new PublicKey(selectedValidator.votePubkey);
// With a validator selected, we can now setup a transaction that delegates our stake to their vote account.
const delegateTx = StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
votePubkey: selectedValidatorPubkey,
});
const delegateTxId = await sendAndConfirmTransaction(connection, delegateTx, [
wallet,
]);
console.log(
`Stake account delegated to ${selectedValidatorPubkey}. Tx Id: ${delegateTxId}`
);
// Check in on our stake account. It should now be activating.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// At anytime we can choose to deactivate our stake. Our stake account must be inactive before we can withdraw funds.
const deactivateTx = StakeProgram.deactivate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
});
const deactivateTxId = await sendAndConfirmTransaction(
connection,
deactivateTx,
[wallet]
);
console.log(`Stake account deactivated. Tx Id: ${deactivateTxId}`);
// Check in on our stake account. It should now be inactive.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
})();
// At anytime we can choose to deactivate our stake. Our stake account must be inactive before we can withdraw funds.
const deactivateTx = StakeProgram.deactivate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
});
const deactivateTxId = await sendAndConfirmTransaction(
connection,
deactivateTx,
[wallet]
);
console.log(`Stake account deactivated. Tx Id: ${deactivateTxId}`);
// Check in on our stake account. It should now be inactive.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
I-withdraw ang Stake
Kapag na-deactivate, ang Withdrawal Authority
ay maaaring mag-withdraw ng SOL pabalik sa isang system account. Kapag ang isang stake account ay hindi na na-delegate at may balanseng 0 SOL, ito ay epektibong masisira.
import {
clusterApiUrl,
Connection,
Keypair,
LAMPORTS_PER_SOL,
StakeProgram,
Authorized,
sendAndConfirmTransaction,
Lockup,
PublicKey,
} from "@solana/web3.js";
(async () => {
// Setup our connection and wallet
const connection = new Connection(clusterApiUrl("devnet"), "confirmed");
const wallet = Keypair.generate();
// Fund our wallet with 1 SOL
const airdropSignature = await connection.requestAirdrop(
wallet.publicKey,
LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature);
// Create a keypair for our stake account
const stakeAccount = Keypair.generate();
// Calculate how much we want to stake
const minimumRent = await connection.getMinimumBalanceForRentExemption(
StakeProgram.space
);
const amountUserWantsToStake = LAMPORTS_PER_SOL / 2; // This is can be user input. For now, we'll hardcode to 0.5 SOL
const amountToStake = minimumRent + amountUserWantsToStake;
// Setup a transaction to create our stake account
// Note: `StakeProgram.createAccount` returns a `Transaction` preconfigured with the necessary `TransactionInstruction`s
const createStakeAccountTx = StakeProgram.createAccount({
authorized: new Authorized(wallet.publicKey, wallet.publicKey), // Here we set two authorities: Stake Authority and Withdrawal Authority. Both are set to our wallet.
fromPubkey: wallet.publicKey,
lamports: amountToStake,
lockup: new Lockup(0, 0, wallet.publicKey), // Optional. We'll set this to 0 for demonstration purposes.
stakePubkey: stakeAccount.publicKey,
});
const createStakeAccountTxId = await sendAndConfirmTransaction(
connection,
createStakeAccountTx,
[
wallet,
stakeAccount, // Since we're creating a new stake account, we have that account sign as well
]
);
console.log(`Stake account created. Tx Id: ${createStakeAccountTxId}`);
// Check our newly created stake account balance. This should be 0.5 SOL.
let stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
// Verify the status of our stake account. This will start as inactive and will take some time to activate.
let stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// To delegate our stake, we first have to select a validator. Here we get all validators and select the first active one.
const validators = await connection.getVoteAccounts();
const selectedValidator = validators.current[0];
const selectedValidatorPubkey = new PublicKey(selectedValidator.votePubkey);
// With a validator selected, we can now setup a transaction that delegates our stake to their vote account.
const delegateTx = StakeProgram.delegate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
votePubkey: selectedValidatorPubkey,
});
const delegateTxId = await sendAndConfirmTransaction(connection, delegateTx, [
wallet,
]);
console.log(
`Stake account delegated to ${selectedValidatorPubkey}. Tx Id: ${delegateTxId}`
);
// Check in on our stake account. It should now be activating.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// At anytime we can choose to deactivate our stake. Our stake account must be inactive before we can withdraw funds.
const deactivateTx = StakeProgram.deactivate({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
});
const deactivateTxId = await sendAndConfirmTransaction(
connection,
deactivateTx,
[wallet]
);
console.log(`Stake account deactivated. Tx Id: ${deactivateTxId}`);
// Check in on our stake account. It should now be inactive.
stakeStatus = await connection.getStakeActivation(stakeAccount.publicKey);
console.log(`Stake account status: ${stakeStatus.state}`);
// Once deactivated, we can withdraw our SOL back to our main wallet
const withdrawTx = StakeProgram.withdraw({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
toPubkey: wallet.publicKey,
lamports: stakeBalance, // Withdraw the full balance at the time of the transaction
});
const withdrawTxId = await sendAndConfirmTransaction(connection, withdrawTx, [
wallet,
]);
console.log(`Stake account withdrawn. Tx Id: ${withdrawTxId}`);
// Confirm that our stake account balance is now 0
stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);
})();
// Once deactivated, we can withdraw our SOL back to our main wallet
const withdrawTx = StakeProgram.withdraw({
stakePubkey: stakeAccount.publicKey,
authorizedPubkey: wallet.publicKey,
toPubkey: wallet.publicKey,
lamports: stakeBalance, // Withdraw the full balance at the time of the transaction
});
const withdrawTxId = await sendAndConfirmTransaction(connection, withdrawTx, [
wallet,
]);
console.log(`Stake account withdrawn. Tx Id: ${withdrawTxId}`);
// Confirm that our stake account balance is now 0
stakeBalance = await connection.getBalance(stakeAccount.publicKey);
console.log(`Stake account balance: ${stakeBalance / LAMPORTS_PER_SOL} SOL`);