Пакет @solana-commerce/connector предоставляет подключение кошелька без
графического интерфейса, построенное на основе
Wallet Standard. Он
управляет обнаружением кошельков, состоянием подключения, управлением аккаунтами
и автоматическим повторным подключением. Пакет разработан как независимый от
фреймворка с включёнными привязками для React. Он адаптирован для бесшовного
использования в Solana Commerce Kit и совместим с
@solana/kit и
gill.
Подключение кошелька
Установка
pnpm add @solana-commerce/connector
Настройка провайдера
ConnectorProvider
Компонент ConnectorProvider оборачивает ваше приложение и предоставляет
состояние подключения кошелька всем дочерним компонентам. Он управляет
единственным экземпляром ConnectorClient, который сохраняется в течение циклов
монтирования/размонтирования компонентов.
Свойства
Вся конфигурация передаётся через свойство config:
config(ConnectorConfig, необязательно) - Объект конфигурации для коннектора. Все поля необязательны.
ConnectorConfig
Объект конфигурации для поведения подключения кошелька.
Необязательные поля
-
autoConnect(boolean) - Если установлено значениеtrue, автоматически переподключается к последнему использованному кошельку при монтировании. Предпочтение кошелька сохраняется в настроенном хранилище (по умолчаниюlocalStorage). По умолчанию:false. -
debug(boolean) - Включает подробное логирование в консоль для отладки потоков подключения, изменений аккаунтов и ошибок. Логи включают префиксы, такие как[Connector]и[ConnectorProvider]. По умолчанию:false. -
accountPollingIntervalMs(number) - Интервал опроса в миллисекундах для проверки изменений аккаунта, когда кошелёк не поддерживает функциюstandard:events. Большинство современных кошельков поддерживают события, поэтому опрос является запасным вариантом. По умолчанию:1500(1,5 секунды). -
storage(Storage) - Пользовательский адаптер хранилища для сохранения предпочтений кошелька. Должен реализовывать:getItem(key: string): string | nullsetItem(key: string, value: string): voidremoveItem(key: string): void
По умолчанию:
window.localStorage, когда доступно (только браузер). Используйте это для React Native (AsyncStorage) или пользовательского SSR-безопасного хранилища.
Архитектура провайдера
Провайдер использует паттерн одиночки с подсчетом ссылок:
- Несколько экземпляров
ConnectorProviderиспользуют один и тот жеConnectorClient - Клиент создается при первом монтировании и сохраняется между размонтированиями
- Когда все провайдеры размонтируются, очистка откладывается на 5 секунд для обработки быстрых повторных монтирований
- Во время очистки кошелек отключается и все обработчики событий удаляются
Эта архитектура предотвращает отключение кошелька при смене маршрутов или обновлении компонентов.
Хуки
useConnector()
Основной хук для доступа к состоянию и действиям подключения кошелька. Должен
использоваться внутри ConnectorProvider.
Возвращает объект ConnectorSnapshot, содержащий:
Свойства состояния
-
wallets(WalletInfo[]) - Массив всех обнаруженных кошельков, совместимых со стандартом Wallet Standard. Автоматически обновляется при установке или удалении кошельков. Каждый кошелек включает метаданные, такие как название, иконка и возможности. См. WalletInfo. -
selectedWallet(Wallet | null) - Текущий подключенный объект кошелька Wallet Standard.nullпри отключении. Это необработанный экземпляр кошелька из API Wallet Standard. -
connected(boolean) - Статус подключения.true, когда кошелек подключен и аккаунты доступны. Используйте это для условного рендеринга UI. -
connecting(boolean) - Состояние загрузки во время подключения кошелька.trueмежду вызовомselect()и получением результата подключения. Используйте это для отображения индикаторов загрузки или деактивации кнопок. -
accounts(AccountInfo[]) - Массив аккаунтов из подключенного кошелька. Большинство кошельков предоставляют один аккаунт, но некоторые поддерживают несколько. Обновляется автоматически через события кошелька или опрос. См. AccountInfo. -
selectedAccount(string | null) - Адрес текущего выбранного аккаунта (публичный ключ в кодировке base58). Когда кошелек подключается с новым аккаунтом, этот аккаунт автоматически выбирается. В противном случае сохраняется ранее выбранный аккаунт.
Методы действий
-
select((walletName: string) => Promise<void>) - Подключается к кошельку по имени (например,"Phantom","Solflare"). Имя кошелька должно точно совпадать с полемnameобнаруженного кошелька.Процесс:
- Устанавливает
connecting: true - Вызывает функцию
standard:connectкошелька - Получает аккаунты из кошелька
- Подписывается на события кошелька (или запускает опрос, если события недоступны)
- Сохраняет предпочтение кошелька в настроенном хранилище
- Обновляет состояние с аккаунтами и выбранным аккаунтом
Генерирует ошибку: Если кошелек не найден, кошелек не поддерживает подключение или подключение отклонено пользователем.
- Устанавливает
-
disconnect(() => Promise<void>) - Отключает текущий кошелек и очищает все состояние.Процесс:
- Отменяет подписку на события кошелька
- Останавливает опрос аккаунтов
- Вызывает функцию
standard:disconnectкошелька, если доступна - Очищает выбранный кошелек, аккаунты и выбранный аккаунт
- Удаляет предпочтение кошелька из хранилища
Никогда не генерирует ошибок (ошибки записываются в журнал, если включена отладка).
-
selectAccount((address: string) => Promise<void>) - Переключает выбранный аккаунт на другой адрес из подключенного кошелька. Если адреса нет в текущем массиве аккаунтов, запускает повторное подключение для получения обновленных аккаунтов.Генерирует ошибку: Если кошелек не подключен или запрошенный аккаунт не найден после повторного подключения.
useConnectorClient()
Предоставляет прямой доступ к базовому экземпляру ConnectorClient для
продвинутых сценариев использования.
Возвращает: ConnectorClient | null - Экземпляр синглтон-клиента или null
при использовании вне ConnectorProvider.
Сценарии использования:
- Прямой доступ к
getConnectorState()для императивного чтения состояния - Ручная подписка с
subscribe(listener)для пользовательских обработчиков состояния - Вызов
destroy()для принудительной очистки (не рекомендуется при обычном использовании)
Пример:
const client = useConnectorClient();// Get current state without triggering re-renderconst state = client?.getConnectorState();// Subscribe to state changes manuallyuseEffect(() => {if (!client) return;const unsubscribe = client.subscribe((state) => {console.log("Wallet state changed:", state);});return unsubscribe;}, [client]);
Определения типов
WalletInfo
Метаданные об обнаруженном кошельке.
interface WalletInfo {wallet: Wallet; // Raw Wallet Standard wallet objectname: string; // Display name (e.g., "Phantom", "Solflare")icon?: string; // Data URL for wallet icon (base64 encoded)installed: boolean; // Always true (only installed wallets are discovered)connectable?: boolean; // Whether wallet supports required features}
connectable Требования: Кошелек считается подключаемым, если он
поддерживает:
- функцию
standard:connect - функцию
standard:disconnect - блокчейны Solana (определяются через
wallet.chains, содержащий"solana")
Неподключаемые кошельки отображаются в массиве wallets, но не могут быть
выбраны.
AccountInfo
Информация об аккаунте кошелька.
interface AccountInfo {address: string; // Base58-encoded public keyicon?: string; // Account-specific icon (data URL)raw: WalletAccount; // Raw WalletAccount object from Wallet Standard}
Поле raw предоставляет доступ к дополнительным свойствам аккаунта:
address: string- публичный ключ в кодировке Base58publicKey: Uint8Array- байты публичного ключа в необработанном видеlabel?: string- метка аккаунта (если кошелек предоставляет её)icon?: string- иконка, специфичная для аккаунта (data URL)chains: string[]- поддерживаемые блокчейны для этого аккаунтаfeatures: string[]- поддерживаемые функции для этого аккаунта
ConnectorSnapshot
Возвращаемый тип useConnector(), объединяющий состояние и действия.
type ConnectorSnapshot = ConnectorState & {select: (walletName: string) => Promise<void>;disconnect: () => Promise<void>;selectAccount: (address: string) => Promise<void>;};interface ConnectorState {wallets: WalletInfo[];selectedWallet: Wallet | null;connected: boolean;connecting: boolean;accounts: AccountInfo[];selectedAccount: string | null;}
Обнаружение изменений аккаунта
Коннектор автоматически обнаруживает изменения аккаунтов кошелька (пользователь добавляет/удаляет аккаунты, переключается между аккаунтами в кошельке). Используются две стратегии:
На основе событий (предпочтительно)
Когда кошелек поддерживает standard:events, коннектор подписывается на события
change:
- Получает уведомления в реальном времени при изменении аккаунтов
- Более эффективно (без опроса)
- Агрегирует аккаунты как из события, так и из
wallet.accountsдля обработки кошельков, которые включают в события только выбранный аккаунт
Резервный опрос
Когда события не поддерживаются, коннектор опрашивает wallet.accounts:
- Проверяет каждые
accountPollingIntervalMs(по умолчанию: 1500 мс) - Сравнивает адреса аккаунтов для обнаружения изменений
- Запускает повторный рендеринг только при фактическом изменении аккаунтов
Логика выбора аккаунта:
- При изменении аккаунтов сохранять выбранный аккаунт, если он все еще существует
- Если выбранный аккаунт был удален, выбрать первый доступный аккаунт
- При подключении с новым аккаунтом (отсутствующим в предыдущих аккаунтах) отдавать предпочтение новому аккаунту
Хранилище и автоподключение
Постоянство хранилища
Коннектор сохраняет один ключ в настроенном хранилище:
- Ключ:
arc-connector:lastWallet - Значение: Имя кошелька (например,
"Phantom")
Операции с хранилищем обёрнуты в try-catch для обработки:
- Изолированных iframe, где
localStorageвызывает исключение - SSR-окружений, где
windowне определён - React Native, где
localStorageне существует
Если работа с хранилищем не удаётся, коннектор продолжает работу без постоянства (ошибки не выбрасываются).
Поведение автоподключения
Когда autoConnect: true:
- При монтировании читает имя последнего кошелька из хранилища
- Ожидает 100 мс (позволяет кошелькам зарегистрироваться)
- Вызывает
select(walletName), если кошелёк обнаружен - Если автоподключение не удалось, удаляет некорректные настройки из хранилища
Примечание по безопасности: Сохранённая настройка — это всего лишь имя кошелька (строка), а не конфиденциальные данные. Кошелёк обрабатывает аутентификацию/авторизацию через собственный интерфейс.
Примеры использования
Базовая кнопка кошелька
import { ConnectorProvider, useConnector } from "@solana-commerce/connector";function App() {return (<ConnectorProvider config={{ autoConnect: true }}><WalletButton /></ConnectorProvider>);}function WalletButton() {const { wallets, select, disconnect, connected, accounts, connecting } =useConnector();if (!connected) {return (<div><h3>Connect Wallet</h3>{wallets.map((wallet) => (<buttonkey={wallet.name}onClick={() => select(wallet.name)}disabled={!wallet.connectable || connecting}>{wallet.icon && (<img src={wallet.icon} alt={wallet.name} width={24} />)}{wallet.name}{!wallet.connectable && " (Unsupported)"}</button>))}</div>);}return (<div><p>Connected: {accounts[0]?.address.slice(0, 8)}...</p><button onClick={disconnect}>Disconnect</button></div>);}
Селектор нескольких аккаунтов
function AccountSelector() {const { accounts, selectedAccount, selectAccount } = useConnector();if (accounts.length <= 1) return null;return (<selectvalue={selectedAccount || ""}onChange={(e) => selectAccount(e.target.value)}>{accounts.map((account) => (<option key={account.address} value={account.address}>{account.raw.label || `${account.address.slice(0, 8)}...`}</option>))}</select>);}
Мониторинг подключения
function ConnectionMonitor() {const { connected, selectedWallet, accounts } = useConnector();useEffect(() => {if (connected) {console.log("Wallet connected:", selectedWallet?.name);console.log("Accounts:",accounts.map((a) => a.address));}}, [connected, selectedWallet, accounts]);return null;}
Поддерживаемые кошельки
Коннектор поддерживает все кошельки, реализующие Wallet Standard, включая:
- Phantom
- Solflare
- Backpack
- Glow
- Brave Wallet
- Coinbase Wallet
- Любой другой совместимый с Wallet Standard кошелёк
Кошельки автоматически обнаруживаются при регистрации в API Wallet Standard (настройка не требуется).
Использование без UI (Без React)
Для приложений, не использующих React, или для серверного использования
применяйте ConnectorClient напрямую:
import { ConnectorClient } from "@solana-commerce/connector";const connector = new ConnectorClient({autoConnect: true,debug: true});// Get current stateconst state = connector.getConnectorState();console.log("Available wallets:", state.wallets);// Connect to a walletawait connector.select("Phantom");// Subscribe to state changesconst unsubscribe = connector.subscribe((state) => {console.log("Connected:", state.connected);console.log("Accounts:", state.accounts);});// Switch accountawait connector.selectAccount("account-address-here");// Disconnectawait connector.disconnect();// Cleanup (removes all listeners and timers)connector.destroy();
Примечание: ConnectorClient управляет собственным состоянием и никогда не
вызывает повторный рендеринг React. Вы должны вручную подписываться на изменения
состояния.
Is this page helpful?