@solana-commerce/connector 패키지는
Wallet Standard를 기반으로
구축된 헤드리스 지갑 연결 기능을 제공합니다. 이 패키지는 지갑 검색, 연결 상태,
계정 관리 및 자동 재연결을 관리합니다. 프레임워크에 구애받지 않도록 설계되었으며
React 바인딩이 포함되어 있습니다. Solana Commerce Kit에서 원활하게 사용할 수
있도록 맞춤 제작되었으며 @solana/kit 및
gill과 호환됩니다.
지갑 연결
설치
pnpm add @solana-commerce/connector
프로바이더 구성
ConnectorProvider
ConnectorProvider 컴포넌트는 애플리케이션을 감싸고 모든 하위 컴포넌트에 지갑
연결 상태를 제공합니다. 컴포넌트의 마운트/언마운트 주기 전반에 걸쳐 지속되는
싱글톤 ConnectorClient 인스턴스를 관리합니다.
Props
모든 구성은 config prop을 통해 전달됩니다:
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입니다. 이것은 Wallet Standard API의 원시 지갑 인스턴스입니다. -
connected(boolean) - 연결 상태입니다. 지갑이 연결되고 계정을 사용할 수 있을 때true입니다. 조건부 UI 렌더링에 사용하세요. -
connecting(boolean) - 지갑 연결 중 로딩 상태입니다.select()호출과 연결 결과 수신 사이에true입니다. 로딩 표시기를 표시하거나 버튼을 비활성화하는 데 사용하세요. -
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- Base58로 인코딩된 공개 키publicKey: Uint8Array- 원시 공개 키 바이트label?: string- 계정 레이블 (지갑이 제공하는 경우)icon?: string- 계정별 아이콘 (데이터 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마다 확인 (기본값: 1500ms)- 계정 주소를 비교하여 변경사항을 감지
- 계정이 실제로 변경된 경우에만 재렌더링을 트리거
계정 선택 로직:
- 계정이 변경될 때, 선택된 계정이 여전히 존재하는 경우 유지
- 선택된 계정이 제거된 경우, 사용 가능한 첫 번째 계정을 선택
- 새 계정(이전 계정에 없던)으로 연결할 때, 새 계정을 우선적으로 선택
저장소 & 자동 연결
저장소 지속성
커넥터는 구성된 저장소에 하나의 키를 저장합니다:
- 키:
arc-connector:lastWallet - 값: 지갑 이름 (예:
"Phantom")
저장소 작업은 다음 상황을 처리하기 위해 try-catch로 래핑됩니다:
localStorage가 오류를 발생시키는 샌드박스 iframewindow가 정의되지 않은 SSR 환경localStorage가 존재하지 않는 React Native
저장소가 실패하면 커넥터는 지속성 없이 계속 작동합니다(오류가 발생하지 않음).
자동 연결 동작
autoConnect: true인 경우:
- 마운트 시 저장소에서 마지막 지갑 이름을 읽습니다
- 100ms 대기 (지갑 등록 허용)
- 지갑이 발견되면
select(walletName)를 호출합니다 - 자동 연결이 실패하면 저장소에서 유효하지 않은 설정을 제거합니다
보안 참고사항: 저장된 설정은 지갑 이름(문자열)일 뿐 민감한 데이터가 아닙니다. 지갑은 자체 UI를 통해 인증/권한 부여를 처리합니다.
사용 예제
기본 지갑 버튼
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 호환 지갑
지갑은 Wallet Standard API에 등록되면 자동으로 발견됩니다(구성 불필요).
Headless 사용법 (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?