Grin testnet exchange example

I’ve created a simple grin testnet exchange example so that we can play with it, analyze the flow and try to improve its UX and security. I would call it some kind of a beta version since it probably has some bugs and security issues, so sorry in advance for that, will try to fix them asap (i know i still need to check some stuff but i’ve decided to let you play with it to not delay this any longer). I might reset the database when doing upgrades if I won’t feel like bothering with the updates so you might lose your coins on the exchange because of it. But you should not be keeping the coins on this test exchange anyway.
Current grin-wallet rust implementation has some wallet-api bugs, so i’ve forked it and the testnet exchange is currently using this branch - i could create a PR but since i’m not that familiar with rust and grin-wallet i’m not sure if my fixes are appropriate and don’t break some other stuff.


For those who like to dive into the code, here it is. The most important files are and Thanks to @bladedoyle and @xiaojay for their python wallet and node api implementation (i’ve partially done it myself, then blade showed me their implementation so i’ve reused the rest). Also thanks to @david for helping me understand some grin-wallet basics which helped me fix the grin-wallet api issues that were needed for this exchange to work.

Deposit and Withdrawal

I used django and vue (both are very readable and i know them, so yeah good reasons :D).
Deposits are done through invoice flow (RSR), Withdrawals are done through payment flow (SRS). This seems the best to me because it makes the flow practically the same for the user to do both and at the same time exchange is the one responsible for finalizing stuff (well i would hope they know more about how to do that than the users). In withdrawal we require a payment proof, in deposits we don’t since payment proofs for invoice flows are not yet implemented. In both cases the user gets an encrypted slatepack for his wallet and after he performs “pay” (deposit) or “receive” (withdrawal) the generated slatepack is also encrypted for the exchange’s wallet.

Confirmations update

I wasn’t sure how to check for confirmations so what i do is i store the kernel of deposit/withdrawal and then each minute i have a task which gets the current height and checks the height of all “active” deposits/withdrawals and updates number of confirmations. Until there are 10 confirmations the funds are locked, after that they’re unlocked (in the case of deposit that means they become useful, in the case of withdrawal they disappear). User can only have 1 active deposit (eg. waiting for user’s signature), if he creates another one, the old one gets canceled (tx is also canceled, but as we know grin-wallet currently doesn’t have a proper cancel implemented yet so that might not be the best).

Automatic transaction rebroadcast

I’ve wanted to do that through the “repost”, but wallet-api doesn’t have it implemented yet and i wasn’t sure if i can just pass everything to the owner api or not, so i didn’t implement that. The idea was to automatically try to rebroadcast the transaction if it didn’t land on chain for 30 minutes or so (should reduce the number of tickets an exchange gets).

For more detailed explanation on how to deposit and withdraw you can click on Instructions at the top-left corner on the website.


This is a testnet exchange example, security is probably not the best, so no, it was not built to be anything more than a testnet exchange and there is no plan for it to be anything more than that.

Getting testnet coins

One way to get testnet coins is through faucet. The faucet communication works through TOR so you need to have it installed on your system and then run grin-wallet --testnet listen to listen for TOR communication (when you run this command it will output that you don’t have TOR if you don’t have it installed). Then run curl -d '{"address": "<your wallet address>"}' - that’s basically “please send me 1 grin”. You get 1 grin for each call, can do this up to 5 times i think - probably per day or smth - thanks to @quentinlesceller for the faucet


Bug reporting

Either write it here or open an issue on github repo


This is great! Thanks for the effort! Maybe you mentioned before, but why you called “contract” to the slatepack?

I think we should have an Airdrop of testnet grins to play with this :moneybag:


This guy is fast and furious :vulcan_salute:

1 Like

the sender and the receiver are building a “transaction contract”, there was a thread about the names and i liked offer/sign/sign suggestion, but offers are usually accepted while sign is used for contracts. So i went with contracts. That’s just my pick, obviously i can change it to whatever the community would agree on. Thanks for the nice words!

Edit: i’ve edited the main post with instructions on how to get grin on the testnet

This is really cool, but why exclude the majority of users? None of the GUI or mobile wallets support invoices AFAIK. So they can’t even test this. And since invoices don’t have payment proofs, they aren’t even secure yet.

And reinventing the terminology just means we’re now suggesting non-standard terminology for exchanges who want to use this as a model.

I’d be happy to help fix these critical issues so we have something we can point to for other exchanges to adopt.


So you’ll add testnet invoice support to Grin++ :-?

1 Like

these seem like the best flows to me - easy for the user since withdrawal and deposit are symmetrical, number of tickets the exchange gets is mostly limited to their “bad implementation” imo (user can’t make problems by not knowing how to finalize). I know that Grin++ doesn’t have invoice flow and i could change it to SRS, but when we get RSR payment proofs then this implementation would be the one i would suggest to the exchanges. Currently grin is not on many exchanges and they’ve each implemented it in their own way. I wouldn’t like to suggest them now SRS for deposits and then later RSR when we have payment proofs - i would like all exchanges to have the same flow so that it’s the easiest for the user and for us to help them

1 Like

No, and the issue isn’t just Grin++. Like I said, it’s all GUI wallets that didn’t adopt invoice, and for good reasons.

Why would we go against the grain and add even more hurdles to adoption for Grin? We have a better chance of succeeding if we stick to what we know works (nobody adopted invoices so far, so they remain untested), and it’s much simpler for users to wrap their head around transacting if there’s a single flow (SRS).

But it’s not even one that’s secure today, nor is it one that the overwhelming majority of developers agree with. The fact that no GUIs support invoices should be an obvious indicator that your opinion is not shared by everyone. Why make controversial choices when this is supposed to be something we can point to as an example for exchanges to follow? I can no longer do that with the way you’ve designed it.

I know that. My opinion is that every gui wallet should support the invoice flow and i think now is a great opportunity to implement that, before exchanges integrate grin. If GUI wallets supported the invoice flow would you think SRS/SRS would be better than RSR/SRS (for deposits/withdrawals)? I feel like RSR/SRS is my answer and SRS/SRS is yours

1 Like

I think SRS/SRS is the easiest, most obvious answer. Besides, we’ve had issues in the past with exchanges not broadcasting right away. We want to make sure we aren’t making it even easier for transactions to get delayed due to poor exchange implementations of RSR (just because you show exchanges a good example of doesn’t mean they’ll follow it exactly).

My opinion is that bad UX choices should not keep getting forced on every GUI wallet. The big advantage of having competing 3rd party wallets is we have freedom to experiment with what does and doesn’t work. I’ve personally experimented and concluded invoices don’t work well.

That’s definitely true. But if they implement it in the wrong way, the users will be unhappy, they will be getting many more support tickets and users will move to other exchanges.

Yeah i know you’re not a fan of the invoice flow. From my experience using it, i found it quite pleasant to work with. I understand that it’s a new flow that we would need to teach the users about but creating a good guide is imo a better approach than throwing away one possible flow which could be used way more in the future (i don’t know, nobody does imo). What the user needs to learn about the invoice flow to use it with the exchanges is basically the “pay” part which seems very simple to me

That’s not really how it has worked in practice. TO has done the best job of implementing it, but they don’t get used much because of liquidity issues. People use the exchange they’re most familiar with, not the one that does the best job at supporting Grin.

What is so pleasant about it? It’s not like it simplifies the UX at all, and it actually makes it a bit worse in some cases, since you have to add deposit amount.

Say you want to send your max balance, you have to go to your wallet and do an estimate send for max balance, copy that amount and go back to the exchange to enter the amount and the address. Then back to your wallet, then back to the exchange. It’s an extra step.

1 Like

I just deposited 10k tgrin in my exchange account, and it was quite pleasant, since it only needed a single cryptographic (slatepack) interaction with my grin-wallet.

From the exchange’s perspective, it gives them the freedom to schedule and batch/aggregate the final transaction as they see fit. Aggregation with other client’s deposits and withdrawals benefits on-chain size and privacy


I suggest we don’t start making videos now. People should try it out and give feedback so that there is iterative improvement. If we ever agree on something at the end, then it’s the time to make a video (otherwise we risk people using some ideas prematurely).


what about i want deposit to exchange with ironbelly like on TO ,i create 10 grin slatepack and exchange give back QR and i finalize

That was the debate before with david. Each exchange currently integrates grin in their own way. This implementation uses the invoice flow for the deposit and afaik the only wallet implementation which supports invoices is the grin-wallet rust implementation

Let’s not turn this into an unsolvable battle about the “proper way :man_facepalming:” to send a grin transaction.

This code works. It’s written in Python and easy to understand, thus easily adaptable to other languages.

Is it perfect? Probably not, but it’s v1 and the code is on github. Will exchanges copy and paste it into their infrastructure? Probably not. I feat some might Does this allow testing deposit + withdraw with one of the multiple ways? Yes it does.

Should it include other ways as well? I think it should. That way users / exchanges / wallet developers / whoever have a single place to test and interact with different flows.


Yes, might as well support two withdraw buttons:
RSR withdraw and SRS withdraw.

1 Like

I can do that, but it will complicate the code. More specifically the deposit will then have different states which are unrelated, eg. in RSR i have kernel excess, in SRS i won’t have it, which probably means i have to store something else to notice that the tx landed on chain - maybe output, I’ll have to check the api. So whoever will be reading the code will need to understand for which flow something is stored in the db. It also means that the confirmation update will be a bit more complicated. If this post gets enough likes I’ll try to add a second deposit btn for srs. After i do that please don’t ping exchanges to say “here, implement that”. That’s how i implemented it, people need to go through the code and verify that the implementation is correct (deposit, withdrawal, confirmation update method, init_secure_wallet threading questions which were asked not long ago etc) or point out the problems so i can fix them

1 Like