Keypairs and Wallets

新しいキーペアの生成方法

さまざまな Solana ライブラリで実行できるさまざまなアクションの多くには、キーペアまたはウォレットが必要です。 ウォレットに接続している場合は、心配する必要はありません。ただし、鍵ペアが必要な場合は生成する必要があります。

Press </> button to view full source
import { Keypair } from "@solana/web3.js";

(async () => {
  let keypair = Keypair.generate();
})();
from solders.keypair import Keypair

keypair = Keypair()
// clang++ generate_keypair.cpp -o generate_keypair -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  auto key_pair = Keypair::generate();

  auto public_key = key_pair.public_key;
  std::cout << "public_key = " << public_key.to_base58() << std::endl;

  return 0;
}
use solana_sdk::signature::{Keypair};

fn main() {
    let wallet = Keypair::new();
}
$ solana-keygen new

# pubkey: 9ZNTfG4NyQgxy2SWjSiQoUyBPEvXT2xo7fKc5hPYYJ7b

シークレットからキーペアを復元する方法

シークレットが既にある場合は、シークレットからキーペアを取得して dApp をテストできます。

  1. バイトから
Press </> button to view full source
import { Keypair } from "@solana/web3.js";

(async () => {
  const keypair = Keypair.fromSecretKey(
    Uint8Array.from([
      174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56,
      222, 53, 138, 189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246,
      15, 185, 186, 82, 177, 240, 148, 69, 241, 227, 167, 80, 141, 89, 240, 121,
      121, 35, 172, 247, 68, 251, 226, 218, 48, 63, 176, 109, 168, 89, 238, 135,
    ])
  );
})();
from solders.keypair import Keypair

secret_key= [
        174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138,
        189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240,
        148, 69, 241, 227, 167, 80, 141, 89, 240, 121, 121, 35, 172, 247, 68, 251, 226, 218, 48,
        63, 176, 109, 168, 89, 238, 135,
    ]
    
keypair = Keypair.from_bytes(secret_key)
print("Created Keypair with Public Key: {}".format(keypair.pubkey()))
// clang++ keypair_from_seed.cpp -o keypair_from_seed -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  const uint8_t bytes[] = {
    174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138,
    189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240,
    148, 69, 241, 227, 167, 80, 141, 89, 240, 121, 121, 35, 172, 247, 68, 251, 226, 218, 48,
    63, 176, 109, 168, 89, 238, 135,
  };
  Keypair key_pair = Keypair::from_seed(bytes);
  std::cout << "Created Keypair with Public Key: " << key_pair.public_key.to_base58() << std::endl;
}
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let secret_key: [u8; 64] = [
        174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138,
        189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240,
        148, 69, 241, 227, 167, 80, 141, 89, 240, 121, 121, 35, 172, 247, 68, 251, 226, 218, 48,
        63, 176, 109, 168, 89, 238, 135,
    ];

    if let Ok(wallet) = Keypair::from_bytes(&secret_key) {
        let pubkey = Signer::pubkey(&wallet);
        println!("Created keypair: {}", pubkey)
    }
}
# input your secret into the Keypath listed under solana config get
  1. Base58文字列から
Press </> button to view full source
import { Keypair } from "@solana/web3.js";
import * as bs58 from "bs58";

(async () => {
  const keypair = Keypair.fromSecretKey(
    bs58.decode(
      "5MaiiCavjCmn9Hs1o3eznqDEhRwxo7pXiAYez7keQUviUkauRiTMD8DrESdrNjN8zd9mTmVhRvBJeg5vhyvgrAhG"
    )
  );
})();
from solders.keypair import Keypair

b58_string = "5MaiiCavjCmn9Hs1o3eznqDEhRwxo7pXiAYez7keQUviUkauRiTMD8DrESdrNjN8zd9mTmVhRvBJeg5vhyvgrAhG"
keypair = Keypair.from_string(b58_string)
print("Created Keypair with Public Key: {}".format(keypair.pubkey()))
use solana_sdk::signature::{Keypair, Signer};

fn main() {
    let wallet = Keypair::from_base58_string(
        "5MaiiCavjCmn9Hs1o3eznqDEhRwxo7pXiAYez7keQUviUkauRiTMD8DrESdrNjN8zd9mTmVhRvBJeg5vhyvgrAhG",
    );
    let pubkey = Signer::pubkey(&wallet);
    println!("Created keypair: {}", pubkey)
}

キーペアを確認する方法

キーペアが与えられた場合、秘密が与えられた公開鍵と一致するかどうかを確認できます。

Press </> button to view full source
import { Keypair, PublicKey } from "@solana/web3.js";

(async () => {
  const publicKey = new PublicKey(
    "24PNhTaNtomHhoy3fTRaMhAFCRj4uHqhZEEoWrKDbR5p"
  );
  const keypair = Keypair.fromSecretKey(
    Uint8Array.from([
      174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56,
      222, 53, 138, 189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246,
      15, 185, 186, 82, 177, 240, 148, 69, 241, 227, 167, 80, 141, 89, 240, 121,
      121, 35, 172, 247, 68, 251, 226, 218, 48, 63, 176, 109, 168, 89, 238, 135,
    ])
  );
  console.log(keypair.publicKey.toBase58() === publicKey.toBase58());
  // true
})();
from solders.keypair import Keypair
from solders.pubkey import Pubkey

public_key = Pubkey.from_string("24PNhTaNtomHhoy3fTRaMhAFCRj4uHqhZEEoWrKDbR5p")

keys = [
        174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138,
        189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240,
        148, 69, 241, 227, 167, 80, 141, 89, 240, 121, 121, 35, 172, 247, 68, 251, 226, 218, 48,
        63, 176, 109, 168, 89, 238, 135,
    ]
keypair = Keypair.from_bytes(keys)

print(keypair.pubkey() == public_key)
# True
// clang++ verify_keypair.cpp -o verify_keypair -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  PublicKey public_key = PublicKey("24PNhTaNtomHhoy3fTRaMhAFCRj4uHqhZEEoWrKDbR5p");

  const uint8_t bytes[] = {
    174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138,
    189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240,
    148, 69, 241, 227, 167, 80, 141, 89, 240, 121, 121, 35, 172, 247, 68, 251, 226, 218, 48,
    63, 176, 109, 168, 89, 238, 135,
  };
  Keypair key_pair = Keypair::from_seed(bytes);

  std::cout << (public_key.to_base58() == key_pair.public_key.to_base58()) << std::endl;
}
solana-keygen verify <PUBKEY> prompt://

公開鍵に秘密鍵が関連付けられているかどうかを確認する方法

プログラム派生アドレス(PDA)などの特定の特殊なケースでは、公開鍵に秘密鍵が関連付けられていない場合があります。これは、公開鍵がed25519曲線上にあるかどうかを調べることで確認できます。ウォレットを持つユーザーが制御できるのは、曲線上にある公開鍵のみです。

Press </> button to view full source
import { PublicKey } from "@solana/web3.js";

(async function () {
  // Note that Keypair.generate() will always give a public key that is valid for users
  const key = new PublicKey("5oNDL3swdJJF1g9DzJiZ4ynHXgszjAEpUkxVYejchzrY"); // Valid public key
  console.log(PublicKey.isOnCurve(key.toBytes())); // Lies on the ed25519 curve and is suitable for users

  const offCurveAddress = new PublicKey(
    "4BJXYkfvg37zEmBbsacZjeQDpTNx91KppxFJxRqrz48e"
  ); // Valid public key
  console.log(PublicKey.isOnCurve(offCurveAddress.toBytes())); // Not on the ed25519 curve, therefore not suitable for users

  const errorPubkey = new PublicKey("testPubkey"); // Is not a valid public key
})();
from solders.pubkey import Pubkey

# Note that Keypair() will always give a public key that is valid for users
key = Pubkey.from_string('5oNDL3swdJJF1g9DzJiZ4ynHXgszjAEpUkxVYejchzrY') # Valid public key
print(key.is_on_curve()) # Lies on the ed25519 curve and is suitable for users

off_curve_address = Pubkey.from_string('4BJXYkfvg37zEmBbsacZjeQDpTNx91KppxFJxRqrz48e') # Valid public key
print(off_curve_address.is_on_curve()) # Not on the ed25519 curve, therefore not suitable for users

error_pubkey = Pubkey.from_string("testPubkey"); # Is not a valid public key
#include <iostream>
#include <solana_sdk.h>

int main()
{
    auto public_key = PublicKey("5oNDL3swdJJF1g9DzJiZ4ynHXgszjAEpUkxVYejchzrY");

    std::cout << public_key.is_on_curve() << std::endl;

    return 0;
}
use solana_sdk::pubkey::{Pubkey};
use std::str::FromStr;

fn main() {
    // Note that Keypair::new() will always give a public key that is valid for users
    let pubkey = Pubkey::from_str("5oNDL3swdJJF1g9DzJiZ4ynHXgszjAEpUkxVYejchzrY").unwrap(); // Valid public key
    println!("{:?}", pubkey.is_on_curve()); // Lies on the ed25519 curve and is suitable for users

    let off_curve_address = Pubkey::from_str("4BJXYkfvg37zEmBbsacZjeQDpTNx91KppxFJxRqrz48e").unwrap(); // Valid public key
    println!("{:?}", off_curve_address.is_on_curve()); // Not on the ed25519 curve, therefore not suitable for users

    let error_pubkey = Pubkey::from_str("testPubkey").unwrap(); // Is not a valid public key
}

ニーモニックフレーズの生成方法

ウォレットを作成する場合は、ユーザーがバックアップとして保存できるようにニーモニック フレーズを生成する必要があります。

Press </> button to view full source
import * as bip39 from "bip39";

const mnemonic = bip39.generateMnemonic();
from mnemonic import Mnemonic

mnemo = Mnemonic("english")
words = mnemo.generate(strength=256)
solana-keygen new

ニーモニックフレーズからキーペアを復元する方法

多くのウォレット拡張機能は、ニーモニックを使用して秘密鍵を表します。ローカルテスト用にニーモニックをキーペアに変換できます。

  1. BIP39 - 単一のウォレットの作成
Press </> button to view full source
import { Keypair } from "@solana/web3.js";
import * as bip39 from "bip39";

(async () => {
  const mnemonic =
    "pill tomorrow foster begin walnut borrow virtual kick shift mutual shoe scatter";
  const seed = bip39.mnemonicToSeedSync(mnemonic, ""); // (mnemonic, password)
  const keypair = Keypair.fromSeed(seed.slice(0, 32));
  console.log(`${keypair.publicKey.toBase58()}`); // 5ZWj7a1f8tWkjBESHKgrLmXshuXxqeY9SYcfbshpAqPG
})();
from solders.keypair import Keypair
from mnemonic import Mnemonic

mnemo = Mnemonic("english")
seed = mnemo.to_seed("pill tomorrow foster begin walnut borrow virtual kick shift mutual shoe scatter")
keypair = Keypair.from_bytes(seed)
print("Created Keypair with Public Key: {}".format(keypair.pubkey()))
solana-keygen recover
  1. BIP44 (複数のウォレット、別名 HDウォレット)

単一のシードから複数のウォレットを作成できます。これは、「階層的決定論的ウォレット」または HD ウォレットとも呼ばれます。:

Press </> button to view full source
import { Keypair } from "@solana/web3.js";
import { HDKey } from "micro-ed25519-hdkey";
import * as bip39 from "bip39";

(async () => {
  const mnemonic =
    "neither lonely flavor argue grass remind eye tag avocado spot unusual intact";
  const seed = bip39.mnemonicToSeedSync(mnemonic, ""); // (mnemonic, password)
  const hd = HDKey.fromMasterSeed(seed.toString("hex"));
  for (let i = 0; i < 10; i++) {
    const path = `m/44'/501'/${i}'/0'`;
    const keypair = Keypair.fromSeed(hd.derive(path).privateKey);
    console.log(`${path} => ${keypair.publicKey.toBase58()}`);
  }
})();
solana-keygen recover 'prompt:?key=0/0'

バニティアドレスの生成方法

バニティ公開鍵またはカスタム アドレスは、特定の文字で始まるキーです。たとえば、公開鍵を「elv1s」または「cook」で開始したい場合があります。これらは、他の人がキーの所有者を思い出すのに役立ち、キーをより簡単に識別できるようにします。

Note: バニティ アドレスの文字数が多いほど、時間がかかります。

WARNING

このタスクには CLI を使用する必要があります。 Python と TypeScript の例は説明を目的としており、CLI よりもはるかに遅くなります。

Press </> button to view full source
import { Keypair } from "@solana/web3.js";

(async () => {
  let keypair = Keypair.generate();
  while (!keypair.publicKey.toBase58().startsWith("elv1s")) {
    keypair = Keypair.generate();
  }
})();
from solders.keypair import Keypair

keypair = Keypair()
while(str(keypair.pubkey())[:5]!="elv1s") :
    keypair = Keypair()
    
print("Created Keypair with Public Key: {}".format(keypair.pubkey()))
// clang++ vanity_keypair.cpp -o vanity_keypair -std=c++17 -lssl -lcrypto -lsodium

#include "solana.hpp"

using namespace many::solana;

int main() {
  auto key_pair = Keypair::generate();

  while (key_pair.public_key.to_base58().substr(0, 5) != "elv1s") {
    key_pair = Keypair::generate();
  }

  std::cout << "Created Keypair with Public Key: " << key_pair.public_key.to_base58() << std::endl;
}
solana-keygen grind --starts-with e1v1s:1

ウォレットでメッセージに署名して検証する方法

鍵ペアの主な機能は、メッセージに署名し、署名の検証を可能にすることです。 署名の検証により、受信者は、データが特定の秘密鍵の所有者によって署名されたことを確認できます。

そのために、TweetNaClopen in new window暗号ライブラリをインポートします。

Press </> button to view full source
import { Keypair } from "@solana/web3.js";
import nacl from "tweetnacl";
import { decodeUTF8 } from "tweetnacl-util";

(async () => {
  const keypair = Keypair.fromSecretKey(
    Uint8Array.from([
      174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56,
      222, 53, 138, 189, 224, 216, 117, 173, 10, 149, 53, 45, 73, 251, 237, 246,
      15, 185, 186, 82, 177, 240, 148, 69, 241, 227, 167, 80, 141, 89, 240, 121,
      121, 35, 172, 247, 68, 251, 226, 218, 48, 63, 176, 109, 168, 89, 238, 135,
    ])
  );

  const message = "The quick brown fox jumps over the lazy dog";
  const messageBytes = decodeUTF8(message);

  const signature = nacl.sign.detached(messageBytes, keypair.secretKey);
  const result = nacl.sign.detached.verify(
    messageBytes,
    signature,
    keypair.publicKey.toBytes()
  );

  console.log(result);
})();
from solders.keypair import Keypair

secret_key =  [
      174, 47, 154, 16, 202, 193, 206, 113, 199, 190, 53, 133, 169, 175, 31, 56, 222, 53, 138, 189, 224, 216, 117,
      173, 10, 149, 53, 45, 73, 251, 237, 246, 15, 185, 186, 82, 177, 240, 148, 69, 241, 227, 167, 80, 141, 89, 240,
      121, 121, 35, 172, 247, 68, 251, 226, 218, 48, 63, 176, 109, 168, 89, 238, 135,
    ] 
keypair = Keypair.from_bytes(secret_key)
message = b"The quick brown fox jumps over the lazy dog"
signature = keypair.sign_message(message)
verify_sign = signature.verify(keypair.pubkey(), message)

print(verify_sign) # bool

ウォレットへの接続方法

Solanaのwallet-adapteropen in new windowライブラリを使用すると、クライアント側でウォレット接続を簡単に管理できます。

React

次のコマンドを実行して、必要な依存関係をインストールします:

yarn add @solana/wallet-adapter-react @solana/wallet-adapter-react-ui @solana/wallet-adapter-base @solana/wallet-adapter-wallets

React wallet-adapterライブラリでは、フックと Context プロバイダ、すなわちuseWallet, WalletProvider, useConnection, ConnectionProviderを通じてウォレットの接続状態を持続させたりアクセスしたりすることができます。Reactアプリは、WalletProviderConnectionProviderでラップする必要があります。

加えて、@solana/wallet-adapter-react-uiWalletModalProviderでアプリをラップし、 useWalletModalを使用して接続モーダルの可視性を切り替えることで、使用してユーザーに接続を促すことができます。接続モーダルはその接続フローを処理するので、ウォレットがいつ接続されたかをリッスンできます。useWallet応答にnull 以外のwalletプロパティがある場合、ウォレットが接続されていることがわかります。逆に、そのプロパティが null の場合、ウォレットが切断されていることがわかります。

Press </> button to view full source
import React, { useMemo, FC, PropsWithChildren } from "react";
import {
  ConnectionProvider,
  WalletProvider,
} from "@solana/wallet-adapter-react";
import { WalletModalProvider } from "@solana/wallet-adapter-react-ui";
import { WalletAdapterNetwork } from "@solana/wallet-adapter-base";
import {
  LedgerWalletAdapter,
  PhantomWalletAdapter,
  SlopeWalletAdapter,
  TorusWalletAdapter,
} from "@solana/wallet-adapter-wallets";
import { clusterApiUrl } from "@solana/web3.js";
import { useWallet } from "@solana/wallet-adapter-react";
import { useWalletModal } from "@solana/wallet-adapter-react-ui";
import { MouseEventHandler } from "react";

export const Web3Provider: FC<PropsWithChildren<{}>> = ({ children }) => {
  // Can be set to 'devnet', 'testnet', or 'mainnet-beta'
  const endpoint = useMemo(
    () => clusterApiUrl(WalletAdapterNetwork.Devnet),
    []
  );

  // @solana/wallet-adapter-wallets includes all the adapters but supports tree shaking --
  // Only the wallets you configure here will be compiled into your application
  const wallets = useMemo(
    () => [
      new PhantomWalletAdapter(),
      new SlopeWalletAdapter(),
      new TorusWalletAdapter(),
      new LedgerWalletAdapter(),
    ],
    []
  );

  return (
    <ConnectionProvider endpoint={endpoint}>
      <WalletModalProvider>
        <WalletProvider wallets={wallets}>{children}</WalletProvider>
      </WalletModalProvider>
    </ConnectionProvider>
  );
};

/**
 * Make sure to wrap the App with
 * ConnectionProvider, WalletProvider, and WalletModalProvider.
 *
 * If you have a lot of Providers already, you can combine them
 * into a single wrapper (i.e. Web3Provider) instead.
 */
export const App = () => {
  return (
    <Web3Provider>
      <AppChild />
    </Web3Provider>
  );
};

const AppChild = () => {
  const { wallet } = useWallet();
  const { setVisible } = useWalletModal();

  // Display the connection modal
  const onRequestConnectWallet = () => {
    setVisible(true);
  };

  // Prompt user to connect wallet
  if (!wallet) {
    return <button onClick={onRequestConnectWallet}>Connect Wallet</button>;
  }

  return (
    <main>
      <p>Wallet successfully connected!</p>
      <p>{wallet.publicKey.toString()}</p>
    </main>
  );
};

Vue

次のコマンドを実行して、必要な依存関係をインストールします:

npm install solana-wallets-vue @solana/wallet-adapter-wallets

Solana Wallets Vueopen in new window プラグインを使用すると、ウォレットストアを初期化し、任意のコンポーネント内でアクセスできる新しい$walletグローバル プロパティを作成できます。useWallet() から使用可能なすべてのプロパティとメソッドはこちらopen in new windowに表記されています。また、WalletMultiButton コンポーネントをインポートしてレンダリングし、ユーザーがウォレットを選択して接続できるようにします。

Press </> button to view full source
<script setup>
import { WalletMultiButton } from "solana-wallets-vue";
import {
  LedgerWalletAdapter,
  PhantomWalletAdapter,
  SlopeWalletAdapter,
  TorusWalletAdapter,
} from "@solana/wallet-adapter-wallets";
import { initWallet, useWallet } from "solana-wallets-vue";

const wallets = {
  wallets: [
    new PhantomWalletAdapter(),
    new SlopeWalletAdapter(),
    new TorusWalletAdapter(),
    new LedgerWalletAdapter(),
  ],
};
initWallet(wallets);

const { connected, wallet } = useWallet();
</script>

<template>
  <div>
    <p v-if="connected">
      Wallet with public key {{ wallet.publicKey }} successfully connected!
    </p>
    <div v-else>
      <wallet-multi-button></wallet-multi-button>
    </div>
  </div>
</template>

Svelte

次のコマンドを実行して、必要な依存関係をインストールします:

npm install @svelte-on-solana/wallet-adapter-core @svelte-on-solana/wallet-adapter-ui @solana/wallet-adapter-base @solana/wallet-adapter-wallets @solana/web3.js

Svelte Wallet Adapteropen in new windowパッケージを使うことにより、Svelte TemplateまたはSvelteKitで作成されたプロジェクト内のすべてのJS、TS、Svelte ファイル間でアクセス可能な Svelteストア($walletStore) を追加できます。こちらopen in new windowのリポジトリを参照の上、SSR または SPA 用のアダプターを使用できます。UI パッケージには、ユーザーがウォレットを選択して接続できるようにする <WalletMultiButton /> コンポーネントが含まれています。

Press </> button to view full source
<script>
  import { walletStore } from "@svelte-on-solana/wallet-adapter-core";
  import {
    WalletProvider,
    WalletMultiButton,
    ConnectionProvider,
  } from "@svelte-on-solana/wallet-adapter-ui";
  import { clusterApiUrl } from "@solana/web3.js";
  import {
    PhantomWalletAdapter,
    SolflareWalletAdapter,
    TorusWalletAdapter,
    LedgerWalletAdapter,
  } from "@solana/wallet-adapter-wallets";

  const localStorageKey = "walletAdapter";
  const network = clusterApiUrl("devnet"); // localhost or mainnet

  let wallets = [
    new PhantomWalletAdapter(),
    new SolflareWalletAdapter(),
    new TorusWalletAdapter(),
    new LedgerWalletAdapter(),
  ];
</script>

<WalletProvider {localStorageKey} {wallets} autoConnect />
<ConnectionProvider {network} />

{#if $walletStore?.connected} Wallet with public key {$walletStore.publicKey}
successfully connected! {:else}
<WalletMultiButton />
{/if}
Last Updated:
Contributors: PokoPoko2ry