Solana - Solana Staking:4 种简单的方法来抵押 SOL 并赚取收益

  • QuickNode
  • 发布于 2025-02-21 22:56
  • 阅读 66

这篇文章详细介绍了如何在Solana网络上进行SOL质押,包括使用钱包、命令行接口和JavaScript API等多种方法。文章结构清晰,内容丰富,逐步指导用户完成质押过程,同时强调了液体质押的概念。提供了大量资源和链接,适合希望深入了解Solana质押的用户。

更聪明地质押。更快地赚钱。使用 QuickNode。

与顶级 Solana RPC 提供商进行质押——体验 QuickNode 的高性能验证器 带来的无与伦比的可靠性和速度。

  • 100% 在线:过去 30 天内无停机时间的可靠性。
  • 0% 佣金:所有质押奖励,包括 JITO 小费,均直接归质押者所有。
  • 高性能质押:Solana 生态系统信赖的可靠且高效的基础设施。
  • 合规性:符合 SOC 1 Type 2 和 Soc 2 Type 2 标准。

了解更多: StakeWiz | Solana Compass | Validators.app | Solscan | Solana Beach

概述

质押原生代币是区块链网络激励验证者保障网络安全的一种常见方式。验证者因为他们的工作而获得网络原生代币的一部分作为奖励。质押也是代币持有者在他们持有的代币上赚取被动收入的绝佳方式。在本指南中,我们将介绍在 Solana 上质押 SOL 的四种方法:

  • 使用 Solana 钱包(例如 PhantomSolflare
  • 使用 Solana 命令行界面(Solana CLI)
  • 使用 Solana 的 JavaScript API
  • 使用液体质押

你将需要什么

  • 安装最新版本的 Solana CLI
  • 安装 Nodejs(版本 16.15 或更高)
  • 基本的 JavaScript 经验
  • 现代网页浏览器(例如 Google Chrome
  • Solana 钱包(例如 Phantom)或 Squad
  • 一些用于质押和账户租金/交易费的 SOL 代币

什么是质押?

质押对于 Solana 的安全性和激励结构至关重要,它允许验证者将一定数量的他们的 SOL 代币锁定在质押账户中,通过权益证明(Proof-of-Stake, PoS)机制参与共识。验证者为交易确认和区块生产做出贡献,获得与其质押金额成比例的奖励。该机制通过对任何恶意行为的验证者施加失去的风险来增强网络安全性。

在 Solana 上创建质押账户需要生成一个新的质押账户,然后将 SOL 代币从资助的钱包转移到该账户。可以在创建时分配质押和提取权限,或稍后修改以实现最佳灵活性。每个质押账户只被授权给一个验证者;但是,用户/权限可以拥有多个质押账户,以便将他们的质押分配给多个验证者。对质押的更改(例如,激活、授权和停用)将在下一个纪元生效(一个纪元约为 2 天)。这种渐进过程促进了网络的稳定性和可预测性,防止了质押分布的突然大幅变化。

有关质押的更多信息,请查看 Solana 文档。如果你需要帮助寻找验证者,有一些资源可以帮助你找到一个:

让我们质押一些 SOL 吧!

方法 1 - 使用钱包

质押你的 SOL 的最简单方式之一是直接在你的钱包中。大多数主要的钱包都有一个质押接口,允许你只需点击几下将你的 SOL 指派给一个验证者。以下是如何使用一些流行钱包进行操作:

使用 Phantom 质押

在 Phantom 质押非常简单。打开你的 Phantom 钱包扩展:

Phantom Wallet

你应该会看到一些关于 Solana 的详细信息。向下滚动,直到看到“开始赚取 SOL”按钮。单击它以开始质押。

Phantom Staking

从你提供的选项中选择“原生质押”:

Phantom Staking Options

在搜索栏中搜索“QuickNode”以找到我们的验证者(或选择你选择的验证者名称)。你还可以按验证者的地址进行搜索(例如,5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK)。单击所需的验证者。系统会提示你输入要质押的数量。输入后单击“质押”以确认。过了一会儿,你将看到“SOL 已质押!”的成功消息:

Phantom Staking Validator

你的质押将在下一个纪元开始时激活。你可以通过再次点击你的 Solana 余额在你的钱包中检查你的质押状态(或任何主要 Solana 浏览器)。你应该会在“质押”下看到你的质押:

Phantom Staking Success

你可以打开该项目以查看有关你质押的更多详细信息。你还可以通过 Solana Beach 查看你的质押。

Phantom Staking Details

就这样!你现在正在通过 Phantom 质押 SOL。

使用 Solflare 质押

Solflare 使质押变得轻而易举。打开你的 Solflare 钱包,点击你的 Solana 余额。你将被引导到一个 Solana 详细信息屏幕:

Solflare Wallet

你应该会看到一个“质押 SOL”模块。点击“质押”:

Solflare Wallet Stake Button

搜索你选择的验证者(例如,“QuickNode”或“5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK”),并从下拉列表中选择你的所需验证者:

Solflare Wallet

在输入你希望质押的数量后,点击“质押”。系统会提示你确认交易:

Solflare Wallet

然后你可以返回到你的 Solana 余额详细信息屏幕,你将看到新的“质押”余额:

Solflare Wallet

点击它以查看你正在激活的质押的详细信息:

Solflare Wallet

干得好!你现在正在通过 Solflare 质押 SOL。🔥

使用 Backpack 质押

Backpack 是另一个流行的 Solana 钱包,允许你在不离开钱包的情况下质押你的 SOL。打开你的 Backpack 钱包。从主屏幕上单击你的 Solana 余额:

Backpack Wallet

你将看到你的 SOL 余额,并有一个选项可以“⭐️ 质押 SOL 以赚钱”。点击此按钮:

Backpack SOL Balance

你将获得选择所需验证者的选项。点击“其他验证者”以搜索特定的验证者:

Backpack Validator Search

搜索你的所需验证者(例如,“QuickNode”或“5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK”),并选择它:

Backpack Validator Search Results

你将返回到“新质押”屏幕,并选择的验证者。输入你希望质押的数量,然后单击“质押”。

Backpack QuickNode Validator

你将被重定向到 SOL 余额页面,你将在“质押”下看到你的新账户:

Backpack SOL Balance

你的包(🎒)现在装满了质押的 SOL!

使用 Squads 进行质押

Squads 是 Solana 上的一个开源智能合约钱包标准,允许团队和个人安全管理他们的数字资产。Squads 用户可以直接通过 Squads UI 质押他们的 SOL。让我们来详细了解一下这个过程。

打开你的 Squads 钱包,并连接到授权发起人的钱包。单击左侧边栏上的“质押”选项卡。屏幕底部有一个搜索栏,你可以在其中搜索验证者。搜索你的所需验证者(例如,“QuickNode”或“5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK”)。

Squads Wallet

单击你所需的验证者。你将被要求输入希望质押的数量:

Squads Stake Validators

输入数量后,点击“质押”。系统会提示你发起交易以获得你的 Squad 批准:

Squads Confirmation

导航到“交易”选项卡以查看打开的交易。与你的 Squad 成员共享提案以获得批准。一旦你的投票门槛实现,你将能够在你的 Squad 中“执行”该交易:

Squads Transaction

你现在应该能够返回“质押”选项卡,查看你的质押 SOL:

Squads Staked SOL

你现在正在利用 Squads 保证你的资产并帮助保障 Solana 网络!

方法 2 - 使用 Solana CLI

让我们首先创建一个项目目录,其中包含一个用于 CLI 的文件夹和一个用于 JavaScript API 的文件夹(我们稍后将使用):

mkdir -p solana-staking/cli && mkdir -p solana-staking/web3js
cd solana-staking/cli

要使用 Solana CLI 进行质押,你需要一个纸钱包。如果你还没有,可以在终端中输入以下命令来创建一个:

solana-keygen new --no-passphrase -o wallet.json

这将创建一对新的密钥并将其保存到名为 wallet.json 的文件中。你的新 PublicKey 将在终端中显示:

Generating a new keypair
Wrote new keypair to wallet.json
============================================================================
pubkey: Fzts...kjKb
===========================================================================

确保你的纸钱包已用 SOL 资助。如果你刚刚创建了一个,可以从任何钱包将资金转移到终端中显示的地址。

接下来,我们需要创建一个质押账户。让我们创建另一个名为 stake-account.json 的密钥对:

solana-keygen new --no-passphrase -s -o stake-account.json

注意:这里我们使用 -s 标志是因为我们不需要为此账户提供种子短语。

现在我们可以使用 stake-account.json 密钥对通过 create-stake-account 命令创建一个质押账户:

solana create-stake-account stake-account.json 100 \
    ----from wallet.json \
    --stake-authority wallet.json --withdraw-authority wallet.json \
    --fee-payer wallet.json \
    --url mainnet-beta  # 或 testnet、devnet、本地或你的 QuickNode URL

确保替换 --url 标志为正确的网络。如果你使用 mainnet-beta,将从你的钱包转移真实资金。为了获得最佳效果,我们建议使用 QuickNode 终端,你可以在 这里 注册一个免费账户。

你现在应该能够通过运行以下命令来验证你的账户是否已创建:

solana stake-account stake-account.json

你应该会在终端中看到你的质押账户信息:

Balance: 100 SOL
Rent Exempt Reserve: 0.00228288 SOL
Stake account is undelegated
Stake Authority: FztsbEJLCmdaeQWuJKZrQ8MjN1j3yVMftynzA5e8kjKb
Withdraw Authority: FztsbEJLCmdaeQWuJKZrQ8MjN1j3yVMftynzA5e8kjKb

你会注意到我们的质押仍需指派给一个验证者——让我们指派它。

首先,我们需要找到一个验证者的地址。你可以在 这里 找到验证者列表,或者在终端中输入 solana validators -um(或者对于 devnet 使用 -ud)。找到一个验证者并复制他们的 投票账户 地址。

Vote Account

我们将使用 QuickNode 的验证者(在 主网络 上为 5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK)。

现在你可以通过调用 solana delegate-stake stake-account.json <VOTE_ACCOUNT> 来指派你的质押:

solana delegate-stake stake-account.json <VOTE_ACCOUNT> \ # 将 <VOTE_ACCOUNT> 替换为你的验证者地址
    --stake-authority wallet.json \
    --fee-payer wallet.json \
    --url https://example.solana-mainnet.quiknode.io/12345 \ # 用你的 Quicknode 终点,或 testnet、mainnet-beta、本地替换
    --with-memo "Delegating stake test."

你应该会在终端中看到一条签名,确认成功的指派。你可以再次通过运行 solana stake-account stake-account.json -ud 验证你的质押是否已指派:

Balance: 0.1 SOL
Rent Exempt Reserve: 0.00228288 SOL
Delegated Stake: 0.09771712 SOL
Active Stake: 0 SOL
Activating Stake: 0.09771712 SOL
Stake activates starting from epoch: 529
Delegated Vote Account Address: 5s3vajJvaAbabQvxFdiMfg14y23b2jvK6K2Mw4PYcYK
Stake Authority: FztsbEJLCmdaeQWuJKZrQ8MjN1j3yVMftynzA5e8kjKb
Withdraw Authority: FztsbEJLCmdaeQWuJKZrQ8MjN1j3yVMftynzA5e8kjKb

干得好!你的质押现在正在激活,并将在下一个纪元开始时开始累积奖励。

一旦你的质押处于活动状态,你可能希望停用质押或从账户中提取一些 SOL。你可以使用 deactivate-stakewithdraw-stake 命令来实现。

要停用你的质押,运行:

solana deactivate-stake stake-account.json \
    --stake-authority wallet.json \
    --fee-payer wallet.json \
    --url https://example.solana-mainnet.quiknode.io/12345 \

要从你的质押账户中提取一些 SOL,请运行:

solana withdraw-stake stake-account.json <DESTINATION> <AMOUNT> \
    --withdraw-authority wallet.json  \
    --fee-payer wallet.json \
    --url https://example.solana-mainnet.quiknode.io/12345 \

确保将你的 --url 替换为你正在使用的适当网络(testnet、mainnet-beta、本地、devnet,或你的 QuickNode URL)。

你现在拥有了从 Solana 命令行质押 SOL 的所有基础知识。我们没有在这里涵盖的一些其他命令。请随意通过在终端中运行 solana -h 来独立探索所有可用命令。

方法 3 - 使用 Solana 的 JavaScript API 质押 SOL

要开始使用 JavaScript,请导航到我们之前创建的 JS 子目录。从你的 cli 目录,运行:

cd ../web3js

创建一个启用了 .json 导入的 tsconfig.json

tsc -init --resolveJsonModule true

安装 SolanaWeb3.js:

npm install @solana/web3.js@1 # 或使用 yarn add @solana/web3.js

创建一个名为 app.ts 的新文件:

echo > app.ts

让我们遵循在上一部分中使用的相同命名约定,并创建一个名为 wallet.json 的新密钥对:

solana-keygen new --no-passphrase -o wallet.json

与其为我们的质押账户使用单一密钥对,我们将使用脚本中的密钥对生成器,以便我们可以创建多个质押账户。

结构化你的项目

打开你喜欢的编辑器中的 app.ts 并添加以下代码:

import { Connection, PublicKey, Keypair, StakeProgram, LAMPORTS_PER_SOL, Authorized, TransactionSignature, TransactionConfirmationStatus, SignatureStatus } from '@solana/web3.js'
import walletSecret from './wallet.json'

const connection = new Connection('http://127.0.0.1:8899', 'confirmed');
const wallet = Keypair.fromSecretKey(new Uint8Array(walletSecret));
const stakeAccount = Keypair.generate();
const validatorVoteAccount = new PublicKey("TBD");

async function confirmTransaction(
    connection: Connection,
    signature: TransactionSignature,
    desiredConfirmationStatus: TransactionConfirmationStatus = 'confirmed',
    timeout: number = 30000,
    pollInterval: number = 1000,
    searchTransactionHistory: boolean = false
): Promise<SignatureStatus> {
    const start = Date.now();

    while (Date.now() - start < timeout) {
        const { value: statuses } = await connection.getSignatureStatuses([signature], { searchTransactionHistory });

        if (!statuses || statuses.length === 0) {
            throw new Error('Failed to get signature status');
        }

        const status = statuses[0];

        if (status === null) {
            await new Promise(resolve => setTimeout(resolve, pollInterval));
            continue;
        }

        if (status.err) {
            throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`);
        }

        if (status.confirmationStatus && status.confirmationStatus === desiredConfirmationStatus) {
            return status;
        }

        if (status.confirmationStatus === 'finalized') {
            return status;
        }

        await new Promise(resolve => setTimeout(resolve, pollInterval));
    }

    throw new Error(`Transaction confirmation timeout after ${timeout}ms`);
}

async function main() {
    try {
        // Step 1 - Fund the wallet
        console.log("---Step 1---Funding wallet");
        await fundAccount(wallet, 2 * LAMPORTS_PER_SOL);
        // Step 2 - Create the stake account
        console.log("---Step 2---Create Stake Account");
        await createStakeAccount({ wallet, stakeAccount, lamports: 1.9 * LAMPORTS_PER_SOL });
        // Step 3 - Delegate the stake account
        console.log("---Step 3---Delegate Stake Account");
        await delegateStakeAccount({ stakeAccount, validatorVoteAccount, authorized: wallet });
        // Step 4 - Check the stake account
        console.log("---Step 4---Check Stake Account");
        await getStakeAccountInfo(stakeAccount.publicKey);
    } catch (error) {
        console.error(error);
        return;
    }
}

async function fundAccount(accountToFund: Keypair, lamports = LAMPORTS_PER_SOL) {

}
async function createStakeAccount({ wallet, stakeAccount, lamports }: { wallet: Keypair, stakeAccount: Keypair, lamports?: number }) {

}
async function delegateStakeAccount({ stakeAccount, validatorVoteAccount }: { stakeAccount: Keypair, validatorVoteAccount: PublicKey }) {

}
async function getStakeAccountInfo(stakeAccount: PublicKey) {

}

main();

我们在这里所做的是:

  • 从 SolanaWeb3.js 和我们的 wallet.json 文件中导入必要的包
  • 创建到我们的本地节点的连接(如果需要,你可以使用不同的集群)
  • 为我们的质押账户创建一个新的密钥对
  • 为我们的验证者投票账户创建一个新的 PublicKey(我们暂时将其保留为“TBD”——在启动本地验证者时需要替换)
  • 建立一个帮助函数以确认交易
  • 创建一个将按顺序运行我们所有函数的 main 函数
  • 创建四个函数,我们将填充以资助、创建、指派和获取有关我们质押账户的信息

让我们逐一构建我们的函数。

第一步 - 资助钱包

我们需要一些测试用的 SOL 来实施我们的交易。让我们使用以下代码更新 fundAccounts 函数:

async function fundAccount(accountToFund: Keypair, lamports = LAMPORTS_PER_SOL) {
    const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
    try {
        const signature = await connection.requestAirdrop(accountToFund.publicKey, lamports);
        const result = await confirmTransaction(connection, signature, 'finalized');
        if (result.value.err) {
            throw new Error(`Failed to confirm airdrop: ${result.value.err}`);
        }
        console.log("Wallet funded", signature);
    }
    catch (error) {
        console.error(error);
    }
    return;
}

我们简单地传递一个 Keypair 并使用 requestAirdrop 方法请求一个 SOL(或用户指定的金额)进行空投。我们耐心等待空投在网络上被确认( 最终确定),以确保我们的资金将在后续步骤中可用。

第二步 - 创建质押账户

接下来,我们将创建质押账户。使用以下代码更新 createStakeAccount 函数:

async function createStakeAccount({ wallet, stakeAccount, lamports }: { wallet: Keypair, stakeAccount: Keypair, lamports?: number }) {
    const transaction = StakeProgram.createAccount({
        fromPubkey: wallet.publicKey,
        stakePubkey: stakeAccount.publicKey,
        authorized: new Authorized(wallet.publicKey, wallet.publicKey),
        lamports: lamports ?? LAMPORTS_PER_SOL
    });
    try {
        const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
        transaction.feePayer = wallet.publicKey;
        transaction.recentBlockhash = blockhash;
        transaction.lastValidBlockHeight = lastValidBlockHeight;
        transaction.sign(wallet, stakeAccount);
        const signature = await connection.sendRawTransaction(transaction.serialize());
        const result = await confirmTransaction(connection, signature, 'finalized');
        if (result.value.err) {
            throw new Error(`Failed to confirm airdrop: ${result.value.err}`);
        }
        console.log("Stake Account created", signature);
    }
    catch (error) {
        console.error(error);
    }
    return;
}

让我们详细分析一下这里发生的事情:

  1. 首先,我们使用 StakeProgram 类的 createAccount 方法定义我们的交易。我们传入钱包的公钥,之前生成的质押账户的公钥,钱包的公钥作为授权质押者,以及我们希望质押的 SOL 数量(默认为 1 SOL)。注意:如果你之前没有使用过 StakeProgram 类,我们建议你浏览 文档 以了解可用的方法。
  2. 接着,我们获取网络的最新块哈希和最后有效块高度。然后我们将费用支付者、最近块哈希和最后有效块高度设置在我们的交易上。
  3. 我们使用钱包和质押账户密钥对进行签署、发送和确认交易。

现在我们有了一个资助的质押账户!让我们继续下一步,将质押账户指派给验证者。

第三步 - 指派质押账户

现在我们有了一个资助的质押账户,我们需要将其指派给一个验证者。使用以下代码更新 delegateStakeAccount 函数:

async function delegateStakeAccount({ stakeAccount, validatorVoteAccount, authorized }: { stakeAccount: Keypair, validatorVoteAccount: PublicKey, authorized: Keypair }) {
    const transaction = StakeProgram.delegate({
        stakePubkey: stakeAccount.publicKey,
        authorizedPubkey: authorized.publicKey,
        votePubkey: validatorVoteAccount
    });
    try {
        const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash();
        transaction.feePayer = authorized.publicKey;
        transaction.recentBlockhash = blockhash;
        transaction.lastValidBlockHeight = lastValidBlockHeight;
        transaction.sign(authorized);
        const signature = await connection.sendRawTransaction(transaction.serialize());
        const result = await confirmTransaction(connection, signature, 'finalized');
        if (result.value.err) {
            throw new Error(`Failed to confirm airdrop: ${result.value.err}`);
        }
        console.log("Stake Account delegated to vote account", signature);
    }
    catch (error) {
        console.error(error);
    }
    return;
}

与上一步一样,我们利用 StakeProgram 类来创建交易。这次我们调用 delegate 方法,传入质押账户的公钥、授权质押者的公钥和验证者投票账户的公钥。然后我们使用授权质押者的密钥对进行签署、发送和确认交易。

我们现在应该有一个资助且已指派的质押账户!让我们再添加一个函数以验证质押账户是否正在激活。

第四步 - 验证质押账户是否正在激活

我们可以通过在 Connection 类上调用 getStakeAccountInfo 来验证质押账户是否正在激活。使用以下代码更新 getStakeAccountInfo 函数:

async function getStakeAccountInfo(stakeAccount: PublicKey) {
    try {
        const info = await connection.getAccountInfo(stakeAccount);
        console.log(`Stake account exists.`);
    } catch (error) {
        console.error(error);
    }
    return;
}

我们只是传入质押账户的公钥并记录质押账户的状态。现在我们可以调用该函数以验证质押账户是否正在激活。

运行脚本

现在我们已经定义了所有函数,让我们测试一下。

首先,确保我们的本地集群正在运行。如果你在 CLI 质押练习后关闭了它,或者没有完成 CLI 质押练习,可以通过运行以下命令重新启动它:

solana-test-validator

在运行脚本之前,我们必须找到验证者的投票账户公钥。我们可以通过运行以下命令来完成:

solana validators -ul

-ul 标志将确保我们查看本地集群。复制投票账户的公钥:

Vote Account

这是我们本地验证者的投票账户。让我们更新之前定义的 validatorVoteAccount 变量:

const validatorVoteAccount = new PublicKey("YOUR_VALIDATOR_VOTE_ACCOUNT");

在你的第二个终端中,运行以下命令以执行脚本:

ts-node app.ts

你应该会看到以下输出:

Stake Account Activating

恭喜!你已经成功创建、资助、指派并激活了使用 Solana Web3.js 库的质押账户。

方法 4 - 液体质押

液体质押是一种允许用户在保持流动性的情况下质押 SOL 的概念。用户可以质押他们的 SOL 以换取数量众多的液体质押代币(例如,mSOL、jitoSOL 等)。这允许用户在其他应用程序中使用 SOL 的同时获得质押奖励。要深入了解液体质押,请查看我们的 指南

总结

质押 SOL 是帮助保护 Solana 网络并获得奖励的关键方式。你现在拥有质押你自己的 SOL 或将质押集成到你的 Solana dApps 中的工具。干得好!

TwitterDiscord 上向我们展示你正在构建的内容。我们很想看看你在做什么!

我们 ❤️ 意见反馈!

让我们知道 你是否有任何反馈或新的主题请求。我们很想听到你的声音。

资源

  • 原文链接: quicknode.com/guides/sol...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
QuickNode
QuickNode
江湖只有他的大名,没有他的介绍。