Pares de Chaves e Carteiras

Como gerar um novo Par de Chaves (Keypair)

Muitas das diferentes ações que você pode executar com as diversas bibliotecas da Solana requerem um Par de Chaves ou Carteira. Se você estiver conectando-se a uma carteira, não precisa se preocupar. No entanto, se precisar de um par de chaves, precisará gerar um.

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

Como restaurar um Par de Chaves a partir de uma senha

Se você já tem sua senha, pode obter seu Par de Chaves a partir da senha para testar seu dApp.

  1. A partir de 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 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. A partir de uma String 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)
}

Como verificar um Par de Chaves

Se você receber um Par de Chaves, pode verificar se a senha corresponde à chave pública fornecida.

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://

Como verificar se uma chave pública tem uma chave privada associada

Em certos casos especiais (por exemplo, em um endereço derivado do programa), as chaves públicas podem não ter uma chave privada associada a elas. Você pode verificar isso conferindo se a chave pública está na curva ed25519. Somente chaves públicas que estão na curva podem ser controladas por usuários com carteiras.

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
}

Como gerar uma frase mnemônica

Se você estiver criando uma carteira, precisará gerar uma frase mnemônica para que o usuário possa salvá-la como backup.

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

Como restaurar um Par de Chaves a partir de uma frase mnemônica

Muitas extensões de carteira usam mnemônicos para representar suas chaves secretas. Você pode converter o mnemônico em Pares de Chaves para testes locais.

  1. BIP39 - criando uma única carteira
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 (múltiplas carteiras, também conhecidas como carteiras HD)

Você pode criar várias carteiras a partir de uma única semente - também conhecidas como "carteiras determinísticas hierárquicas" ou carteiras 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'

Como gerar um endereço personalizado

As chaves públicas personalizadas, ou endereços personalizados (vanity addresses), são chaves que começam com caracteres específicos. Por exemplo, uma pessoa pode querer uma chave pública que comece com "elv1s", ou talvez até "cook". Isso pode ajudar outras pessoas a lembrar a quem a chave pertence, tornando a chave mais facilmente identificável.

Observação: quanto mais caracteres tiver o endereço personalizado, mais tempo levará.

Aviso

Você deve usar apenas a CLI para essa tarefa. Os exemplos em Python e TypeScript são apenas para fins ilustrativos e são muito mais lentos do que a 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

Como assinar e verificar mensagens com carteiras

A função principal de um par de chaves é assinar mensagens e permitir a verificação da assinatura. A verificação de uma assinatura permite que o destinatário tenha certeza de que os dados foram assinados pelo proprietário de uma chave privada específica.

Para fazer isso, importaremos a biblioteca criptográfica 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

Como se conectar a uma carteira

As bibliotecas wallet-adapteropen in new window da Solana facilitam a gestão de conexões de carteira no lado do cliente.

React

Execute o seguinte comando para instalar as dependências necessárias:

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

As bibliotecas wallet-adapter do React nos permitem persistir e acessar estados de conexão de carteira por meio de ganchos (hooks) e provedores de contexto, nomeadamente useWallet, WalletProvider, useConnection e ConnectionProvider. O aplicativo React deve ser envolvido com WalletProvider e ConnectionProvider.

Além disso, podemos solicitar que os usuários se conectem usando useWalletModal para alternar a visibilidade do modal de conexão e envolvendo o aplicativo com WalletModalProvider de @solana/wallet-adapter-react-ui. O modal de conexão lidará com o fluxo de conexão para nós, então só precisamos ouvir quando uma carteira estiver conectada. Sabemos que uma carteira está conectada quando a resposta useWallet tem uma propriedade wallet não nula. Vice-versa, se essa propriedade for nula, sabemos que a carteira está desconectada.

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

Execute o seguinte comando para instalar as dependências necessárias:

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

O plugin de integração Solana Wallets - Vueopen in new window nos permite inicializar uma loja de carteiras e criar uma nova propriedade global $wallet que pode ser acessada dentro de qualquer componente. Todas as propriedades e métodos que podem ser obtidos a partir de useWallet() são exibidos aquiopen in new window. Também importamos e renderizamos o componente WalletMultiButton para permitir que os usuários selecionem uma carteira e se conectem a ela.

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

Execute o seguinte comando para instalar as dependências necessárias:

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

O pacote Svelte Wallet Adapteropen in new window permite adicionar uma Loja Svelte ($walletStore) acessível em todos os arquivos JS, TS ou Svelte dentro de um projeto feito com Svelte Template ou SvelteKit. Usando a referência do repositório aquiopen in new window, você pode usar o adaptador para SSR ou SPA. O pacote da interface do usuário contém um componente <WalletMultiButton /> para permitir que os usuários selecionem uma carteira para se conectar a ela.

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: Daniel Cukier