import { SolanaRPCUrls } from '@tuwaio/orbit-solana'; import { BaseConnector, SatelliteAdapter, SatelliteSiwxState } from '@tuwaio/satellite-core'; import { UiWallet, UiWalletAccount } from '@wallet-standard/ui'; import { Wallet, WalletAccount } from '@wallet-standard/base'; import { StandardConnectMethod } from '@wallet-standard/features'; import { ConnectorType, TuwaErrorState } from '@tuwaio/orbit-core'; /** * A Solana connection in the Satellite Connect store: `BaseConnector` from `@tuwaio/satellite-core` plus the Wallet * Standard handles of the wallet and account. `chainId` is a cluster moniker (for example `"devnet"`) and * `signMessage` returns a base58 signature. */ interface SolanaConnection extends BaseConnector { /** Wallet Standard UI handle of the connected account (the first account of the wallet). */ connectedAccount?: UiWalletAccount; /** Wallet Standard UI handle of the connected wallet. */ connectedWallet?: UiWallet; } /** A Wallet Standard `UiWallet` from `@wallet-standard/ui`: the wallets returned by `getConnectors` of the Solana adapter. */ type ConnectorSolana = UiWallet; /** * Creates the Solana adapter for the Satellite Connect store (`createSatelliteConnectStore` from * `@tuwaio/satellite-core` or `SatelliteConnectProvider` from `@tuwaio/satellite-react`). It implements * `SatelliteAdapter` with the Wallet Standard and `@solana/kit`: * - `getConnectors` returns the wallets of `getAvailableSolanaConnectors` from `@tuwaio/orbit-solana` (registered * Wallet Standard wallets with the Solana features Satellite needs). A wallet matches a `connectorType` such as * `"solana:phantom"` through `formatConnectorName` from `@tuwaio/orbit-core`. * - `connect` asks the wallet to connect (`standard:connect`) and returns a {@link SolanaConnection}: the first * account, the cluster moniker of the requested chain (`"solana:devnet"` and `"devnet"` both become `"devnet"`), the * RPC URL of that cluster from `rpcUrls`, the wallet icon, the Wallet Standard handles and a `signMessage` created * with {@link createSolanaMessageSigner}. When `rpcUrls` has no URL for the cluster, `getRpcUrlForCluster` from * `@tuwaio/orbit-solana` returns the public endpoint of that cluster (the mainnet-beta one for `localnet`, and for * every cluster with `@tuwaio/orbit-solana` 0.3.1 and earlier). * - `disconnect` disconnects the wallet of the given connection, or every wallet that has accounts. * - `checkAndSwitchNetwork` makes no wallet request (Solana wallets have no network switch): it sets the connection's * `chainId` and `rpcURL` to the new cluster. * - `getBalance` reads the balance with `getBalance` over RPC and returns it in SOL. * - `getExplorerUrl(url?, chainId?)` builds a Solana Explorer link (`explorer.solana.com`). * - `getName` and `getAvatar` resolve SNS names and avatars with `@tuwaio/orbit-solana` (Bonfida APIs, cached in * memory); `getName` returns the address when there is no name. There is no `getAddress` and no contract check. * - `switchConnection` runs `standard:connect` of the wallet again. * * @param params - Adapter options: `rpcUrls`, the RPC URL for each cluster moniker (`mainnet`, `devnet`, `testnet`, * `localnet`). The URLs are kept in memory and exposed as `rpcURL` of the connection; they are not saved to * `localStorage`. * @returns The Solana adapter. * * @example * ```ts * import { satelliteSolanaAdapter } from '@tuwaio/satellite-solana'; * * export const solanaAdapter = satelliteSolanaAdapter({ * rpcUrls: { * mainnet: 'https://api.mainnet-beta.solana.com', * devnet: 'https://api.devnet.solana.com', * }, * }); * ``` */ declare function satelliteSolanaAdapter({ rpcUrls, }: SolanaRPCUrls): SatelliteAdapter; /** * Returns the Wallet Standard `Wallet` and `WalletAccount` behind UI handles, which carry the feature implementations * (for example `solana:signMessage`). Uses the registry of `@wallet-standard/ui-registry`. * * @param uiWallet - The UI wallet handle. * @param uiAccount - The UI account handle. * @returns The underlying wallet and account, or the handles themselves when they are not registered. */ declare function unwrapUiWalletHandles(uiWallet: UiWallet, uiAccount: UiWalletAccount): { /** The Wallet Standard wallet, or `uiWallet` when it is not registered. */ wallet: Wallet | UiWallet; /** The Wallet Standard account, or `uiAccount` when it is not registered. */ account: WalletAccount | UiWalletAccount; }; /** * Connects a Wallet Standard wallet with its `standard:connect` feature. The wallet may show a prompt. * * @param uiWallet - The wallet to connect. * @param input - Options of `standard:connect`, without `silent`. * @returns `uiWallet`: the current UI handle of the same wallet (a handle is a snapshot, and the new one lists the * connected accounts); `accounts`: UI handles of the accounts the wallet returned. * @throws {Error} A `WalletStandardError` when the wallet does not implement `standard:connect`, the wallet's error * when the user rejects, or `[SATELLITE-SOLANA] The wallet did not return any accounts.` * * @example * ```ts * import { getAvailableSolanaConnectors } from '@tuwaio/orbit-solana'; * import { connect } from '@tuwaio/satellite-solana'; * * const [wallet] = getAvailableSolanaConnectors(); * if (wallet) { * const { accounts } = await connect(wallet); * console.log('Connected account:', accounts[0].address); * } * ``` */ declare function connect(uiWallet: UiWallet, input?: Omit[0]>, 'silent'>): Promise<{ uiWallet: UiWallet; accounts: UiWalletAccount[]; }>; /** * Disconnects a Wallet Standard wallet with its `standard:disconnect` feature. * * @param uiWallet - The wallet to disconnect. * @returns Resolves when the wallet has disconnected. * @throws {Error} A `WalletStandardError` when the wallet does not implement `standard:disconnect` (the wallets of * `getAvailableSolanaConnectors` from `@tuwaio/orbit-solana` always do), or the wallet's error. */ declare function disconnect(uiWallet: UiWallet): Promise; /** * Store state and actions used by {@link createSolanaConnectionsWatcher}. Pass the store's `disconnect` and * `updateActiveConnection` and its `getState`. Instead of `getState` you can pass the current `activeConnection` and * `connectionError`. */ interface SolanaWatcherCallbacks { /** The active connection. Ignored when `getState` is passed. */ activeConnection?: SolanaConnection; /** * Disconnects a connection; the store's `disconnect`. * * @param connectorType - The connector to disconnect. */ disconnect: (connectorType: ConnectorType) => void; /** * The store's `connectionError`. While it is set, wallet changes are not copied to the store. Ignored when * `getState` is passed. */ connectionError?: TuwaErrorState | string; /** * Merges fields into the active connection; the store's `updateActiveConnection`. * * @param connection - Fields to merge. */ updateActiveConnection: (connection: Partial) => void; /** * Returns the current store state, for example the store's `getState`. It is called once per run. * * @returns The current `activeConnection` and `connectionError`. */ getState?: () => { /** The active connection. */ activeConnection?: SolanaConnection; /** The connection error. */ connectionError?: TuwaErrorState | string; }; } /** * Configuration of {@link createSolanaConnectionsWatcher}. */ interface SolanaWatcherConfig { /** The registered Wallet Standard wallets, for example from `useWallets()` of `@wallet-standard/react`. */ wallets: readonly UiWallet[]; /** Optional SIWX session state. See `SatelliteSiwxState` from `@tuwaio/satellite-core`. */ siwx?: SatelliteSiwxState; } /** * Copies the state of the connected Solana wallet into the Satellite Connect store, without a UI framework. * `SolanaConnectorsWatcher` from `@tuwaio/satellite-react/solana` runs it in React apps. * * The Wallet Standard has no connection events, so the function does not subscribe to anything: it checks the given * `wallets` once. Call it again whenever the wallets change (the React component calls it on every change of * `useWallets()`). Each call: * - disconnects the active connection when the SIWX sign-in was rejected or failed (see `SatelliteSiwxState` from * `@tuwaio/satellite-core`); * - when the active connection is a Solana connection, finds its wallet in `wallets` by name and, while the user is * signed in with SIWX, disconnects when the wallet's first account is not the session account; * - otherwise, unless `connectionError` is set or the sign-in was rejected, merges the wallet's first account, its * handles and a new `signMessage` into the store when the address or connection state changed or `signMessage` is * missing; * - disconnects the active connection when its wallet has no accounts left. * * @param config - The wallets and the optional SIWX state. * @param callbacks - Store state and actions. * @returns A cleanup function that does nothing, kept for symmetry with `createEVMConnectionsWatcher` from * `@tuwaio/satellite-evm`. * * @example * ```ts * import { getAvailableSolanaConnectors } from '@tuwaio/orbit-solana'; * import { createSatelliteConnectStore } from '@tuwaio/satellite-core'; * import { * type ConnectorSolana, * createSolanaConnectionsWatcher, * satelliteSolanaAdapter, * type SolanaConnection, * } from '@tuwaio/satellite-solana'; * * const store = createSatelliteConnectStore({ * adapter: satelliteSolanaAdapter({ rpcUrls: { devnet: 'https://api.devnet.solana.com' } }), * }); * * // Run after the user switches accounts in the wallet, for example on the wallet's `standard:events` change event. * export function syncSolanaWallets() { * const { disconnect, updateActiveConnection } = store.getState(); * createSolanaConnectionsWatcher( * { wallets: getAvailableSolanaConnectors() }, * { disconnect, updateActiveConnection, getState: store.getState }, * ); * } * ``` */ declare function createSolanaConnectionsWatcher(config: SolanaWatcherConfig, callbacks: SolanaWatcherCallbacks): () => void; /** * @file Message signer for Solana wallets: Wallet Standard `solana:signMessage`, with fallbacks for wallet adapters. */ /** * The wallet and account that {@link createSolanaMessageSigner} signs with. Pass the Wallet Standard `Wallet` and * `WalletAccount` (see {@link unwrapUiWalletHandles}) or a wallet adapter. When `wallet` or `account` is missing, the * target object itself is used in its place. */ interface SolanaSignerTarget { /** The account to sign with, passed to the wallet's `signMessage`. */ account?: unknown; /** The wallet that implements `solana:signMessage`, `signMessages` or `signMessage`. */ wallet?: unknown; /** Any other property; the target may be a wallet adapter itself. */ [key: string]: unknown; } /** * Creates a function that signs UTF-8 messages with a Solana wallet and returns base58 signatures. The adapter and the * watcher use it as `signMessage` of a Solana connection. * * The signer uses the first capability it finds: the Wallet Standard `solana:signMessage` feature of the wallet (or * of the account), a `signMessages` function, then a legacy `signMessage` function of the wallet, its `adapter` or the * account. The wallet may show a prompt. * * @param target - The wallet and account to sign with. * @returns A function that signs `message` and resolves to the base58-encoded signature. It rejects with * `[SATELLITE-SOLANA] Invalid signer target.` when `target` is missing, * `[SATELLITE-SOLANA] Signer lacks known message signing capabilities.` when no capability is found, an * `... invalid signMessage output.` or `... invalid signMessages output.` error when the wallet returns no signature, * and with the wallet's error when the user rejects. */ declare function createSolanaMessageSigner(target: SolanaSignerTarget): (message: string) => Promise; export { type ConnectorSolana, type SolanaConnection, type SolanaSignerTarget, type SolanaWatcherCallbacks, type SolanaWatcherConfig, connect, createSolanaConnectionsWatcher, createSolanaMessageSigner, disconnect, satelliteSolanaAdapter, unwrapUiWalletHandles };