> ## 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.

# 入金

> SOL、SPL、またはToken 2022の資産をプライベートバランスに入金するためのガイド。完全なコード例付き。

1. 入金はユーザーの公開Solanaバランスから自分または他人のプライベートバランスにトークンを移動します。
2. 入金は単一のSolanaトランザクションでSolanaウォレットアドレスに送信されます。

#### 入金: プライベートとは何か

| Field                      | Visibility | Why                                                |
| -------------------------- | ---------- | -------------------------------------------------- |
| Source public wallet       | Public     | The source wallet address is visible onchain       |
| Asset                      | Public     | The asset is visible onchain                       |
| Amount                     | Public     | The deposited amount is visible onchain            |
| Destination wallet address | Public     | The destination wallet address is visible onchain  |
| Resulting private balance  | Private    | The resulting private balance is encrypted onchain |

<Info>
  無許可リングは、金額と資産が暗号化されていて機密性があります。
  カスタムリングは機密性または匿名性（送信者、受信者、資産、金額が暗号化された状態）として構成できます。
</Info>

## 入金の仕組み

入金は、プライベートバランスの結果を伴う公開Solana転送です。

1. ユーザーのSOLまたはSPLバランスはオンチェーンで公開されています。
2. ウォレットは金額と受取人を設定し、入金を構築し、所有者が署名します。入金はZK証明を要求しません。
3. Solanaランタイムは署名を検証し、Solanaプライバシープログラムを呼び出します。
4. アプリはSolanaトランザクションハッシュを介してステータスを追跡します。

```mermaid theme={"system"}
%%{init: {
  'theme': 'base',
  'themeVariables': {
    'lineColor':           '#FF6B35',
    'primaryTextColor':    '#737373',
    'primaryBorderColor':  '#9CA3AF',
    'actorBkg':            '#FFFFFF',
    'actorBorder':         '#9CA3AF',
    'actorTextColor':      '#737373',
    'signalColor':         '#FF6B35',
    'signalTextColor':     '#737373',
    'labelBoxBkgColor':    '#FF6B351F',
    'labelBoxBorderColor': '#FF6B35',
    'noteBkgColor':        '#F5F5F5',
    'noteTextColor':       '#737373',
    'noteBorderColor':     '#9CA3AF'
  }
}}%%
sequenceDiagram
    participant Wallet
    participant RPC as RPC Provider
    participant Solana

    Wallet->>RPC: Get public balance
    RPC-->>Wallet: Public state
    Note over Wallet: Set amount and recipient
    Note over Wallet: Build deposit, sign
    Wallet->>RPC: Submit Transaction
    RPC->>Solana: Forward transaction
    Note over Solana: Verify signatures
    Note over Solana: CPI Solana Privacy Program
    RPC-->>Wallet: Transaction signature
```

<Accordion title="Solana Transferとの比較">
  1. ユーザーのSOLまたはSPLバランスはオンチェーンで公開されています。
  2. ウォレットは公開状態を読み取り、転送を構築し、所有者が署名します。
  3. Solanaランタイムは署名を検証し、システムプログラムまたはトークンプログラムを呼び出し、公開バランスを更新します。
  4. アプリはSolanaトランザクションハッシュを介してステータスを追跡します。

  ```mermaid theme={"system"}
  %%{init: {
    'theme': 'base',
    'themeVariables': {
      'lineColor':           '#FF6B35',
      'primaryTextColor':    '#737373',
      'primaryBorderColor':  '#9CA3AF',
      'actorBkg':            '#FFFFFF',
      'actorBorder':         '#9CA3AF',
      'actorTextColor':      '#737373',
      'signalColor':         '#FF6B35',
      'signalTextColor':     '#737373',
      'labelBoxBkgColor':    '#FF6B351F',
      'labelBoxBorderColor': '#FF6B35',
      'noteBkgColor':        '#F5F5F5',
      'noteTextColor':       '#737373',
      'noteBorderColor':     '#9CA3AF'
    }
  }}%%
  sequenceDiagram
      participant Wallet
      participant RPC
      participant Solana

      Wallet->>RPC: Get public balance
      RPC-->>Wallet: Public state
      Note over Wallet: Build transfer, owner signs
      Wallet->>RPC: sendTransaction
      RPC->>Solana: Forward transaction
      Note over Solana: Verify signatures
      Note over Solana: CPI System / Token Program
      Note over Solana: Update balance
      RPC-->>Wallet: Transaction signature
  ```
</Accordion>

<Info>
  これは、無許可の機密リングの高レベルトランザクションフローです。
  カスタムリングとの比較は[concepts](/docs/ja/privacy/concepts#高レベルのトランザクションフロー)をご覧ください。
</Info>

# はじめに

<Tabs>
  <Tab title="TypeScript Client">
    <Steps>
      <Step>
        ### 前提条件

        <Info>
          The TypeScript examples require Node.js 24 or later, pnpm 11.18.0, and the Solana CLI.
        </Info>

        ```bash theme={"system"}
        pnpm add @heliuslabs/zolana @solana/kit
        ```

        Source: [sdk-libs/ts](https://github.com/helius-labs/zolana/tree/main/sdk-libs/ts)

        <Accordion title="Connect to Endpoints">
          <Tabs>
            <Tab title="Devnet">
              ```bash theme={"system"}
              pnpm install
              cp .env.example .env
              ```

              Add a [Helius API key](https://dashboard.helius.dev/):

              ```bash .env theme={"system"}
              API_KEY=YOUR_API_KEY
              ZOLANA_PAYER_KEYPAIR=~/.config/solana/id.json
              ```

              ```ts theme={"system"}
              import { createZolanaClient } from "@heliuslabs/zolana";

              const client = await createZolanaClient({
                solanaRpcUrl: "https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY",
                indexerUrl: "http://zolnet-devnet-1779374825.eu-north-1.elb.amazonaws.com",
                proverUrl: "http://zolnet-devnet-1779374825.eu-north-1.elb.amazonaws.com:3001",
                allowInsecureHttp: true,
              });
              ```

              The examples use the Solana CLI wallet as the payer by default. The payer must hold devnet SOL. See [How to Get Devnet SOL](/docs/rpc/devnet-sol).
            </Tab>

            <Tab title="Localnet">
              On localnet the SDK starts the local test validator (`:8899`), Photon indexer (`:8784`), and prover (`:3001`), and the
              client connects to them automatically without needing endpoint configuration.

              ```bash theme={"system"}
              cargo install --git https://github.com/helius-labs/zolana --tag v0.1.0-alpha zolana-cli
              zolana dev start
              ```

              ```ts theme={"system"}
              import { createZolanaClient } from "@heliuslabs/zolana";

              const client = await createZolanaClient({});
              ```
            </Tab>
          </Tabs>
        </Accordion>
      </Step>

      <Step>
        ### プライベートバランスへの入金

        <Accordion title="ソラナキット送信ヘルパー">
          ```typescript theme={"system"}
          import {
            appendTransactionMessageInstructions,
            assertIsTransactionWithBlockhashLifetime,
            createTransactionMessage,
            getSignatureFromTransaction,
            pipe,
            sendTransactionWithoutConfirmingFactory,
            setTransactionMessageFeePayerSigner,
            setTransactionMessageLifetimeUsingBlockhash,
            signTransactionMessageWithSigners,
            type Instruction,
            type Signature,
            type TransactionSigner,
          } from "@solana/kit";
          import { createZolanaClient } from "@heliuslabs/zolana";

          type Client = Awaited<ReturnType<typeof createZolanaClient>>;

          export interface ConfirmedTransaction {
            readonly signature: Signature;
            readonly slot: bigint;
          }

          export function sendAndConfirmFactory(
            client: Client,
            feePayer: TransactionSigner,
          ): (instructions: readonly Instruction[]) => Promise<ConfirmedTransaction> {
            const sendTransaction = sendTransactionWithoutConfirmingFactory({
              rpc: client.solanaRpc,
            });

            return async function sendAndConfirm(
              instructions: readonly Instruction[],
            ): Promise<ConfirmedTransaction> {
              const { value: lifetime } = await client.solanaRpc
                .getLatestBlockhash()
                .send();
              const signed = await signTransactionMessageWithSigners(
                pipe(
                  createTransactionMessage({ version: 0 }),
                  (message) => setTransactionMessageFeePayerSigner(feePayer, message),
                  (message) =>
                    setTransactionMessageLifetimeUsingBlockhash(lifetime, message),
                  (message) =>
                    appendTransactionMessageInstructions(instructions, message),
                ),
              );
              assertIsTransactionWithBlockhashLifetime(signed);
              await sendTransaction(signed, { commitment: "confirmed" });
              const signature = getSignatureFromTransaction(signed);
              const slot = await client.confirmTransaction(signature);
              return { signature, slot };
            };
          }
          ```

          * SDKは命令を返します。アプリはそれを署名して送信します。
          * `sendAndConfirmFactory`はキットトランザクションを構築し、送信し、署名と到達したスロットを返します。
        </Accordion>

        <Tabs>
          <Tab title="SOL">
            ```typescript theme={"system"}
            import {
              depositInstruction,
              DepositAsset,
            } from "@heliuslabs/zolana/interface";
            import { randomBlinding } from "@heliuslabs/zolana/keypair";
            import { sendAndConfirmFactory } from "../src/lib.js";


              const sendAndConfirm = sendAndConfirmFactory(
                client,
                senderSigner,
              );
              const senderViewTag =
                senderAddress.confidentialViewTag();
              const depositIx = await depositInstruction({
                tree: client.tree,
                depositor: senderSigner,
                deposits: [
                  {
                    asset: DepositAsset.sol(),
                    viewTag: senderViewTag,
                    recipientOwnerHash:
                      senderAddress.ownerHash(),
                    blinding: randomBlinding(),
                    amount: DEPOSIT_AMOUNT,
                  },
                ],
              });

              const depositTx = await sendAndConfirm([
                depositIx,
              ]);
            ```
          </Tab>

          <Tab title="SPL">
            ```typescript theme={"system"}
            import {
              depositInstruction,
              DepositAsset,
            } from "@heliuslabs/zolana/interface";
            import { randomBlinding } from "@heliuslabs/zolana/keypair";
            import { sendAndConfirmFactory } from "../src/lib.js";


              const sendAndConfirm = sendAndConfirmFactory(
                client,
                senderSigner,
              );
              const senderViewTag =
                senderAddress.confidentialViewTag();
              const depositIx = await depositInstruction({
                tree: client.tree,
                depositor: senderSigner,
                deposits: [
                  {
                    asset: DepositAsset.spl({
                      mint: spl.mint,
                      sourceTokenAccount: spl.sourceTokenAccount,
                      tokenProgram: spl.tokenProgram,
                    }),
                    viewTag: senderViewTag,
                    recipientOwnerHash:
                      senderAddress.ownerHash(),
                    blinding: randomBlinding(),
                    amount: DEPOSIT_AMOUNT,
                  },
                ],
              });

              const depositTx = await sendAndConfirm([
                depositIx,
              ]);
            ```
          </Tab>
        </Tabs>

        <AccordionGroup>
          <Accordion title="1. 公開トークンを送信者のプライベートバランスに移動">
            ```typescript theme={"system"}
            import {
              depositInstruction,
              DepositAsset,
            } from "@heliuslabs/zolana/interface";
            import { randomBlinding } from "@heliuslabs/zolana/keypair";

            const senderViewTag =
              senderAddress.confidentialViewTag();
            const depositIx = await depositInstruction({
              tree: client.tree,
              depositor: senderSigner,
              deposits: [
                {
                  asset: DepositAsset.sol(),
                  viewTag: senderViewTag,
                  recipientOwnerHash:
                    senderAddress.ownerHash(),
                  blinding: randomBlinding(),
                  amount: DEPOSIT_AMOUNT,
                },
              ],
            });
            ```

            * `senderAddress`は受取人の<Tooltip tip="ユーザーの登録記録に公開されている公開鍵バンドル（署名、ヌリファイア、ビューキー）。オンチェーンのアドレスではありません。">シールドアドレス</Tooltip>です。この例は送信者への入金です。受取人は送信者または第三者のウォレットとすることができます。
            * `senderViewTag`は`senderAddress.confidentialViewTag()`であり、機密リング内での送信者のSolana公開鍵です。インデクサーはそれを使用して一致する暗号化出力を返します。
            * `client.tree`は新しい出力コミットメントを受け取る状態マークルツリーです。
            * `depositor` / `senderSigner`はパブリックからプライベートへの入金に資金を提供し署名します。
            * `DepositAsset.sol()`はSOLを選択します。`DepositAsset.spl`はSPLおよびToken 2022資産のためにミント、ソーストークンアカウント、トークンプログラムを取ります。
            * `recipientOwnerHash`は`senderAddress.ownerHash()`です。受取人の署名およびヌリファイア公開鍵のハッシュは新しいプライベートトークンアカウントにコミットされた所有者フィールドです。
            * `randomBlinding()`はプライベートトークンアカウントコミットメントにランダム性を追加します。
            * `DEPOSIT_AMOUNT`はSOLの場合はラマポートまたはSPLおよびToken 2022資産のためのトークンの基本単位を使用します。
          </Accordion>

          <Accordion title="2. 任意のSolanaトランザクションとして送信">
            ```typescript theme={"system"}
            import { sendAndConfirmFactory } from "../src/lib.js";

            const depositTx = await sendAndConfirm([
              depositIx,
            ]);
            ```

            * `sendAndConfirm`はSolanaトランザクションとして`depositIx`を署名して送信します。
            * 確認によりインデクサーフェッチをゲートするために使用されたスロットが得られます。
          </Accordion>
        </AccordionGroup>
      </Step>
    </Steps>

    ### 完全なコード例

    例をクローンして実行:

    ```bash theme={"system"}
    git clone https://github.com/helius-labs/zolana-examples.git
    cd zolana-examples/typescript-client
    pnpm install
    pnpm example examples/deposit_transfer_withdraw.ts
    ```

    <Info>
      例はローカル/Devnet上の機密リングを使用しています。<a href="https://github.com/helius-labs/zolana-examples/blob/main/typescript-client/examples/deposit_transfer_withdraw.ts">こちら</a>。
    </Info>

    ```typescript deposit_transfer_withdraw.ts expandable theme={"system"}
    import {
      SOL_MINT,
      createZolanaClient,
    } from "@heliuslabs/zolana";
    import { atSlot } from "@heliuslabs/zolana/client";
    import {
      depositInstruction,
      transactInstruction,
      DepositAsset,
      TransactWithdrawal,
    } from "@heliuslabs/zolana/interface";
    import { randomBlinding } from "@heliuslabs/zolana/keypair";
    import {
      AssetRegistry,
      ConfidentialTransfer,
      ProofInputUtxo,
      decryptToBalances,
      WithdrawalTarget,
    } from "@heliuslabs/zolana/transaction";

    import {
      sendAndConfirmFactory,
      setup,
    } from "../src/lib.js";

    const DEPOSIT_AMOUNT = 1_000_000_000n;
    const TRANSFER_AMOUNT = 300_000_000n;
    const WITHDRAW_AMOUNT = 300_000_000n;

    async function main(): Promise<void> {
      const {
        sender: senderKeypair,
        recipient: recipientKeypair,
        clientConfig,
      } = await setup();

      // Connect to Helius devnet RPC plus the Photon indexer and prover.
      const client =
        await createZolanaClient(clientConfig);

      // Initialize the sender's private wallet and local authority
      // to decrypt transactions and sync balances.
      // The Solana signer and private wallet are derived from the same Ed25519 seed.
      const senderSigner =
        senderKeypair.toSolanaSigner();
      const senderAddress =
        senderKeypair.shieldedAddress();
      const recipient =
        recipientKeypair.shieldedAddress();

      // The SDK hands back instructions; the app owns signing and sending.
      const sendAndConfirm = sendAndConfirmFactory(
        client,
        senderSigner,
      );

      // Mints that are registered with Solana Rings for privacy.
      const assets = new AssetRegistry();

      // Deposit SOL into the sender's private balance.
      // A deposit from a public balance reveals
      // sender, recipient, asset and amount.
      // Alternatively, you can onramp fiat directly to a private balance.

      // 1. Move public SOL into the sender's private balance.
      // The view tag is the sender's Solana public key in confidential rings.
      // Used by the indexer to fetch the sender's UTXOs.
      const senderViewTag =
        senderAddress.confidentialViewTag();
      const depositIx = await depositInstruction({
        tree: client.tree,
        depositor: senderSigner,
        deposits: [
          {
            asset: DepositAsset.sol(),
            viewTag: senderViewTag,
            recipientOwnerHash:
              senderAddress.ownerHash(),
            blinding: randomBlinding(),
            amount: DEPOSIT_AMOUNT,
          },
        ],
      });

      // 2. Send and confirm like any Solana transaction; confirmation yields the landed slot.
      const depositTx = await sendAndConfirm([
        depositIx,
      ]);

      // 3. Fetch transaction outputs from the indexer, gated on the deposit's slot.
      // The indexer returns encrypted outputs by view tag.
      const depositResponse =
        await client.getShieldedTransactionsByTags(
          { tags: [senderViewTag] },
          atSlot(depositTx.slot),
        );

      // 4. The sender decrypts the transaction outputs locally to read the private balance.
      const balancesAfterDeposit =
        await decryptToBalances({
          keypair: senderKeypair,
          registry: assets,
          transactions: depositResponse.transactions,
        });
      const depositBalance =
        balancesAfterDeposit.balance(SOL_MINT);
      if (depositBalance.amount !== DEPOSIT_AMOUNT) {
        throw new Error(
          `expected deposit amount ${DEPOSIT_AMOUNT}, got ${depositBalance.amount}`,
        );
      }
      if (depositBalance.utxos.length !== 1) {
        throw new Error(
          `expected 1 deposit utxo, got ${depositBalance.utxos.length}`,
        );
      }

      // Confidential SOL transfer to the recipient's private balance.
      // A confidential transfer reveals only sender and recipient,
      // not the asset or amount.

      // 1. Select private token accounts (UTXOs) that make up the private balance for the transfer.
      const transferUtxo = depositBalance.utxos[0]!;

      // 2. Prepare the selected UTXOs as inputs for the zero-knowledge proof.
      const transferInput =
        ProofInputUtxo.fromKeypair(
          transferUtxo,
          senderKeypair,
        );

      // 3. Build and sign the confidential transfer.
      // Signing encrypts the asset and amount and produces the proof inputs for the ZK prover.
      const transfer = new ConfidentialTransfer(
        senderAddress,
        [transferInput],
        senderSigner.address,
      );
      transfer.send(
        recipient,
        SOL_MINT,
        TRANSFER_AMOUNT,
      );
      const transferProofInputs = transfer.sign(
        senderKeypair,
        assets,
      );

      // 4. Fetch the ZK proof to prove the sender can spend the balance without revealing asset and amount.
      const transferData = await client.proveTransact(
        transferProofInputs,
      );

      // 5. Build the instruction with the state Merkle tree and Solana accounts required for the transfer.
      // Private transfers move balances only between private token accounts, not public token accounts.
      const transferInstruction = transactInstruction(
        {
          payer: senderSigner,
          inputTree: client.tree,
          outputTree: client.tree,
          data: transferData,
        },
      );

      // 6. Send and confirm like any Solana transaction; confirmation yields the landed slot.
      const transferTx = await sendAndConfirm([
        transferInstruction,
      ]);

      // 7. Fetch the sender's UTXOs again, gated on the transfer's slot,
      // and read the remaining private balance.
      const transferResponse =
        await client.getShieldedTransactionsByTags(
          { tags: [senderViewTag] },
          atSlot(transferTx.slot),
        );
      const balancesAfterTransfer =
        await decryptToBalances({
          keypair: senderKeypair,
          registry: assets,
          transactions: transferResponse.transactions,
        });
      const transferBalance =
        balancesAfterTransfer.balance(SOL_MINT);
      if (
        transferBalance.amount !==
        DEPOSIT_AMOUNT - TRANSFER_AMOUNT
      ) {
        throw new Error(
          `expected remaining amount ${DEPOSIT_AMOUNT - TRANSFER_AMOUNT}, got ${transferBalance.amount}`,
        );
      }
      if (transferBalance.utxos.length !== 1) {
        throw new Error(
          `expected 1 transfer utxo, got ${transferBalance.utxos.length}`,
        );
      }

      // Withdraw SOL from the sender's private balance to their public balance.
      // A withdrawal reveals the sender, recipient, asset, and amount.

      // 1. Select private token accounts (UTXOs) that make up the private balance for the withdrawal.
      const withdrawalUtxo =
        transferBalance.utxos[0]!;

      // 2. Prepare the selected UTXOs as inputs for the zero-knowledge proof.
      const withdrawalInput =
        ProofInputUtxo.fromKeypair(
          withdrawalUtxo,
          senderKeypair,
        );

      // 3. Build and sign the private-to-public withdrawal.
      // Signing encrypts the asset and amount of the remaining private balance
      // and produces the proof inputs for the ZK prover.
      const withdrawal = new ConfidentialTransfer(
        senderAddress,
        [withdrawalInput],
        senderSigner.address,
      );
      withdrawal.withdraw(
        SOL_MINT,
        WITHDRAW_AMOUNT,
        WithdrawalTarget.sol({
          recipient: senderSigner.address,
        }),
      );
      const withdrawalProofInputs = withdrawal.sign(
        senderKeypair,
        assets,
      );

      // 4. Fetch the ZK proof to prove the sender can spend the balance.
      const withdrawalData =
        await client.proveTransact(
          withdrawalProofInputs,
        );

      // 5. Build the instruction with the state Merkle tree and Solana accounts required for the withdrawal.
      const withdrawalInstruction =
        transactInstruction({
          payer: senderSigner,
          inputTree: client.tree,
          outputTree: client.tree,
          withdrawal: TransactWithdrawal.sol({
            recipient: senderSigner.address,
          }),
          data: withdrawalData,
        });

      // 6. Send and confirm like any Solana transaction; confirmation yields the landed slot.
      const withdrawalTx = await sendAndConfirm([
        withdrawalInstruction,
      ]);

      // 7. Fetch the sender's UTXOs again, gated on the withdrawal's slot,
      // and read the remaining private balance.
      const withdrawalResponse =
        await client.getShieldedTransactionsByTags(
          { tags: [senderViewTag] },
          atSlot(withdrawalTx.slot),
        );
      const balancesAfterWithdrawal =
        await decryptToBalances({
          keypair: senderKeypair,
          registry: assets,
          transactions:
            withdrawalResponse.transactions,
        });
      const withdrawalBalance =
        balancesAfterWithdrawal.balance(SOL_MINT);
      if (
        withdrawalBalance.amount !==
        DEPOSIT_AMOUNT -
          TRANSFER_AMOUNT -
          WITHDRAW_AMOUNT
      ) {
        throw new Error(
          `expected remaining amount ${DEPOSIT_AMOUNT - TRANSFER_AMOUNT - WITHDRAW_AMOUNT}, got ${withdrawalBalance.amount}`,
        );
      }
      if (withdrawalBalance.utxos.length !== 1) {
        throw new Error(
          `expected 1 withdrawal utxo, got ${withdrawalBalance.utxos.length}`,
        );
      }

      // 8. Read remaining private balance and the public balance.
      const solanaBalance = await client.getBalance(
        senderSigner.address,
      );
      console.log(
        `withdraw private_balance=${withdrawalBalance.amount} ` +
          `solana_balance=${solanaBalance} tx=${withdrawalTx.signature}`,
      );
    }

    await main();
    ```
  </Tab>

  <Tab title="Rust Client">
    <Steps>
      <Step>
        ### 前提条件

        <Info>
          The Rust examples require the latest stable Rust toolchain and the Solana CLI v4.0.2. See the [Solana installation guide](https://solana.com/docs/intro/installation).
        </Info>

        ```toml Cargo.toml theme={"system"}
        [dependencies]
        zolana-client = { git = "https://github.com/helius-labs/zolana", tag = "v0.1.0-alpha", features = ["indexer-api", "solana-rpc"] }
        zolana-interface = { git = "https://github.com/helius-labs/zolana", tag = "v0.1.0-alpha", features = ["solana"] }
        zolana-keypair = { git = "https://github.com/helius-labs/zolana", tag = "v0.1.0-alpha" }
        zolana-transaction = { git = "https://github.com/helius-labs/zolana", tag = "v0.1.0-alpha" }
        ```

        Source: [sdk-libs/client](https://github.com/helius-labs/zolana/tree/v0.1.0-alpha/sdk-libs/client)

        <Accordion title="Connect to Endpoints">
          <Tabs>
            <Tab title="Devnet">
              Add a [Helius API key](https://dashboard.helius.dev/):

              ```bash .env theme={"system"}
              API_KEY=YOUR_API_KEY
              ZOLANA_PAYER_KEYPAIR=~/.config/solana/id.json
              ```

              ```rust theme={"system"}
              use solana_address::Address;
              use zolana_client::{SolanaRpc, ZolanaClient};
              use zolana_interface::DEFAULT_TREE_ADDRESS;

              let tree: Address = DEFAULT_TREE_ADDRESS.parse()?;
              let client = ZolanaClient::from_urls_allowing_insecure_http(
                  SolanaRpc::new("https://devnet.helius-rpc.com/?api-key=YOUR_API_KEY"),
                  "http://zolnet-devnet-1779374825.eu-north-1.elb.amazonaws.com",
                  "http://zolnet-devnet-1779374825.eu-north-1.elb.amazonaws.com:3001",
                  tree,
              );
              ```

              The examples use the Solana CLI wallet as the payer by default. The payer must hold devnet SOL. See [How to Get Devnet SOL](/docs/rpc/devnet-sol).
            </Tab>

            <Tab title="Localnet">
              ```bash theme={"system"}
              cargo install --git https://github.com/helius-labs/zolana --tag v0.1.0-alpha zolana-cli
              zolana dev start
              ```

              ```rust theme={"system"}
              use solana_address::Address;
              use zolana_client::{SolanaRpc, ZolanaClient};
              use zolana_interface::DEFAULT_TREE_ADDRESS;

              let tree: Address = DEFAULT_TREE_ADDRESS.parse()?;
              let client = ZolanaClient::from_urls(
                  SolanaRpc::new("http://127.0.0.1:8899"),
                  "http://127.0.0.1:8784",
                  "http://127.0.0.1:3001",
                  tree,
              )?;
              ```
            </Tab>
          </Tabs>
        </Accordion>
      </Step>

      <Step>
        ### プライベートバランスへの入金

        ```rust theme={"system"}
        use zolana_interface::instruction::{AssetDeposit, Deposit, DepositAsset};
        use zolana_keypair::random_blinding;


        let deposit_ix = Deposit {
            tree,
            depositor: sender_solana_keypair.pubkey(),
            deposits: vec![AssetDeposit {
                asset: DepositAsset::Sol,
                // SPL: asset: DepositAsset::Spl(zolana_interface::instruction::DepositSplAccounts {
                // SPL:     mint: spl.mint,
                // SPL:     user_token: spl.user_token_account,
                // SPL:     token_program: spl.token_program,
                // SPL: }),
                view_tag: sender_shielded_address.confidential_view_tag()?,
                owner: sender_shielded_address.owner_hash()?,
                blinding: random_blinding(),
                amount: DEPOSIT_AMOUNT,
                utxo_data: None,
                memo: None,
            }],
        }
        .instruction()?;
        ```

        <AccordionGroup>
          <Accordion title="1. 公開SOLを送信者のプライベートバランスに移動">
            ```rust theme={"system"}
            use zolana_interface::instruction::{AssetDeposit, Deposit, DepositAsset};
            use zolana_keypair::random_blinding;


                // 1. Move public SOL into the sender's private balance.
                    let deposit_ix = Deposit {
                        tree,
                        depositor: sender_solana_keypair.pubkey(),
                        deposits: vec![AssetDeposit {
                            asset: DepositAsset::Sol,
                            // SPL: asset: DepositAsset::Spl(zolana_interface::instruction::DepositSplAccounts {
                            // SPL:     mint: spl.mint,
                            // SPL:     user_token: spl.user_token_account,
                            // SPL:     token_program: spl.token_program,
                            // SPL: }),
                            view_tag: sender_shielded_address.confidential_view_tag()?,
                            owner: sender_shielded_address.owner_hash()?,
                            blinding: random_blinding(),
                            amount: DEPOSIT_AMOUNT,
                            utxo_data: None,
                            memo: None,
                        }],
                    }
                    .instruction()?;
            ```

            * `sender_shielded_address`は受取人の<Tooltip tip="ユーザーの登録記録に公開されている公開鍵バンドル（署名、ヌリファイア、ビューキー）。オンチェーンのアドレスではありません。">シールドアドレス</Tooltip>です。この例は送信者への入金です。受取人は送信者または第三者のウォレットとすることができます。
            * `view_tag`は`sender_shielded_address.confidential_view_tag()`であり、機密リング内での送信者のSolana公開鍵です。インデクサーはそれを使用して一致する暗号化出力を返します。
            * `tree`は新しい出力コミットメントを受け取る状態マークルツリーです。
            * `depositor` / `sender_solana_keypair`はパブリックからプライベートへの入金に資金を提供し署名します。
            * `DepositAsset::Sol`はSOLを選択します。`// SPL:`のコメントはミント、ソーストークンアカウント、およびToken 2022資産のトークンプログラムを示します。
            * `owner`は`sender_shielded_address.owner_hash()`です。受取人の署名およびヌリファイア公開鍵のハッシュは新しいプライベートトークンアカウントにコミットされた所有者フィールドです。
            * `random_blinding()`はプライベートトークンアカウントコミットメントにランダム性を追加します。
            * `DEPOSIT_AMOUNT`はSOLの場合はラマポートまたはSPLおよびToken 2022資産のためのトークンの基本単位を使用します。`utxo_data`および`memo`は`None`です。
          </Accordion>

          <Accordion title="2. 任意のSolanaトランザクションとして送信">
            ```rust theme={"system"}
            use zolana_client::Rpc;

            let signature = client.create_and_send_transaction(
                &[deposit_ix],
                sender_solana_keypair.pubkey(),
                &[&sender_solana_keypair],
            )?;
            let slot = landed_slot(&client, signature)?;
            ```

            * `create_and_send_transaction`はSolanaトランザクションとして`deposit_ix`を署名して送信します。
            * `landed_slot`はインデクサーフェッチをゲートするために使用された確認スロットを読み取ります。
            * `sender_solana_keypair`は料金を支払い、パブリックからプライベートへの入金を承認します。
          </Accordion>
        </AccordionGroup>
      </Step>
    </Steps>

    ## 完全なコード例

    例をクローンして実行:

    ```bash theme={"system"}
    git clone https://github.com/helius-labs/zolana-examples.git
    cd zolana-examples/rust-client
    cargo run -p rust-client-example --example deposit_transfer_withdraw
    ```

    <Info>
      例はローカル/Devnet上の機密リングを使用しています。[こちら](https://github.com/helius-labs/zolana-examples/blob/main/rust-client/examples/deposit_transfer_withdraw.rs)。
    </Info>

    ```rust deposit_transfer_withdraw.rs expandable theme={"system"}
    use anyhow::{anyhow, Result};
    use rust_client_example::{setup, SetupContext};
    use solana_signature::Signature;
    use solana_signer::Signer;
    use zolana_client::{IndexerRpcConfig, Rpc, SolanaRpc, ZolanaClient};
    use zolana_interface::instruction::{
        AssetDeposit, Deposit, DepositAsset, Transact, TransactInterfaceTransferAccounts,
        TransactSolTransferAccounts,
    };
    use zolana_keypair::random_blinding;
    use zolana_transaction::{
        decrypt_transactions,
        instructions::{
            transact::{ConfidentialTransfer, SettlementTarget},
            types::SppProofInputUtxo,
        },
        AssetRegistry, SOL_MINT,
    };

    const DEPOSIT_AMOUNT: u64 = 1_000_000_000;
    const TRANSFER_AMOUNT: u64 = 300_000_000;
    const WITHDRAW_AMOUNT: u64 = 300_000_000;

    fn main() -> Result<()> {
        let SetupContext {
            rpc_url,
            indexer_url,
            prover_url,
            tree,
            sender,
            recipient_address,
        } = setup()?;

        // Load the funded fee payer and devnet settings, then connect.
        // Photon and the prover are HTTP on this ALB, so the constructor permits that.
        let client = ZolanaClient::from_urls_allowing_insecure_http(
            SolanaRpc::new(rpc_url),
            &indexer_url,
            prover_url,
            tree,
        );

        // Mints that are registered with Solana Rings for privacy.
        let assets = AssetRegistry::default();
        // SPL: assets.insert(spl.asset_id, spl.mint)?;

        // Initialize the sender's private wallet and local authority
        // to decrypt transactions and sync balances.
        // The Solana signer and private wallet are derived from the same Ed25519 seed.
        let sender_solana_keypair = sender.to_solana_keypair()?;
        let sender_shielded_address = sender.shielded_address()?;

        // Deposit SOL into the sender's private balance.
        // A deposit from a public balance reveals
        // sender, recipient, asset and amount.
        // Alternatively, you can onramp fiat directly to a private balance.

        // 1. Move public SOL into the sender's private balance.
        let sender_balances_after_deposit = {
            let deposit_ix = Deposit {
                tree,
                depositor: sender_solana_keypair.pubkey(),
                deposits: vec![AssetDeposit {
                    asset: DepositAsset::Sol,
                    // SPL: asset: DepositAsset::Spl(zolana_interface::instruction::DepositSplAccounts {
                    // SPL:     mint: spl.mint,
                    // SPL:     user_token: spl.user_token_account,
                    // SPL:     token_program: spl.token_program,
                    // SPL: }),
                    view_tag: sender_shielded_address.confidential_view_tag()?,
                    owner: sender_shielded_address.owner_hash()?,
                    blinding: random_blinding(),
                    amount: DEPOSIT_AMOUNT,
                    utxo_data: None,
                    memo: None,
                }],
            }
            .instruction()?;

            // 2. Send and confirm like any Solana transaction; the landed slot gates
            // the indexer fetch below.
            let signature = client.create_and_send_transaction(
                &[deposit_ix],
                sender_solana_keypair.pubkey(),
                &[&sender_solana_keypair],
            )?;
            let slot = landed_slot(&client, signature)?;

            // 3. Fetch transaction outputs from the indexer, gated on the deposit's slot.
            // The indexer returns encrypted outputs by view tag, the sender's public key in Confidential Rings.
            let sender_tag = sender_shielded_address.confidential_view_tag()?;
            let response = client.get_shielded_transactions_by_tags(
                vec![sender_tag],
                None,
                Some(50),
                Some(IndexerRpcConfig::at_slot(slot)),
            )?;

            // 4. The sender decrypts the transaction outputs locally to update the private balance.
            let balances = decrypt_transactions(&sender, &response.transactions, &assets)
                .map_err(|e| anyhow!("decrypt sender transactions: {e:?}"))?;

            let sender_balance = balances
                .get_balance(SOL_MINT)
                // SPL: .get_balance(spl.mint)
                .expect("failed to fetch sender's utxo");
            assert_eq!(sender_balance.amount, DEPOSIT_AMOUNT);
            assert_eq!(sender_balance.utxos.len(), 1);

            balances
        };

        // Confidential SOL transfer to the recipient's private balance.
        // A confidential transfer reveals only sender and recipient,
        // not the asset or amount.
        let sender_balances_after_transfer = {
            // 1. Select UTXOs that make up the private balance for the transfer.
            let transfer_utxo = sender_balances_after_deposit
                .get_balance(SOL_MINT)
                // SPL: .get_balance(spl.mint)
                .and_then(|balance| balance.utxos.first())
                .expect("failed to fetch deposited utxo")
                .clone();

            // 2. Prepare the selected UTXOs as inputs for the zero-knowledge proof.
            let transfer_input_utxo = SppProofInputUtxo::new(transfer_utxo, &sender);

            // 3. Build and sign the confidential transfer.
            // Signing encrypts the asset and amount and produces the proof inputs for the ZK prover.
            let mut transfer = ConfidentialTransfer::new(
                sender_shielded_address,
                vec![transfer_input_utxo],
                sender_solana_keypair.pubkey(),
            );
            transfer.send(&recipient_address, SOL_MINT, TRANSFER_AMOUNT)?;
            // SPL: transfer.send(&recipient_address, spl.mint, TRANSFER_AMOUNT)?;
            let proof_inputs = transfer.sign(&sender, &assets)?;

            // 4. Fetch the zk proof to prove the sender can spend the balance without revealing asset and amount.
            let transfer_data = client.prove_transact(tree, proof_inputs, None)?;

            // 5. Construct the instruction.
            let transfer_ix = Transact {
                payer: sender_solana_keypair.pubkey(),
                input_tree: tree,
                output_tree: tree,
                owner_signers: Vec::new(),
                interface_transfer_accounts: Vec::new(),
                data: transfer_data,
            }
            .instruction();

            // 6. Send and confirm like any Solana transaction; confirmation yields the landed slot.
            let signature = client.create_and_send_transaction(
                &[transfer_ix],
                sender_solana_keypair.pubkey(),
                &[&sender_solana_keypair],
            )?;
            let slot = landed_slot(&client, signature)?;

            // 7. Sync the sender's wallet, gated on the transfer's slot, and read
            // the remaining private balance.
            let sender_tag = sender_shielded_address.confidential_view_tag()?;
            let response = client.get_shielded_transactions_by_tags(
                vec![sender_tag],
                None,
                Some(50),
                Some(IndexerRpcConfig::at_slot(slot)),
            )?;
            let sender_balances = decrypt_transactions(&sender, &response.transactions, &assets)
                .map_err(|e| anyhow!("decrypt sender transactions: {e:?}"))?;
            let sender_balance = sender_balances
                .get_balance(SOL_MINT)
                // SPL: .get_balance(spl.mint)
                .expect("failed to fetch sender's utxo");
            assert_eq!(sender_balance.amount, DEPOSIT_AMOUNT - TRANSFER_AMOUNT);
            assert_eq!(sender_balance.utxos.len(), 1);

            sender_balances
        };

        // Withdraw SOL back to the sender's public balance.
        // A withdrawal from a confidential balance reveals
        // sender, recipient, asset and amount.
        {
            // 1. Select UTXOs that make up the private balance for the withdrawal.
            let withdrawal_utxo = sender_balances_after_transfer
                .get_balance(SOL_MINT)
                // SPL: .get_balance(spl.mint)
                .and_then(|balance| balance.utxos.first())
                .expect("failed to fetch sender's utxo")
                .clone();

            // 2. Prepare the selected UTXOs as inputs for the zero-knowledge proof.
            let withdrawal_input_utxo = SppProofInputUtxo::new(withdrawal_utxo, &sender);

            // 3. Build and sign the confidential withdrawal.
            // Signing encrypts the private change and produces the ZK prover inputs.
            let mut withdrawal = ConfidentialTransfer::new(
                sender_shielded_address,
                vec![withdrawal_input_utxo],
                sender_solana_keypair.pubkey(),
            );
            withdrawal.withdraw(
                SOL_MINT,
                WITHDRAW_AMOUNT,
                SettlementTarget::Sol {
                    user_sol_account: sender_solana_keypair.pubkey(),
                },
            )?;
            // SPL: withdrawal.withdraw(
            // SPL:     spl.mint,
            // SPL:     WITHDRAW_AMOUNT,
            // SPL:     SettlementTarget::Spl {
            // SPL:         user_spl_token: spl.user_token_account,
            // SPL:         spl_token_interface: spl.vault,
            // SPL:     },
            // SPL: )?;
            let proof_inputs = withdrawal.sign(&sender, &assets)?;

            // 4. Fetch the ZK proof to prove the sender can spend the balance.
            let withdrawal_data = client.prove_transact(tree, proof_inputs, None)?;

            // 5. Combine the proof and withdrawal accounts in a single instruction.
            let withdraw_ix = Transact {
                payer: sender_solana_keypair.pubkey(),
                input_tree: tree,
                output_tree: tree,
                owner_signers: Vec::new(),
                interface_transfer_accounts: vec![TransactInterfaceTransferAccounts::Sol(
                    TransactSolTransferAccounts {
                        recipient: sender_solana_keypair.pubkey(),
                    },
                )],
                // SPL: interface_transfer_accounts: vec![
                // SPL:     TransactInterfaceTransferAccounts::SplWithdrawal(
                // SPL:         zolana_interface::instruction::TransactSplWithdrawalAccounts {
                // SPL:             mint: spl.mint,
                // SPL:             vault: spl.vault,
                // SPL:             user_token_account: spl.user_token_account,
                // SPL:             token_program: spl.token_program,
                // SPL:         },
                // SPL:     ),
                // SPL: ],
                data: withdrawal_data,
            }
            .instruction();

            // 6. Send and confirm like any Solana transaction.
            let signature = client.create_and_send_transaction(
                &[withdraw_ix],
                sender_solana_keypair.pubkey(),
                &[&sender_solana_keypair],
            )?;
            let slot = landed_slot(&client, signature)?;

            // 7. Sync the sender's wallet, gated on the withdrawal's slot, and read
            // the remaining private balance.
            let sender_tag = sender_shielded_address.confidential_view_tag()?;
            let response = client.get_shielded_transactions_by_tags(
                vec![sender_tag],
                None,
                Some(50),
                Some(IndexerRpcConfig::at_slot(slot)),
            )?;
            let sender_balances = decrypt_transactions(&sender, &response.transactions, &assets)
                .map_err(|e| anyhow!("decrypt sender transactions: {e:?}"))?;
            let sender_balance = sender_balances
                .get_balance(SOL_MINT)
                // SPL: .get_balance(spl.mint)
                .expect("failed to fetch sender's utxo");
            assert_eq!(
                sender_balance.amount,
                DEPOSIT_AMOUNT - TRANSFER_AMOUNT - WITHDRAW_AMOUNT
            );
            assert_eq!(sender_balance.utxos.len(), 1);

            // 8. Read remaining private balance and the public SOL balance.
            let solana_balance = client.get_balance(sender_solana_keypair.pubkey())?;
            println!("withdraw solana_balance={solana_balance} tx={signature}");
            // SPL: println!(
            // SPL:     "withdraw user_token={} tx={signature}",
            // SPL:     spl.user_token_account,
            // SPL: );
        }
        Ok(())
    }

    /// Slot the confirmed transaction landed in, which drives the indexer
    /// freshness gate on the fetches that read the transaction back.
    fn landed_slot(client: &ZolanaClient<SolanaRpc>, signature: Signature) -> Result<u64> {
        client
            .get_signature_statuses(vec![signature])?
            .first()
            .and_then(|status| status.as_ref())
            .map(|status| status.slot)
            .ok_or_else(|| anyhow!("transaction status missing after confirmation"))
    }
    ```
  </Tab>
</Tabs>

## 関連ガイド

<CardGroup cols={2}>
  <Card title="転送" icon="arrow-right-arrow-left" href="/docs/ja/privacy/guides/transfer" horizontal />

  <Card title="出金" icon="arrow-up-from-bracket" href="/docs/ja/privacy/guides/withdraw" horizontal />

  <Card title="プライベートバランスを読む" icon="wallet" href="/docs/ja/privacy/guides/read-balance" horizontal />

  <Card title="プライベート履歴を読む" icon="clock-rotate-left" href="/docs/ja/privacy/guides/read-history" horizontal />
</CardGroup>

## Didn't find what you were looking for?

<Callout type="info">
  Reach out! [Telegram](https://t.me/tilo_light) | [E-Mail](mailto:sales@helius.xyz) | [Contact](https://www.helius.dev/contact)
</Callout>
