Skip to content

Getting Started

Installation

yarn
yarn add @omnisat/lasereyes

Quick Start

  1. Wrap your app with the LaserEyesProvider:
// note: component MUST NOT be rendered with SSR
import { LaserEyesProvider, MAINNET } from "@omnisat/lasereyes";
 
function App() {
  return (
    <LaserEyesProvider config={{ network: MAINNET }}>
      {/* Your app components */}
    </LaserEyesProvider>
  );
}
  1. Use the useLaserEyes hook in your components:
import { useLaserEyes, UNISAT } from "@omnisat/lasereyes";
 
function WalletConnector() {
  const {
    connect,
    connected,
    address,
    balance,
    sign,
    sendBTC,
    signPsbt,
    switchNetwork,
  } = useLaserEyes();
 
  const handleConnect = () => {
    connect(UNISAT);
  };
 
  const handleSendBTC = async () => {
    const recipient = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
    const amount = 1000; // 1000 sats
    await sendBTC(recipient, amount);
  };
 
  const handleSignMessage = async () => {
    const message = "SIGN ME, BABY";
    const signature = await sign(message);
    console.log(signature);
  };
 
  const handleSignPsbt = async () => {
    const psbtBase64 = "..."; // Your PSBT as a base64 string
    const tx = await signPsbt(psbtBase64);
    console.log(tx);
  };
 
  const handleSwitchNetwork = () => {
    switchNetwork("testnet");
  };
 
  return (
    <div>
      {!connected ? (
        <button onClick={handleConnect}>Connect Wallet</button>
      ) : (
        <div>
          <p>Connected Address: {address}</p>
          <p>Balance: {balance.total}</p>
 
          <button onClick={handleSendBTC}>Send BTC</button>
 
          <button onClick={handleSignMessage}>Sign Message</button>
 
          <button onClick={handleSignPsbt}>Sign PSBT</button>
 
          <button onClick={handleSwitchNetwork}>Switch Network</button>
        </div>
      )}
    </div>
  );
}

API Reference

LaserEyesProvider

The main context provider that should wrap your app. It initializes the LaserEyes context and makes the wallet connection and functionality available to all child components.

Usage

import { LaserEyesProvider, MAINNET } from "@omnisat/lasereyes";
 
function App() {
  return (
    <LaserEyesProvider config={{ network: MAINNET }}>
      {/* Your app components */}
      <WalletConnector />
      <TransactionHistory />
    </LaserEyesProvider>
  );
}

Props

The LaserEyesProvider accepts a config prop with the following options:

  • network: 'mainnet' | 'testnet' - The Bitcoin network to connect to. Default is 'mainnet'.

Notes

  • The LaserEyesProvider should be placed at the root of your application or at least above any components that need to interact with the wallet.
  • All child components of LaserEyesProvider can access the wallet state and functions using the useLaserEyes hook.
  • The provider initializes the wallet connection state, so it's ready to use as soon as your app loads.
  • If you're using server-side rendering (SSR), make sure to conditionally render the LaserEyesProvider only on the client-side to avoid SSR conflicts.
import { useEffect, useState } from "react";
import { LaserEyesProvider, MAINNET } from "@omnisat/lasereyes";
 
function App() {
  const [isClient, setIsClient] = useState(false);
 
  useEffect(() => {
    setIsClient(true);
  }, []);
 
  if (!isClient) return null;
 
  return (
    <LaserEyesProvider config={{ network: MAINNET }}>
      {/* Your app components */}
    </LaserEyesProvider>
  );
}

This setup ensures that the LaserEyesProvider only renders on the client-side, preventing any server-side rendering issues.


useLaserEyes

A hook that provides access to all wallet functions and state. Here are the key properties and methods:

import { useLaserEyes, UNISAT } from "@omnisat/lasereyes";
 
function WalletInfo() {
  const {
    connected,
    isConnecting,
    address,
    paymentAddress,
    publicKey,
    paymentPublicKey,
    balance,
    provider,
    network,
    accounts,
    hasUnisat,
    connect,
    disconnect,
  } = useLaserEyes();
 
  useEffect(() => {
    if (hasUnisat && !connected && !isConnecting) {
      connect(UNISAT);
    }
  }, [hasUnisat, connected, isConnecting]);
 
  if (isConnecting) return <p>Connecting to wallet...</p>;
  if (!connected)
    return <button onClick={() => connect(UNISAT)}>Connect</button>;
 
  return (
    <div>
      <h2>Wallet Information</h2>
      <p>Address: {address}</p>
      <p>Payment Address: {paymentAddress}</p>
      <p>Public Key: {publicKey}</p>
      <p>Payment Public Key: {paymentPublicKey}</p>
      <p>
        Balance: {balance !== undefined ? `${balance} satoshis` : "Loading..."}
      </p>
      <p>Provider: {provider}</p>
      <p>Network: {network}</p>
      <p>Accounts: {accounts.join(", ")}</p>
      <button onClick={disconnect}>Disconnect</button>
    </div>
  );
}

This example demonstrates how to use the useLaserEyes hook to access and display all available wallet properties, as well as use the connect and disconnect methods.


Properties

connected: Boolean - Indicates if a wallet is currently connected.

isConnecting: Boolean - Indicates if a wallet connection is in progress.

address: String - The current wallet address.

paymentAddress: String - The current wallet payment address.

  • may be different from address for some wallet types.

publicKey: String - The current wallet public key.

paymentPublicKey: String - The current wallet payment public key

  • may be different from publicKey for some wallet types.

balance: Number | undefined - The current wallet balance in satoshis.

  • undefined if not yet fetched.

provider: String | undefined - Current wallet provider (e.g., 'unisat').

  • undefined if not connected.

network: 'mainnet' | 'testnet' - Current network the wallet is connected to.

accounts: String[] - Array of accounts associated with the connected wallet.

hasUnisat: Boolean - Indicates if the Unisat wallet is available in the browser.

network: 'mainnet' | 'testnet' - Current network the wallet is connected to.

accounts: String[] - Array of accounts associated with the connected wallet.

hasUnisat: Boolean - Indicates if the Unisat wallet is available in the browser.


Methods

connect

Connects to the specified wallet.

Input
  • walletName: 'unisat'
  • The name of the wallet to connect to (currently only 'unisat' is supported)
Output

Promise<void>

  • Resolves when the connection is successful
  • Rejects with an error if the connection fails
Example
import { UNISAT } from "@omnisat/lasereyes";
 
try {
  await connect(UNISAT);
  console.log("Successfully connected to Unisat wallet");
} catch (error) {
  console.error("Error connecting to wallet:", error);
}
Notes
  • Currently, only the Unisat wallet ('unisat') is supported.
  • This method initiates the connection process, which may involve user interaction (e.g., approving the connection in their wallet).
  • After a successful connection, other wallet-related methods (like sendBTC, signMessage, etc.) become available.
  • The connection process may fail for various reasons (user rejection, wallet not installed, etc.). Always handle potential errors.
  • It's a good practice to check if the wallet is installed before attempting to connect:
if (hasUnisat) {
  await connect(UNISAT);
} else {
  console.log("Unisat wallet is not installed");
}

disconnect

Disconnects the currently connected wallet.

Input

None

Output

void

Example
try {
  disconnect();
  console.log("Wallet disconnected successfully");
} catch (error) {
  console.error("Error disconnecting wallet:", error);
}
Notes
  • This method doesn't return a promise, so it executes synchronously.
  • After disconnecting, all wallet-related properties (like address, balance, etc.) should be considered invalid.
  • You may want to update your UI or application state after calling this method to reflect the disconnected state.
  • It's good practice to call this method when your user initiates a "logout" or "disconnect" action.
  • Even though the method doesn't have a return value, it's still a good idea to wrap it in a try-catch block to handle any unexpected errors.

switchNetwork

Switches the wallet to the specified Bitcoin network.

Input
  • network: 'mainnet' | 'testnet'
  • The network to switch to
Output

Promise<void>

  • Resolves when the network switch is complete
Example
try {
  await switchNetwork("testnet");
  console.log("Successfully switched to testnet");
} catch (error) {
  console.error("Error switching network:", error);
}
 
// Later in your code...
try {
  await switchNetwork("mainnet");
  console.log("Successfully switched back to mainnet");
} catch (error) {
  console.error("Error switching network:", error);
}
Notes
  • Only 'mainnet' and 'testnet' are supported as network options.
  • Switching networks may affect the wallet's balance, address, and other network-specific data.
  • Ensure that you update any network-dependent operations in your application after switching networks.
  • The wallet may require user confirmation to switch networks.
  • Handle potential errors, as the network switch may fail due to various reasons (user rejection, connection issues, etc.).

sendBTC

Sends Bitcoin to a specified address.

Input
  • to: string
    • Recipient's Bitcoin address
  • amount: number
    • Amount to send in satoshis
Output

Promise<string>

  • Resolves with the transaction ID
Example
const recipientAddress = "bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq";
const amountInSatoshis = 100000; // 0.001 BTC
 
try {
  const txId = await sendBTC(recipientAddress, amountInSatoshis);
  console.log("Transaction sent successfully. Transaction ID:", txId);
} catch (error) {
  console.error("Error sending BTC:", error);
}
Notes
  • The amount is specified in satoshis (1 BTC = 100,000,000 satoshis).
  • Ensure that the wallet has sufficient balance before sending.
  • The transaction may take some time to be confirmed on the network.
  • Always double-check the recipient's address to avoid sending to the wrong address.
  • Handle potential errors, as the transaction may fail due to various reasons (insufficient funds, network issues, etc.).

signMessage

Signs a message with the connected wallet.

Input
  • message: string
  • The message to be signed
Output

Promise<string>

  • Resolves with the signature as a string
Example
const messageToSign = "Hello, Bitcoin!";
try {
  const signature = await signMessage(messageToSign);
  console.log("Message signed successfully. Signature:", signature);
} catch (error) {
  console.error("Error signing message:", error);
}
Notes
  • The resulting signature can be used to prove ownership of the address without revealing the private key.
  • The signature format may vary depending on the wallet implementation.
  • Always handle potential errors, as the signing process may fail or be cancelled by the user.

signPsbt

Signs a Partially Signed Bitcoin Transaction (PSBT).

Input
  • psbt: string
    • PSBT as a hex or base64 string
  • finalize: boolean (optional)
    • Whether to finalize the PSBT
Output

Promise<{ signedPsbtHex?: string, signedPsbtBase64?: string, txId?: string } | undefined>

Example
const psbtHex = "70736274ff01..."; // Your PSBT hex string
try {
  const { signedPsbtHex, txId } = await signPsbt(psbtHex, true, false);
  console.log("Signed PSBT (hex):", signedPsbtHex);
  console.log("Transaction ID:", txId);
} catch (error) {
  console.error("Error signing PSBT:", error);
}
Notes
  • If finalize is true, the PSBT will be finalized after signing.
  • If broadcast is true, the transaction will be broadcast to the network after signing.
  • The method may return undefined if the signing process fails or is cancelled by the user.

pushPsbt

Pushes a signed Partially Signed Bitcoin Transaction (PSBT) to the network.

Input
  • tx: string
    • Signed PSBT as a hex or base64 string
Output

Promise<string | undefined>

  • Resolves with the transaction ID if successful
  • Resolves to undefined if the push fails or is cancelled
Example
const signedPsbtHex = "70736274ff01..."; // Your signed PSBT hex string
try {
  const txId = await pushPsbt(signedPsbtHex);
  if (txId) {
    console.log("Transaction successfully pushed. Transaction ID:", txId);
  } else {
    console.log("Transaction push failed or was cancelled.");
  }
} catch (error) {
  console.error("Error pushing PSBT:", error);
}
Notes
  • Ensure that the PSBT is fully signed before pushing to the network.
  • The method may return undefined if the push fails or is cancelled for any reason.
  • Always handle potential errors when using this method, as network operations can fail.

Supported Wallets

More wallets are coming soon... Please vote which wallet we should add next: https://demo.lasereyes.build/

Each wallet has different capabilities and methods of interaction. The package abstracts these differences to provide a unified API.

Network Handling

The package supports both mainnet and testnet. You can switch networks using the switchNetwork function, and check the current network with the network property.

Error Handling

Most functions in the package are asynchronous and may throw errors. It's recommended to use try-catch blocks when calling these functions:

try {
  await connect("unisat");
} catch (error) {
  console.error("Failed to connect:", error);
}

Advanced Usage

Custom Configuration

You can create a custom configuration using the createConfig function:

import { createConfig } from "@omnisat/lasereyes";
 
const config = createConfig({
  network: "testnet",
  provider: "unisat",
  chainId: 1,
});

Working with PSBTs

The package provides methods for signing and pushing Partially Signed Bitcoin Transactions (PSBTs):

const psbt = "..."; // Your PSBT string
const signedPsbt = await signPsbt(psbt, true, false);
const txId = await pushPsbt(signedPsbt);

Best Practices

  1. Always check if a wallet is connected before performing operations.
  2. Handle network changes gracefully, as they can affect address and balance.
  3. Provide clear feedback to users during wallet operations, as they may require user interaction in the wallet interface.
  4. Always validate user input before sending transactions or signing messages.

Contributing

Contributions are welcome! Please check out our Contributing Guide for more details.

License

This project is licensed under the MIT License - see the LICENSE file for details.