Grin++ recent development updates and nostr

I have been working on improving and updating Grin++ API in the last months, for that I have brought back to life the CLI version which allows me to experiment the changes freely and without affecting the current users of the UI. I am also improving multiplatform support especially for ARM64.

Instead of using TypeScript, I have rewritten the CLI tool in Python. To produce the standalone executables I have chosen cx-Freeze.

The main goal is to make the Grin++ API compatible with the grin-wallet API of the Rust implementation, at least in the basic functionalities. So far so good. Those developers building something on top of Grin will be able to swap nodes/wallets in case they need to.

I’m still not sure if I’m going to open an RFC with my thoughts based on these last few months working on this. Maybe.


I have been distracted by experimenting with Nostr. Nostr is a simple, open protocol that enables global, decentralized, and censorship-resistant “social media”. It bothers me, so to speak, that even most people associate Nostr with social media. From a technical point of view, I don’t see how Nostr could scale in real life to withstand 1 million users, nor why people would want to not have control of their own data by spreading content everywhere with no opportunity to exercise their right to “be forgotten”. But that would be an irrelevant discussion in relation to Grin.

You can get the nostr pubkey with a simple command like this:

As far as Grin is concerned, Nostr seems to be a perfect fit for Grin. This is how a Grin transaction looks like on Nostr:

That’s an encrypted slatepack sent as a DM from one wallet to another wallet using the CLI… this is just pure beauty :star_struck:

I deployed a nostr expensive relay paid with Monero:

What to expect

I want to complete what I started. I believe it is worth the effort to give users the opportunity to use Nostr as a method of transportation. Nostr is safe, fast, and relatively private. I would say, private enough, one can derive several pubkeys to increase privacy. I still not 100% user how to combine Nostr and Grin, but so far the basics are working. I will be releasing the code soon so anyone can experiment.

It would be very easy to create a paywall for a relay payment using Grin :slightly_smiling_face: instead of using BTC :face_vomiting: or Monero :sunglasses: I think I could do it as an exercise to put into practice the changes in the Grin++ API.

I would like to read your opinions about Nostr+Grin. If you have any suggestions on what Grin’s transactions at Nostr could look like, let me know.


Amazing! I really look forward to start using grin++ API and complete my Telegram bot with it Telegram bot progress thread by @renzokuken - #34 by renzokuken


I totally agree about the right to be forgotten, by the way. If we keep speaking up about privacy concerns, it will naturally improve. Just need to guide the zeitgeist in that direction.

  1. The cool thing about Nostr is that the user does have control over where their data spreads. Clients will continue to improve in how this is shown and managed by the user. One client I’ve used actually shows each Relay and whether you read or write to it. Clarifying the read/write relationship is helpful imo. Also, running your own relay from a home device could become easier over time as well.

  2. I think in the future, users will primarily only post encrypted data. Unencrypted will be rare. Sort of like how most people on Facebook only post “to friends”, but you can post publicly if you so choose.

Clients also adding multi-account management (account switching) help with this a ton! So much privacy can be gained from that simple best practice (segmenting your identities).

It unlocks so many use cases! The venmo product idea needed a messaging system and now it’s here! Also there is a marketplace spec built on Nostr too!

How do you do it without invoices or payment proofs though?

1 Like

Looks very nice!

i agree that it doesn’t seem like it can scale, at least not with the current design. I also think that when you put data on the internet you can never 100% delete it (at least you can’t get a proof of complete deletion).

For the cli i think that command transaction send --nostr-pub-key should strictly use nostr and not try tor first (i think it’s nice to have an option to strictly use a specific transport) (i would also rename the flag to --nostr)

Also a few questions:
how does command transaction receive --nostr work? does it autoreceive all existing step1 slatepacks on nostr? to which nostr relay does it connect if you don’t specify it? have you already thought about how it could work with manual confirms? would it make sense to have a command which would list nostr slatepacks and you would then put one such nostr content as an input to receive/finalize commands?

1 Like

I don’t think they have this control. There’s no authentication check when publishing events, which means I, or anyone else, can grab your events and spread them everywhere. Even if there was a check, I could just have a database of everyone’s events and run a relay that serves them.

Yes, bits are easy to copy. It’s the same thing as handing a tape to someone and trying to prove a copy of the tape has not been made. You’d need to search the whole space to prove it doesn’t exist, which is impossible.

Using Nostr without Tor or VPN leaks the IP to the relays. Regardless if Tor is on or off, users should understand what the connection looks like.

I don’t think this is any different than any other transport mechanism, so you can solve the problem in abstract and just substitute transport method with whatever the current flow is.


i meant not to use tor as transport for slatepacks, not tor related to nostr. If i understood correctly it first tries to send slatepack normally over tor and if that fails it tries over nostr

As of now, people are perfectly fine with soft deletion (there is no such thing as a hard delete, as you said). It’s just that 99% of people do not have enemies that are permanently saving everything they say, waiting for something they can use against them. That would take a true psycho to dedicate such disk space to such trivial data.

I just get really annoyed when people make the argument “well since we can’t guarantee a delete, it’s better to have nothing”. It shows such a strong disconnect from the experience of the average user.

One client (Nos Social) just recently implemented honoring of deletion events on the client side. Even if the relays don’t honor deletes, your client still will. I find that nice because I would feel really awkward if my friend wanted to redact something and I for some reason chose not to honor that.

I have heard about this complaint from ActivityPub server admins. Because in ActivityPub, it does the auth check yeah.

But I also think that’s why encryption will become a lot more common. Like friends lists, etc.

i do think that deletion of the data in majority of places is better than nothing, but if nostr client doesn’t show “deleted” items that’s not a deletion, it’s basically just “don’t show this info” which is not the same. Since everything is public, sooner or later someone will create a service which will give you a list of deleted items related to X (pubkey or some more advanced filter) and anyone will be able to easily find such items.

1 Like

As long as NOSTR is used only via connection over Tor, it can serve as an alternative for Grin Bulletin boards:

Call me paranoid, but for me the use of Tor and possibly ephemeral keys should be obligatory if we want to use nostr as transaction relay and bulletin board while preserving transaction privacy.

To use ephemeral keys would require spam protection though and as such payment to the relay.

i suppose that is true. it’s basically like group chats. they are only as private as the amount of trust you have in the people in the group.

i am a big proponent of encryption by default with Nostr. a friend system basically. I think it’ll go a long way in keeping people safe.

then if you post publicly, you’re much more cognizant of the implications

I know that, of course. The point is that most people have no desire to disrespect their friends and look into stuff like that though.

If you’re a person with many opps and haters though, and you love posting to them as your audience, yeah it’s a problem haha

Good people won’t do it, but bad people will and they will spread the unwanted info to them so in the end everyone will know

Burkett was initially hesitant to add the current RSR flow to Grin++, today I don’t think it’s worth the effort for now. One could try to create a wallet whose only function is to wait for a payment of a specific amount from a specific address, start the listener and when the payment is made, it could be sent to turn off the listener. Another option could be as easy a use Slatepack messages and unpack the slatepack and validate the amount. The latter seems easier to me.

It is very similar to how you have described it. Right now, it queries the relay asking for DMs, then the DMs are decrypted, if a Slatepack is found the it is added to a list. Next, the Slatepack unpacked into a Slate, if the Slate isn’t found in your list of transactions, the Slatepack is displayed on screen. The user then specifies which of the slates he wants to add his signature to (“receive”). The Slate is send back signed to the sender via Nostr. The Sender then “finalize” the transaction with a similar process.

No. I think Manual confirmation makes more sense. So, I will not include auto-receive via Nostr.

To none. I’m thinking how to take advantage of the API though. What do you think?

I am trying to leverage Tor to connect the client to the relay. At least in my implementation, the user’s IP address is not being leaked. WebSockets are reliable and quite fast.

Yes and no. That is, I see Nostr as an alternative, not a substitute. Based on my tests, I would say that public relays cannot be trusted at all, at least for now. On the other hand, if we are talking about paid relays, it is in fact the opposite. I see paid relays as a viable option.


Github link for grin++ cli wallet?

what if there are 2 or more new slatepacks fetched from nostr relay? do you display all of them? One idea could be:

  • if the slatepack is from step1 then create new “transaction object” internally (by “transaction object” i mean wallet’s internal data structure for storing transaction related data)
  • if the slatepack is from step2 then update an existing “transaction object” internally and post the completed transaction on the chain

In the first case you still need to sign that transaction and send it. I guess the “fetch from nostr” could just output ID’s of new transaction objects and then you would run command for signing that transaction and specify --nostr or whatever to send the new slatepack there.

I guess you could select a subset of public ones as the default list of relays if the user doesn’t manually tell which set of relays he wants to use. In the future it would be nice to have some kind of wallet config nostr --relay-list domain1,domain2... or something similar to be able to configure transport options (also for other transport protocols).

1 Like

I preparing the PRs. I had to switch the nostr python library from python-nostr to pynostr in order to get Windows support. Also I’m testing another alternatives to cx-Freeze since for macOS the executable depends on so many shared libraries.

1 Like

I personally believe for ツ adoption the RSR flow is even more important than SRS flow.

SRS flow: sender does most of the work, sender does send and finalize, receiver does only receive.
RSR flow: receiver does most of the work, receiver does invoice and finalize, sender does only pay.

(In my opinion) for most of the interactions in modern commerce sender is human and receiver is machine. Reason for that is stores and marketplaces are automated. Even if human is the cashier, the cash register, credit card terminal or POS issues bill and accepts payment. Humans want something, machines allow that to happen. When we do online shopping, purchase airline tickets, pay electricity bills etc, we expect machine to issue the final bill for us, we just want to take a look briefly and pay.

A and B:
If SRS flow is default and only option then most interactions work in a way making humans do more work than machine. According to my argument, most of the transactions in modern world are initiated by machine and paid by human. SRS flow makes sense for the case when it is the sender who decides the amount, in my opinion this is rarely the case.


Perhaps I should consider it then. Thanks for sharing your opinion, king!

1 Like

I’ve made the same conclusion about RSR here (and against RSRS, although i understand why it’s simpler to implement). The way i see it, RSR should give way better UX for store/service style transactions imo.