Cặp khoá và Ví

Làm thế nào để sinh Cặp khoá

Có rất nhiều chức năng trong các thư viện Solana để tương tác được bạn sẽ phải cần có Cặp khoá hoặc Ví. Nếu bạn đang kết nối với một ví, bạn sẽ không phải lo lắng chuyện đó nữa. Tuy nhiên, nếu bạn đang cần một Cặp khoá, bạn sẽ phải sinh ra chúng.

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

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

keypair = Keypair()
use solana_sdk::signature::{Keypair};

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

# pubkey: 9ZNTfG4NyQgxy2SWjSiQoUyBPEvXT2xo7fKc5hPYYJ7b

Làm thế nào để phục hồi một Cặp khoá từ khoá riêng tư

Nếu bạn đã có khoá riêng tư, bạn có thể phục hồi lại cặp khoá từ khoá riêng tư đó và dùng nố để kết nối với dApp của bạn.

  1. Từ Bytes
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 solana.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_secret_key(bytes(secret_key))
print("Created Keypair with Public Key: {}".format(keypair.public_key))
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. Từ chuỗi 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"
    )
  );
})();
import base58
from solana.keypair import Keypair

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

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

Làm thế nào để kiểm tra một cặp khoá

Nếu bạn được cho một cặp khoá, bạn có thể xác nhận rằng cặp khoá đó có khớp giữa khoá riêng tư và khoá công khai hay không.

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 solana.keypair import Keypair
from solana.publickey import PublicKey

public_key = PublicKey("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_secret_key(bytes(keys))

print(keypair.public_key.to_base58() == public_key.to_base58())
# True
solana-keygen verify <PUBKEY> prompt://

Làm thế nào để kiểm tra nếu một khoá công khai không tồn tại khoá riêng tư tương Ứng

Trong một vài trường hợp đặc biệt (ví dụ như PDA), khoá công khai sẽ không hề tồn tại khoá riêng tư tương ứng với nó. Bạn có thể kiểm tra được điều này bằng cách thử xem khoá công khai có nằm trên đường cong ed25519 hay không. Chỉ những khoá công khai nằm trên đường cong mới có khoá riêng tư, hay nói cách khác là được kiểm soát bởi một ví người dùng.

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 solana.keypair import Keypair
from solana.publickey import PublicKey
from solana.utils.ed25519_base import is_on_curve

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

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

error_pubkey = PublicKey("testPubkey"); # Is not a valid public key
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
}

Làm thế nào để sinh ra cụm mnemonic

Nếu bạn đang tạo ví, bạn sẽ cần sinh ra một cụm mnemonic để người dùng có thể lưu và phục hồi lại ví trong trường hợp cần.

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

Làm thế nào để phục hồi lại cặp khoá từ cụm mnemonic

Có rất nhiều ví sử dụng cụm mnemonics để biểu diễn khoá riêng tư. Bạn có thể chuyển đổi giữa mnemonic và cặp khoá để kiểm thử dưới môi trường địa phương.

  1. BIP39 - tạo một ví đơn
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 solana.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_secret_key(seed)
print("Created Keypair with Public Key: {}".format(keypair.public_key)
solana-keygen recover
  1. BIP44 - nhiều ví, thường được biết đến với tên gọi ví HD (Hierarchical Deterministic - Phân quyền Tất định)

Bạn có thể tạo nhiều ví từ một seed đơn và được gọi là ví HD:

Press </> button to view full source
import { Keypair } from "@solana/web3.js";
import { derivePath } from "ed25519-hd-key";
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)
  for (let i = 0; i < 10; i++) {
    const path = `m/44'/501'/${i}'/0'`;
    const keypair = Keypair.fromSeed(
      derivePath(path, seed.toString("hex")).key
    );
    console.log(`${path} => ${keypair.publicKey.toBase58()}`);
  }
})();
solana-keygen recover 'prompt:?key=0/0'

Làm thế nào để sinh một địa chỉ danh nghĩa

Địa chỉ danh nghĩa, hay địa chỉ tuỳ chỉnh là những địa chỉ với các tiền tố là những ký tự cụ thể. Ví dụ, một người muốn một khoá công khai sao cho nó bắt đầu với cụm từ "elv1s", hoặc "cook". Những đại chỉ nào giúp người khác có thể biết được chủ sở hữu của khoá và thuận tiện cho việc nhận dạng hơn.

Lưu ý: Càng nhiều ký tự tiền tố trong đại chỉ danh nghĩa, sẽ càng yêu cầu nhiều thời gian tính toán hơn.

WARNING

Bạn nên sử dụng CLI cho nhiệm vụ này. Ví dụ trên Python và TypeScript chỉ nhằm mục đích minh hoạ và có hiệu suất chậm hơn rất nhiều so với 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 solana.keypair import Keypair

keypair = Keypair()
while(str(keypair.public_key)[:5]!="elv1s") :
    keypair = Keypair()
    
print("Created Keypair with Public Key: {}".format(keypair.public_key))
solana-keygen grind --starts-with e1v1s:1

Làm thế nào ký và kiểm tra tinh nhắn bằng ví

Một chức năng cơ bản của một cặp khoá là ký một tin nhắn và cho phép kiểm tra chữ ký cùng tin nhắn đó. Wuas trình xác nhận một chữ ký cho phép người nhận chắc chắn rằng dữ liệu được ký là do chủ sở hữu thực sự của cặp khoá ký lên.

Để làm được điều đó chúng ta cần sử dụng thư viện mật mã học 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 nacl.signing import VerifyKey
from solana.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_secret_key(bytes(secret_key))
pubkey_bytes = bytes(keypair.public_key)
message = "The quick brown fox jumps over the lazy dog"
message_bytes = bytes(message,'utf8')
signed_message = keypair.sign(message_bytes)

verify_sign = VerifyKey(
    pubkey_bytes
).verify(
    smessage=message_bytes,  
    signature=signed_message.signature
)

#Returns original message if the signature has not been tampered with
print(verify_sign)

Làm thế nào để kết nối ví

Thư viện wallet-adapteropen in new window của Solana sẽ giúp cho việc quản lý và kết nối ví trở nên hết sức đơn giản.

React

Chạy đoạn mã bên dưới để cài đặt các thử viện cần thiết:

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

Thư viện React wallet-adapter cho phép lập trình viên duy trì kết nối cũng như truy cập vào các trạng thái của ví thông qua HookContext Provider như useWallet, WalletProvider, useConnection, và ConnectionProvider. Ứng dụng React phải được bọc bởi WalletProviderConnectionProvider.

Ngoài ra, lập trình viên cũng có thể hiển thị kết nối đến người dùng bằng cách sử dụng useWalletModal để mở một cửa sổ thông báo. Lưu ý, bạn cần phải bọc toàn bộ ứng dụng bằng WalletModalProvider từ thư viện @solana/wallet-adapter-react-ui. Cửa sổ kết nối sẽ xử lý tất cả các bước kết nối nên chúng ta chỉ cần lắng nghe sự kiện kết nối ví thành công. useWallet sẽ trả về giá trị khác rỗng là wallet nếu kết nối thành công. Ngược lại, nó sẽ trả về rỗng nếu kết nối chưa thành công hoặc người dùng đã ngắt kết nối.

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

Chạy đoạn mã sau đây để cài các thư viện cần thiết:

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

Plugin Solana Wallets Vueopen in new window cho phép chúng ta khởi tạo một vùng nhớ cho ví và tạo một thuộc tính $wallet mới với phạm vi toàn cục. Thuộc tính này có thể được truy cập ở bất kỳ một thành phần nào. Tất cả các thuộc tính và phương thức bạn có thể lấy từ useWallet() đều được trình bày ở đâyopen in new window. Chúng ta cũng cần cài và hiển thị thành phần WalletMultiButton để cho phép người dùng có thể chọn ví cũng như kết nối ví.

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

Chạy đoạn mã sau đây để cài các thư viện cần thiết:

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

Gói Svelte Wallet Adapteropen in new window cho phép thêm một Svelte Store ($walletStore) có khả năng truy xuất từ các tập tin JS, TS or/and Svelte bên trong dự án được tạo từ Svelte Template hoặc SvelteKit. Sử dụng mã nguồn tham khảo tại đâyopen in new window bạn có thể sử dụng bộ tiếp hợp cho SSR và cả SPA. Gói giao diện người dùng có chứa một thành phần là <WalletMultiButton />, nó cho phép người dùng có thể chọn và tạo kết nối đến ví.

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: