Paires de Clés (Keypair) et Portefeuilles

Comment générer une nouvelle Paire de Clés

La plupart des actions que vous pouvez effectuer avec les diverses bibliothèques de Solana nécessitent une Paire de Clés ou un Portefeuille. Si vous vous connectez à un portefeuille, vous n'avez pas à vous inquiéter. Cependant, si vous avez besoin d'une paire de clés, vous devrez en générer une.

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

Comment restaurer une Paire de clés à partir d'une clé privée

Si vous disposez déjà de votre clé privée, vous pouvez générer une Paire de Clés à partir de celle-ci pour tester votre dApp.

  1. À partir des 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. À partir de la chaîne de caractères 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)
}

Comment vérifier une Paire de Clés

Si on vous donne une paire de clés, vous pouvez vérifier si, oui ou non, la clé privée correspond à la clé publique donnée

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

Comment vérifier si une clé publique a une clé privée associée

Dans certains cas particuliers (par exemple, une Adresse Dérivée d'un Programme), les clés publiques peuvent ne pas être associées à une clé privée. Vous pouvez le vérifier en regardant si la clé publique se trouve sur la courbe ed25519. Seules les clés publiques qui se trouvent sur la courbe peuvent être contrôlées par les utilisateurs possédant un portefeuille.

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
}

Comment générer une phrase mnémonique

Si vous créez un portefeuille, vous devrez générer une phrase mnémonique afin que l'utilisateur puisse l'enregistrer comme sauvegarde de secours.

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

Comment restaurer une paire de clés à partir d'une phrase mnémonique

De nombreuses extensions de portefeuilles utilisent des mnémoniques pour représenter leurs clés privées. Vous pouvez convertir le mnémonique en Paires de Clés pour des tests locaux.

  1. BIP39 - création d'un portefeuille unique
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 (portefeuilles multiples, également appelés HD wallets)

Vous pouvez créer plusieurs portefeuilles à partir d'une seule seed, également appelés "Portefeuilles Déterministes Hiérarchiques" ou portefeuilles 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'

Comment générer une adresse personnalisée

Les adresses personnalisées (vanity publickeys) sont des clés qui commencent par des caractères spécifiques. Par exemple, une personne peut vouloir que sa clé publique commence par "elv1s", ou peut-être même "cook". Elles peuvent aider les autres personnes à se rappeler à qui appartient la clé, ce qui la rend plus facilement identifiable.

Remarque: Plus il y a de caractères spécifiques dans votre adresse personnalisée, plus la procédure sera longue.

WARNING

Vous devez utiliser le CLI pour cette tâche. Les exemples Python et TypeScript sont donnés à titre d'illustration et sont beaucoup plus lents que le 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

Comment signer et vérifier des messages avec les portefeuilles

La fonction première d'une paire de clés est de signer des messages et de permettre la vérification de la signature. La vérification d'une signature permet au destinataire d'être sûr que les données ont été signées par le propriétaire d'une clé privée spécifique.

Pour ce faire, nous allons importer la bibliothèque cryptographique 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

Comment se connecter à un portefeuille

Les bibliothèques wallet-adapteropen in new window de Solana permettent de gérer facilement les connexions de portefeuilles côté client.

React

Exécutez la commande suivante pour installer les dépendances requises :

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

Les bibliothèques wallet-adapter de React nous permettent de conserver et d'accéder aux états de connexion du portefeuille par le biais de hooks et de fournisseurs de Contexte, à savoir, useWallet, WalletProvider, useConnection, et ConnectionProvider. L'Application React doit être encapsulée avec WalletProvider et ConnectionProvider.

De plus, nous pouvons inviter les utilisateurs à se connecter en utilisant useWalletModal pour activer la visibilité de la modale de connexion et en enveloppant l'Application avec WalletModalProvider de @solana/wallet-adapter-react-ui. La modale de connexion gérera ce flux de connexion pour nous, de sorte que nous pouvons simplement surveiller la connexion d'un portefeuille. Nous savons qu'un portefeuille est connecté lorsque la réponse useWallet a une propriété wallet non nulle. Inversement, si cette propriété est nulle, nous savons que le portefeuille est déconnecté.

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

Exécutez la commande suivante pour installer les dépendances requises :

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

Le plugin Solana Wallets Vueopen in new window nous permet d'initialiser une liste de portefeuilles et de créer une nouvelle propriété globale $wallet à laquelle on peut accéder depuis n'importe quel composant. Toutes les propriétés et méthodes que vous pouvez obtenir grâce à useWallet() sont affichées iciopen in new window. Nous importons et rendons également le composant WalletMultiButton pour permettre aux utilisateurs de sélectionner un portefeuille et de s'y connecter.

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

Exécutez la commande suivante pour installer les dépendances requises :

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

Le package Svelte Wallet Adapteropen in new window package permet d'ajouter un Store Svelte ($walletStore) accessible parmi tous les fichiers JS, TS et/ou Svelte à l'intérieur d'un projet réalisé avec Svelte Template ou SvelteKit. En utilisant le répertoire de référence iciopen in new window vous pouvez utiliser l'adaptateur pour SSR ou SPA. Le package UI contient un composant <WalletMultiButton /> pour permettre aux utilisateurs de sélectionner un portefeuille et de s'y connecter.

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: