> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 部署您的第一个 Solana 程序

> 将 Solana 程序从源码转变为实时 devnet 交易，所有资金、部署和调用均通过您的 Helius RPC 路由。

export const DevnetFaucet = () => {
  const [apiKey, setApiKey] = useState('');
  const [address, setAddress] = useState('');
  const [loading, setLoading] = useState(false);
  const [result, setResult] = useState(null);
  const [error, setError] = useState(null);
  const handleAirdrop = async e => {
    e.preventDefault();
    setLoading(true);
    setError(null);
    setResult(null);
    try {
      const res = await fetch(`https://devnet.helius-rpc.com/?api-key=${apiKey}`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 'faucet',
          method: 'requestAirdrop',
          params: [address, 1000000000]
        })
      });
      const json = await res.json();
      if (json.error) throw new Error(json.error.message || 'Airdrop failed');
      setResult(json.result);
    } catch (err) {
      setError(err.message || 'Airdrop failed. The devnet faucet is rate-limited, try again shortly.');
    } finally {
      setLoading(false);
    }
  };
  const btnClass = loading ? 'px-4 py-2 font-medium rounded-full bg-gray-300 dark:bg-gray-700 cursor-not-allowed' : 'px-4 py-2 font-medium rounded-full bg-primary hover:bg-primary/80 text-white';
  return <div className="p-4 border dark:border-zinc-950/80 rounded-xl bg-white dark:bg-zinc-950/80 shadow-sm">
      <form onSubmit={handleAirdrop} className="space-y-4">
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">Your API Key</label>
          <input type="text" value={apiKey} onChange={e => setApiKey(e.target.value)} placeholder="Enter your API key" className="w-full p-2 border rounded dark:bg-zinc-900 dark:border-zinc-700" required />
        </div>
        <div>
          <label className="block text-sm text-zinc-950/70 dark:text-white/70 mb-1">Devnet Wallet Address</label>
          <input type="text" value={address} onChange={e => setAddress(e.target.value)} placeholder="Your devnet address" className="w-full p-2 border rounded dark:bg-zinc-900 dark:border-zinc-700" required />
        </div>
        <button type="submit" disabled={loading} className={btnClass}>
          {loading ? 'Requesting...' : 'Request 1 Devnet SOL'}
        </button>
      </form>
      <p className="mt-3 text-xs text-zinc-500 dark:text-zinc-400">
        Your API key is used only in your browser to call Helius directly. It is never sent anywhere else.
      </p>
      {error ? <div className="mt-4 p-3 bg-red-100 dark:bg-red-900/30 border border-red-200 dark:border-red-800 rounded text-red-700 dark:text-red-300">
          <strong>Error:</strong> {error}
        </div> : null}
      {result ? <div className="mt-4 p-3 bg-green-100 dark:bg-green-900/30 border border-green-200 dark:border-green-800 rounded text-green-700 dark:text-green-300 text-sm break-all">
          <strong>Airdrop sent!</strong> Signature: {result}
        </div> : null}
    </div>;
};

在本指南中，您将部署一个真实的程序到 devnet 并调用它，整个流程在 Helius 基础设施上运行。您将使用 [`requestAirdrop`](/zh/api-reference/rpc/http/requestairdrop) 为钱包提供资金，部署一个预构建的示例程序，然后用 [`sendTransaction`](/zh/api-reference/rpc/http/sendtransaction) 调用并用 [`getSignatureStatuses`](/zh/api-reference/rpc/http/getsignaturestatuses) 确认结果。使用现成的程序使重点放在部署和调用循环上，而不是编写 Rust 代码。

<Info>
  **先决条件：** [Solana CLI](https://solana.com/docs/intro/installation) 和 [Rust](https://www.rust-lang.org/tools/install) （用于构建程序），Node.js 18+ （用于调用），以及一个 [Helius API 密钥](https://dashboard.helius.dev/api-keys)。Devnet 适用于所有 Helius 计划。
</Info>

***

<Steps>
  <Step title="将 Solana CLI 指向您的 Helius devnet RPC">
    使用您的 Helius 端点进行所有 CLI 命令，如果没有钱包，请创建一个：

    ```bash theme={"system"}
    solana config set --url https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY
    solana-keygen new --no-bip39-passphrase   # skip if you already have a keypair
    solana address
    ```

    `solana address` 打印钱包的公钥，接下来您将为其提供资金。
  </Step>

  <Step title="获取 devnet SOL">
    部署需要一些 SOL。Devnet SOL 是免费的，只用于测试，因此请用下面的水龙头或从 CLI 为您的地址提供资金：

    ```bash theme={"system"}
    solana airdrop 1
    solana balance
    ```

    <DevnetFaucet />

    <Note>
      Devnet 水龙头有速率限制，因此空投可能失败。如果失败，请稍等片刻重试，或使用 Solana 的官方 [devnet 网页水龙头](https://faucet.solana.com/) 作为后备。部署示例程序仅需要约 1 SOL。
    </Note>
  </Step>

  <Step title="克隆并构建示例程序">
    从 Solana 官方 [program-examples](https://github.com/solana-developers/program-examples) 仓库获取"Hello, Solana!"程序。它只是调用时记录一个问候语，这是证明完整循环有效的最小程序。

    ```bash theme={"system"}
    git clone https://github.com/solana-developers/program-examples.git
    cd program-examples
    cargo build-sbf --manifest-path basics/hello-solana/native/program/Cargo.toml
    ```

    `program-examples` 是一个 Cargo 工作空间，因此 `cargo build-sbf` 将程序编译到仓库根目录（而不是在程序文件夹内）。在 `program-examples` 目录内进行下一步。
  </Step>

  <Step title="通过 Helius 部署到 devnet">
    ```bash theme={"system"}
    solana program deploy target/deploy/hello_solana_program.so
    ```

    CLI 通过您的 Helius RPC 提交部署交易并打印 **Program Id**。复制它，因为您将调用此程序。

    ```
    Program Id: 4Nd1mYQ...your program id...
    ```
  </Step>

  <Step title="使用 sendTransaction 调用程序">
    在新文件夹中，设置一个小型 TypeScript 客户端，构建一个交易，发送并确认它。

    ```bash theme={"system"}
    mkdir invoke-client && cd invoke-client
    npm init -y
    npm install @solana/web3.js
    ```

    ```typescript invoke.ts [expandable] theme={"system"}
    import {
      Connection,
      Keypair,
      PublicKey,
      Transaction,
      TransactionInstruction,
    } from "@solana/web3.js";
    import { readFileSync } from "fs";
    import { homedir } from "os";

    const RPC = "https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY";
    const PROGRAM_ID = new PublicKey("YOUR_PROGRAM_ID"); // from the deploy step

    async function main() {
      const connection = new Connection(RPC, "confirmed");

      // Load the same keypair the CLI created and funded.
      const secret = JSON.parse(
        readFileSync(`${homedir()}/.config/solana/id.json`, "utf8")
      );
      const payer = Keypair.fromSecretKey(Uint8Array.from(secret));

      // The hello-solana program takes no accounts and no data. It just logs.
      const instruction = new TransactionInstruction({
        keys: [],
        programId: PROGRAM_ID,
        data: Buffer.alloc(0),
      });

      const tx = new Transaction().add(instruction);
      const { blockhash } = await connection.getLatestBlockhash();
      tx.recentBlockhash = blockhash;
      tx.feePayer = payer.publicKey;
      tx.sign(payer);

      // sendTransaction submits the signed transaction to the cluster via Helius.
      const signature = await connection.sendRawTransaction(tx.serialize());
      console.log("Sent:", signature);

      // Poll getSignatureStatuses until the transaction is confirmed.
      for (let i = 0; i < 30; i++) {
        const { value } = await connection.getSignatureStatuses([signature]);
        const status = value[0];
        if (status?.confirmationStatus === "confirmed" || status?.confirmationStatus === "finalized") {
          if (status.err) throw new Error(`Failed: ${JSON.stringify(status.err)}`);
          console.log("Confirmed! View it on Solana Explorer:");
          console.log(`https://explorer.solana.com/tx/${signature}?cluster=devnet`);
          return;
        }
        await new Promise((r) => setTimeout(r, 1000));
      }
      throw new Error("Timed out waiting for confirmation");
    }

    main().catch(console.error);
    ```

    替换 `YOUR_API_KEY` 和 `YOUR_PROGRAM_ID`，然后运行它：

    ```bash theme={"system"}
    npx tsx invoke.ts
    ```

    您将获得一个签名和一个 Explorer 链接。打开链接并展开 **Program Instruction Logs** 以查看程序的 `Hello, Solana!` 问候语。
  </Step>
</Steps>

## 发生了什么

### 一切都通过您的 Helius RPC 路由

`solana config set --url` 指向每个 CLI 命令（空投、部署和平衡检查）到您的 Helius devnet 端点。TypeScript 客户端使用相同的端点，因此整个流程在 Helius 基础设施上运行。

### 调用循环：发送，然后确认

`sendRawTransaction` 在内部调用 [`sendTransaction`](/zh/api-reference/rpc/http/sendtransaction) RPC 方法并立即返回签名，在网络处理交易之前。这就是为什么您会轮询 [`getSignatureStatuses`](/zh/api-reference/rpc/http/getsignaturestatuses) 直到 `confirmationStatus` 达到 `confirmed`，检查 `err` 以捕获失败。这个发送后确认的模式是您提交的每个 Solana 交易的基础。

## 下一步

<CardGroup cols={2}>
  <Card title="如何获取 Devnet SOL" icon="faucet-drip" href="/zh/rpc/devnet-sol">
    提供开发钱包资金的所有方式，以及速率限制提示。
  </Card>

  <Card title="sendTransaction" icon="paper-plane" href="/zh/api-reference/rpc/http/sendtransaction">
    所有参数，包括 skipPreflight、preflightCommitment 和重试。
  </Card>

  <Card title="可靠地登陆交易" icon="rocket" href="/zh/api-reference/sender/sendtransaction">
    当您进入主网时，使用 Sender 实现超低延迟的登陆。
  </Card>

  <Card title="构建一个投资组合追踪器" icon="wallet" href="/zh/quickstart/portfolio-tracker">
    其他路径：提取任何钱包的代币、NFT 和 SOL，配有实时活动提要。
  </Card>
</CardGroup>
