A Dart package that makes it easy to work with the nostr protocol and develop nostr clients.
Usage
To use this package, add nostr_tools
as a dependency in your pubspec.yaml file.
Generating a private key and a public key
import 'package:nostr_tools/nostr_tools.dart'; void main() { final keyGenerator = KeyApi(); final privateKey = keyGenerator.generatePrivateKey(); print('[+] privateKey: $privateKey'); // [+] privateKey: b2352adb186508e7f617105a6dc070df531f53b56cf8744816fdb838891dc9b7 final publicKey = keyGenerator.getPublicKey(privateKey); print('[+] publicKey: $publicKey'); // [+] publicKey: 9d088c4377b9866fad945d949de8f626784b1639f93bf090c1cea6727f17dd51 }
Creating, signing and verifying events
import 'package:nostr_tools/nostr_tools.dart'; void main() { final keyApi = KeyApi(); final eventApi = EventApi(); final privateKey = keyApi.generatePrivateKey(); final publicKey = keyApi.getPublicKey(privateKey); final event = Event( kind: 1, tags: [], content: 'content', created_at: DateTime.now().millisecondsSinceEpoch ~/ 1000, pubkey: publicKey, ); event.id = eventApi.getEventHash(event); event.sig = eventApi.signEvent(event, privateKey); if (eventApi.verifySignature(event)) print('[+] sig is valid'); }
Interacting with a relay
void main() async { final relay = RelayApi(relayUrl: 'wss://relay.damus.io'); final stream = await relay.connect(); relay.on((event) { if (event == RelayEvent.connect) { print('[+] connected to ${relay.relayUrl}'); } else if (event == RelayEvent.error) { print('[!] failed to connect to ${relay.relayUrl}'); } }); relay.sub([ Filter( kinds: [1], limit: 10, since: DateTime.now().millisecondsSinceEpoch ~/ 1000, ) ]); stream.listen((Message message) { if (message.type == 'EVENT') { Event event = message.message; print('[+] Received event: ${event.content}'); } else if (message.type == 'OK') { print('[+] Event Published: ${message.message}'); } }); // let's publish a new event while simultaneously monitoring the relay for it final privateKey = 'b2352adb186508e7f617105a6dc070df531f53b56cf8744816fdb838891dc9b7'; final event = EventApi().finishEvent( Event( kind: 1, tags: [], content: 'hello world', created_at: DateTime.now().millisecondsSinceEpoch ~/ 1000, ), privateKey, ); relay.publish(event); }
Interacting with multiple relays
void main() async { final relaysList = [ 'wss://relay.damus.io', 'wss://relay.nostr.info', 'wss://eden.nostr.land', 'wss://nostr-pub.wellorder.net', 'wss://nos.lol' ]; final relayPool = RelayPoolApi(relaysList: relaysList); final stream = await relayPool.connect(); relayPool.on((event) { if (event == RelayEvent.connect) { print('[+] connected to: ${relayPool.connectedRelays}'); } else if (event == RelayEvent.error) { print('[!] failed to connect to: ${relayPool.failedRelays}'); } }); relayPool.sub([ Filter( kinds: [1], limit: 10, since: DateTime.now().millisecondsSinceEpoch ~/ 1000, ) ]); stream.listen((Message message) { if (message.type == 'EVENT') { Event event = message.message; print('[+] Received event: ${event.content}'); } }); final privateKey = 'ccbe92bd853e3661bace63df5b8338dcbaa2c766e2dbb0b90d45b2dd58efaae4'; final event = EventApi().finishEvent( Event( kind: 1, tags: [], content: 'hello world', created_at: DateTime.now().millisecondsSinceEpoch ~/ 1000, ), privateKey, ); relayPool.publish(event); }
Querying profile data from a NIP-05 address
void main() async { var nip05 = Nip05(); var profile = await nip05.queryProfile('anipy@aniketambore.github.io'); print('[+] Pubkey: ${profile?.pubkey}'); // [+] Pubkey: c7c187ba76532d55723490af88e76dd570fe551a2461ca9ab542b503bbb25045 print('[+] Relays: ${profile?.relays}'); // [+] Relays: [wss://relay.damus.io, wss://nos.lol, wss://relay.snort.social] }
Encoding and decoding NIP-19 codes
void main() { final keyGenerator = KeyApi(); final nip19 = Nip19(); final sk = keyGenerator.generatePrivateKey(); final nsec = nip19.nsecEncode(sk); final nsecDecoded = nip19.decode(nsec); assert(nsecDecoded['type'] == 'nsec'); assert(nsecDecoded['data'] == sk); final pk = keyGenerator.getPublicKey(sk); final npub = nip19.npubEncode(pk); final npubDecoded = nip19.decode(npub); assert(npubDecoded['type'] == 'npub'); assert(npubDecoded['data'] == pk); final relays = [ 'wss://relay.nostr.example.mydomain.example.com', 'wss://nostr.banana.com' ]; final nprofile = nip19.nprofileEncode(ProfilePointer(pubkey: pk, relays: relays)); final nprofileDecode = nip19.decode(nprofile); assert(nprofileDecode['type'] == 'nprofile'); assert(nprofileDecode['data']['pubkey'] == pk); assert(nprofileDecode['data']['relays'].length == 2); }
Encrypting and decrypting direct messages
void main() { final keyGenerator = KeyApi(); final nip04 = Nip04(); final aliceSK = keyGenerator.generatePrivateKey(); final alicePK = keyGenerator.getPublicKey(aliceSK); final bobSK = keyGenerator.generatePrivateKey(); final bobPK = keyGenerator.getPublicKey(bobSK); var aliceMessageToBob = 'Hello Bob!'; var cipherText = nip04.encrypt(aliceSK, bobPK, aliceMessageToBob); print('[+] cipherText: $cipherText'); var bobDecodingMessage = nip04.decrypt(bobSK, alicePK, cipherText); print('[+] plainText: $bobDecodingMessage'); }
Take a look at the example project for developing a simple basic nostr client in flutter.