Grin contracts
NOTE: The software has bugs and it may lose your funds. The author is not responsible for any damage it may cause. Use this in a VM on testnet wallet.
I should mention that members of OC have not looked at this attempt yet, they were, like the community, informed I’m going to make a prototype, but I’m sharing this with the community and OC at the same time.
This document attempts to explain the contract terminology as well as how to test a prototype including exchange deposit/withdraw. Every transaction that contains 2 parties goes through the same steps. First the initiator creates a new contract (often referred to as a Slate) which is then signed by the counter party and finally, signed by the initiator. This is the same regardless if the flow is regular (payment) or invoice. These two flows can be joined to provide for a unified contract building experience: new -> sign -> sign
.
We have 2 actions here namely new
and sign
. I think it’s good if we completely detach the contract building from its transport to the counterparty as it allows for seamless composition of functionality. This is also why there is no notion of a “destination” in the contract new
and sign
functions. Instead, we merely pick who we want to encrypt the slate for.
The prototype builds transactions a bit differently than they currently are. Some notable differences are:
- A transaction is a payjoin by default
- Each party contributes for their own fees, including for the kernel - each pays
kernel_cost * (1/num_participants)
- By default transactions are late-locked (early-locking is not yet supported)
Prototype implementation
Installation
- Clone my git repo
git clone https://github.com/phyro/grin-wallet.git
- Switch branch
git checkout simple_contracts
- Build branch
cargo build
- Go where the binary is located
cd target/debug
- Call commands with
./grin-wallet --testnet ...
NOTE: If you lack some dependencies and can’t build the project, vegycslol shared with me a configuration to get these over nix
. We first install Nix package manager and then the dependencies through by doing:
- run
sh <(curl -L https://nixos.org/nix/install) --daemon
and install nix - open a new shell session
- run
git checkout simple_contracts
, go inside thegrin-wallet
directory and typenix-shell
. This will download all dependencies needed to build grin-wallet (and grin) includingtor
. It also puts you inside a nix-shell where all these dependencies are available. From there,cargo build
should work.
In case anyone is concerned about what it is they are going to build, the changes are on this branch and the nix packages are defined in default.nix file. The code is not a great example of engineering, but this would be improved. Run in a wallet where you have no mainnet accounts/value (for safety!) and only test against the testnet. This functionality only supports the main/default wallet account at the moment. Payment proofs are also not supported right now. I’d prefer if contracts only supported early payment proofs by @tromp because they seem like a strictly superior variant and on top of that, they fit well in this design due to their ability to work in both directions.
Example usage
For demonstration purposes, I’ll shorten the addresses to save some space when using the commands. The commands below assume you have a testnet grin node running so you can send the transaction on the network. Suppose we have two parties:
- party A: tgrin1y4rqquklzykma8fjyksfhcmqa
- party B: tgrin1y4rqquklzycaa8fjyksfhcmqb
For now we can test the contract building with
##### Payment flow
# 1. Party A creates a new contract and encrypts it for B
./grin-wallet --testnet contract new --send=0.2 --encrypt-for=tgrin1y4rqquklzycaa8fjyksfhcmqb
# 2. Party B signs it and automatically encrypts it back for A
./grin-wallet --testnet contract sign --receive=0.2
# 3. Party A signs it at which point it's broadcasted to the network
./grin-wallet --testnet contract sign
# Party A didn't need to again describe how much they send/receive,
# because already did it when calling 'new' with --send=0.2
##### Invoice flow
./grin-wallet --testnet contract new --receive=0.2 --encrypt-for=tgrin1y4rqquklzycaa8fjyksfhcmqb
./grin-wallet --testnet contract sign --send=0.2 # party B signs
./grin-wallet --testnet contract sign # party A signs
# Note that the flows above look the same. It's important to understand
# the fact that we have signed a transaction for contract revocation.
##### Self-spending by party A
./grin-wallet --testnet contract new --send=0 --num-participants=1 --encrypt-for=tgrin1y4rqquklzykma8fjyksfhcmqa
./grin-wallet --testnet contract sign
As mentioned, by default these transactions are made such that every party contributes for their own fees and they are payjoins by default. It is possible to opt out of a payjoin by calling with --no-payjoin
. At the moment, every party creates exactly 1 output. This may become configurable to be able to create self-spends that look like other regular 2-2 contracts. We can also tell the software to use specific commitments by providing --use-inputs
flag e.g.
# Self-spending consolidation (we enumerate which commitments we want to use as inputs)
./grin-wallet --testnet contract new --send=0 --num-participants=1 --encrypt-for=tgrin1y4rqquklzykma8fjyksfhcmqa --use-inputs=084fb2500a00f19138600f2d94c41f29f80852f7744c26c1a3e83c2af5ee83b3fc,08a7a703388a82dd735c259a55b11cf66e8ce254b2c0745c34173f432b58ba9204
./grin-wallet --testnet contract sign
We also have revocation of a contract (safe-cancel tx) which reverts the expected transaction changes as well as double-spends an input through a 1-1 self-spend if inputs were contributed
./grin-wallet --testnet contract revoke --tx-id=68
To observe what’s going on, ./grin-wallet --testnet txs
and ./grin-wallet --testnet outputs
are your friends.
Here at the end of the code is a quick example of contract API functionality in python.
Later on, I think it would make sense to add a few more commands e.g.
# Listing contracts - lists open contracts by default (either setup or sign performed, but not confirmed)
./grin-wallet contract list
./grin-wallet contract list --all
./grin-wallet contract list --filter=signed,unconfirmed
# Viewing contracts
# If we have received a contract we want to know what it looked like and what we contributed to it. This
# way we can review the contract and send it again to the person if they lose the slatepack. This is still
# something that would need to be defined what it would look like.
./grin-wallet contract view --id=1
# Transporting contracts
./grin-wallet contract transport --tor --grin-addr=tgrin1y4rqquklzycaa8fjyksfhcmqb
To obtain 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”: “”}’ http://faucet.testnet.grin.lesceller.com - 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
Testnet exchange integration
@vegycslol was kind enough to integrate this flow on his testnet exchange so anyone can test sending/receiving from/to the exchange - you can of course opt-out of a payjoin when interacting with the exchange. Feel free to play around with this.
Far from finished and not to be used with wallets that carry value!
I’d like to remind everyone that this is not close to being finished or ready to use with wallets that also hold real coins. We’d need to agree on the interface, try out things, receive feedback, have a really careful and long review to find any potential mistakes and/or attacks and potentially bump the slatepack version because now parties pay for their own parts. Please Let us know of any feedback you may have and we’ll discuss this. I suggest any discussion around this are either on the forum (if the comment doesn’t expect a quick answer) or, preferred, on keybase for a smoother interaction.