Guide
Nostr
NIP-07

NIP-07

In this integration guide, we will use joyid/nostr SDK to connect to JoyID wallet with NIP-07 ↗ (opens in a new tab) protocol. NIP-07 is a simple protocol that allows a dapp to connect to a wallet and request a signature from the wallet.

️🚫

JoyID has currently only implemented the basic methods of NIP-07: getPublicKey() and signEvent(). It has not yet implemented NIP-04 (opens in a new tab), which means that encrypt(), decrypt() cannot be used.

Installation

npm install @joyid/nostr

Initialization

Before writing business code, you can call the initialization function initConfig on the project entry file:

main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { initConfig } from "@joyid/nostr";
import App from "./App";
import "./index.css";
 
initConfig({
  name: "JoyID demo",
  logo: "https://fav.farm/🆔",
  joyidAppURL: "https://testnet.joyid.dev",
});
 
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

Get Nostr public key from JoyID

After the initialization is completed, you can call the nostr.getPublicKey() function to connect to JoyID wallet:

💡

After a successful connection, JoyID persists the connection status to the local storage.

App.tsx
import { nostr } from '@joyid/nostr'
 
export default function App() {
  const [pubkey, setPubkey] = React.useState<string | null>();
  const onConnect = async () => {
    try {
      const res = await nostr.getPublicKey();
      setPubkey(res);
    } catch (error) {
      console.log(error);
    }
  };
 
  return (
    <div id="app">
      <button className="btn btn-primary" onClick={onConnect}>
        Connect JoyID
      </button>
    </div>
  );
}

Logout

You can call the logout function to disconnect from JoyID. logout function clear the connection status from local storage.

App.tsx
import { nostr, logout } from '@joyid/nostr'
 
export default function App() {
  const [pubkey, setPubkey] = React.useState<string | null>();
  const onConnect = async () => {
    try {
      const res = await nostr.getPublicKey();
      setPubkey(res);
    } catch (error) {
      console.log(error);
    }
  };
 
  return (
    <div id="app">
      {pubkey ? (
        <>
          <h1 className="text-xl mb-4">{`Connected: ${address}`}</h1>
          <button
            className="btn btn-primary"
            onClick={() => {
              logout();
              setPubkey(null);
            }}
          >
            Logout
          </button>
          <div className="divider" />
        </>
      ) : (
        <button className="btn btn-primary" onClick={onConnect}>
          Connect JoyID
        </button>
      )}
    </div>
  );
}

Get connected pubkey

After connecting to JoyID, user may refresh the page or close the browser. You can call the getConnectedPubkey function to get the connected pubkey, getConnectedPubkey function get the connected pubkey from local storage.

App.tsx
import { nostr, logout, getConnectedPubkey } from '@joyid/nostr'
export default function App() {
  const [pubkey, setPubkey] = React.useState<string | null>(
    getConnectedPubkey(),
  );
  const onConnect = async () => {
    try {
      const res = await nostr.getPublicKey();
      setPubkey(res);
    } catch (error) {
      console.log(error);
    }
  };
 
  return (
    <div id="app">
      {pubkey ? (
        <>
          <h1 className="text-xl mb-4">{`Connected: ${pubkey}`}</h1>
          <button
            className="btn btn-primary"
            onClick={() => {
              logout();
              setPubkey(null);
            }}
          >
            Disconnect
          </button>
          <div className="divider" />
        </>
      ) : (
        <button className="btn btn-primary" onClick={onConnect}>
          Connect JoyID
        </button>
      )}
    </div>
  );
}

Sign Event

After connecting to JoyID, you can call the nostr.signEvent function to sign the event. The nostr.signEvent function will open the JoyID app and wait for the user to confirm the signature.

SignEvent.tsx
import { nostr, Event } from "@joyid/nostr";
import { getBlankEvent, verifySignature } from "nostr-tools";
interface Props {
  address: string | null;
}
 
const blankEvent = getBlankEvent() as Event<number>;
 
blankEvent.content = Math.random().toString();
 
const SignEvent = ({ address }: Props) => {
  const [event, setEvent] = React.useState<Event>(blankEvent);
  const onSign = async () => {
    const signedEvent = await nostr.signEvent(blankEvent);
    setEvent(signedEvent);
  };
  const onVerify = async () => {
    try {
      const res = verifySignature(event);
      alert(res);
    } catch (error) {
      alert(error.message);
    }
  };
  return address ? (
    <div className="w-full">
      <h2 className="mb-4 text-lg text-center">Sign Event</h2>
      <label className="label">Event:</label>
      <textarea
        className="textarea textarea-bordered w-full h-60 mb-4"
        placeholder="Signature"
        value={JSON.stringify(event, null, 4)}
        disabled
      ></textarea>
 
      <button className="btn btn-primary mb-4 mr-4" onClick={onSign}>
        Sign
      </button>
 
      <button className="btn btn-primary btn-outline mb-4" onClick={onVerify}>
        Verify
      </button>
 
      <div className="divider"></div>
    </div>
  ) : null;
};

Try it out