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:
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.
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.
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.
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.
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;
};