Go Up Number!

This is the user manual for Go up Number! — a command line Bitcoin wallet for plebs, degenerates and revolutionaries.

gun is the world's most fully featured stand alone command line bitcoin wallet. The main design goal of gun is for it to be fun! It might also be secure and stuff but we'll have to see. gun is beta quality in all respects. Thanks in advance for making the sacrifice of your time (and perhaps coins!) while testing this software.

The defining feature of gun is the bet command which lets you do peer-to-peer betting by copy-pasting gibberish. Remember to only put in what you are willing to lose!

Features

  • ✅ Peer-to-peer betting
  • ✅ Easily setup with ColdCard
  • ✅ PSBT & Descriptor based wallet
  • ✅ BIP39 seedwords (incl. passphrase support)
  • ✅ Different output formats for writing tools against (JSON, tabs)
  • ✅ Easy to run inside VM or docker container
  • ☐ Single signer Taproot BIP86 signing (in progress 👷)
  • ☐ Threshold Multisig Schnorr signatures i.e. FROST (in research 🧪)
  • ☐ Make all HTTP requests through Tor with arti
  • ☐ Peer-to-Peer betting protocol using Taproot
  • ☐ Lightning payments with LDK
  • ☐ Demo of improved OP_CTV betting mailing list post on signet.
  • ☐ Coin selection issue#86
  • ☐ Fee bumping
  • ☐ WASM plugins/apps with wasmer
  • ☐ A user interface that is graphical

Architecture

gun is written in rust and uses the Bitcoin Dev Kit (bdk) to implement the underlying wallet functionality1. It needs a trusted esplora backend server to provide blockchain data and by default it uses mempool.space.

Contributing

gun is open source. It relies on the community to report and (if they can) fix bugs. Bugs aren't fun so please report them on the repository. Please help improve this book too.

1

Right now it uses a branch of bdk at llfourn/bdk.

Community

Join us on Discord

Install

Binary Releases

Binary releases should be available at the repository for some architectures (right now only linux-amd64). I haven't figured out how I want to go about this yet so it's better to just compile it yourself for now.

⚠️ The author of gun is the COVID QR code formally known as Lloyd "LLFourn" Fournier. He resides in Prison Island Australia and according to new legislation on the island he could be forced against his will to help the prison guards get access to his online accounts including GitHub. From there they can "alter" data to "gather evidence". The takeover can be granted without Lloyd being suspected of doing anything illegal. The target of the action can be someone else unknown to him and can even be unknown or anonymous to the guards.

So please make sure you check the signatures and more importantly prefer compiling the wallet yourself until he has figured out a more robust defense against this. Actions that publicly modify the code maliciously are far more obvious.

Import author key

Releases should be signed with this public key with this fingerprint:

28EF 6BC9 14AB BA2B AB98  B796 A270 93B5 4DA1 1F65

To verify a binary's signature import @LLFourn's key.

curl -sL https://gun.fun/llfourn.asc | gpg --import --import-options show
# ⚠️ CHECK IT MATCHES THE FINGERPRINT ABOVE

Download and verify

Download the binary and signature and verify like so:

curl -sL -o gun https://github.com/GoUpNumber/gun/releases/download/v0.6.1/gun-linux-amd64
curl -sL -o gun.asc https://github.com/GoUpNumber/gun/releases/download/v0.6.1/gun-linux-amd64.asc
gpg --verify gun.asc # check it verifies against the key with fingerprint above
chmod u+x gun
./gun --help

...verifying this is not fun so hopefully we'll figure out a way to do updating gun without doing this every time.

Compile yourself

Before compiling gun you need to install rust and cargo. Then,

git clone https://github.com/GoUpNumber/gun
cd gun
cargo install --path .
# Make sure ~/.cargo/bin is in your $PATH

If you have a nightly toolchain you can install it faster and download/compile less dependencies using:

cargo -Z avoid-dev-deps install --path .

The minimum supported rust version for gun is 1.58.0.

Upgrading from pre v0.6.0

If upgrading from a pre v0.6.0 release you will need to do the following:

  1. Make sure you have no open bets (gun bet listshould be empty).
  2. Make a note of how many coins you have gun -s balance.
  3. Backup your existing gun directory by moving it from its current location.
  4. Install the latest version of gun.
  5. Run gun setup seed --from-existing <path-to-backup>/seed.txt
  6. Run gun -s balance and to check your coins are there.
  7. Delete the backup

Setup

Use the setup command to do initial wallet. After that, you can use the config command to tweak the wallet's configuration.

gun setup

Setup a new wallet (or restore an old one).

The setup process will create the gun directory and populate it with:

  1. config.json: A configuration file.
  2. database.sled: The database directory containing protocol data and wallet data.

The only thing that is set in stone at setup time are the wallet's descriptors. These are written to the database.

Subcommands

Each subcommand sets up a wallet in a different way. They all take the --network option in addition to their specific options.

  • --network <bitcoin|regtest|testnet|signet>: sets which Bitcoin network we are using. The default is bitcoin (mainnet).

seed

Set up gun using BIP39 seed words. gun saves words to $GUN_DIR/seed.txt and reads them in each time you need to sign.

  • --from-existing <FILE>: reads existing BIP39 seed words from a file (or - to read from STDIN).
  • --n-words <[12|24]>: specifies the number of seed words to use (default: 12).
  • --use-passphrase: apply a BIP39 passphrase to the seed words when deriving private keys from it.

--from-existing and --use-passphrase will only restore coins from existing seed words if the coins were held with the same BIP39 passphrase. You cannot upgrade the security of existing seed words that didn't have a passphrase before with this command.

coldcard <path-to-sd-card>

You can use gun to output PSBTs to an SD card that you can then sign with your ColdCard. Once you've signed them on the device gun can broadcast them.

Step 1

First make a wallet export. On your device:

Advanced -> MicroSD Card -> Export Wallet -> Generic JSON

This should save a file coldcard-export.json to your SD card which contains the information gun needs to load your wallet.

Step 2 (optional)

In order to engage in protocols (e.g. betting) you'll also need to export some entropy that gun can use to generate keys that hold coins temporarily. On your device:

  1. Navigate to Advanced -> Derive Entropy -> 64-bytes hex
  2. Enter index 330
  3. Then, press 1 to export the resulting entropy to drv-hex-idx330.txt on your SD card.

💡 you can set this later using gun config protocol if you skip this now.

Step 3

Insert the SD card to your computer and initialize gun with:

gun setup coldcard /path/to/sd/card --import-entropy

or if you skipped step 2:

gun setup coldcard /path/to/sd/card

💡 If you encounter a ColdCard signing error "We require subpaths to be specified in the PSBT." then please update your firmware.

xkey <xpub|xprv>

You can initialize gun using an extended key descriptor:

gun setup xkey "[E83E2DB9/84'/0'/0']xpub66..mSXJj"

The descriptor is in the form [master-fingerprint/derivation'/path']xkey. gun will derive p2wpkh external keys at xkey/0/* and internal keys at xkey/1/* as is done in BIP84, BIP86 etc.

If you initialize it with an xpriv you will be able to sign transactions. The xpriv itself will be stored unencrypted in the database.

If you initialize with an xpub it will be watch-only until you also add a signer with gun config signer.

descriptor <external> [internal]

You can specify explicit miniscript descriptors for the wallet. gun will use external to derive receiving addresses and, if provided, use internal for deriving change addresses. This is a powerful option that allows you to set up custom multisigs etc.

The following is equivalent to doing xkey example above:

gun setup descriptor wpkh([AAB893A5/84'/0'/0']xpub66..mSXJj/0/* wpkh([AAB893A5/84'/0'/0']xpub66..mSXJj/1/*

You can use private key descriptors as well but remember that they will be stored in plaintext in the database. If you provide public key descriptors the wallet will be watch-only until you add a signer with gun config signer.

gun config

gun config lets you get and set configuration values. The command doesn't let you set every configuration value but it should be a more stable and safe than editing the config.json directly.

See gun config --help for all the configuration options.

Common usage

Set the esplora backend to your local esplora instance:

gun config blockchain base_url set http://esplora.local:3000

Configuration

The main configuration file is in ~/.gun/config.json and looks something like this:

{
  "version": "1",
  "network": "signet",
  "blockchain": {
    "type": "esplora",
    "base_url": "https://mempool.space/signet/api",
    "concurrency": 10,
    "stop_gap": 10
  },
  "signers": [
    {
      "kind": "seed-words-file",
    }
  ]
}

Configuration keys

network

Which network the wallet operates on:

  • bitcoin: The bitcoin Bitcoin.
  • testnet: the Bitcoin testnet.
  • regtest: A local regtest node.
  • signet: The signet testnet

blockchain

Configures the blockchain backend that the wallet will use.

At the moment only esplora style backends are supported (e.g. https://mempool.space/api and https://blockstream.info/api).

base_url

Sets the esplora HTTP API backend to make requests to

concurrency

How many requests to make in parallel to the esplora backend.

stop_gap

How many unused addresses should gun wait to find until it stops scanning more when syncing.

signers

signers is an array of signing methods that will be used to sign transactions. Most of the time this will have a single entry.

GUN_DIR

gun always needs to know its GUN_DIR directory. By default this $HOME/.gun. You can check what it is by running:

gun config dir get

You can override the default in two ways:

  1. By setting the GUN_DIR environment variable.
# Create a wallet with at ~/my_other_wallet
export GUN_DIR=~/my_other_wallet
gun setup seed
gun address new
  1. Or, by setting the -d flag
gun -d my_other_wallet setup seed
gun -d my_other_wallet address new

Backup and Recovery

In your gun directory (usually ~/.gun) there are a couple of files that will cause pain if you lose them.

seed.txt

seed.txt contains your secret BIP39 seed phrase if you setup the wallet using gun setup seed. If you lose seed.txt you lose all your coins. If someone else gets their hands on it they can take all your coins. seed.txt never changes so you only ever need to take one backup.

database.sled

If you lose database.sled you lose the coins from bets you have won or will win but haven't claimed yet. To guarantee you don't lose coins from this, you must backup database.sled after each bet. The best way to avoid loss of funds here is to claim your winnings in a timely manner.

Theoretically, it is possible to recover these with your main wallet but that hasn't been implemented yet.

Wallet Commands

Gun supports just enough wallet functionality to make it useful. Here are the commands:

gun address

Get and view addresses.

Synopsis

gun address <subcommand>

Subcommands

These commands interact with your wallet's external addresses. Internal addresses can't be seen.

You can see change address with coins in gun utxo list.

new

gun address new

Get a new address from the wallet. The wallet remembers that it has given out this address in the database.

last-unused

gun address last-unused

Gets a new address if it hasn't been used yet. Otherwise outputs a fresh address.

list

gun address list

List all addresses given out by this wallet. By default this only shows external addresses i.e. addresses produced by gun address new.

Options:

  • -a, --all: Show all addresses (internal & external)
  • -i, --internal: Show only internal addresses

show

gun address show <address>

Get more details about a particular wallet address.

gun balance

Get the balance of your wallet.

💡 Ah my brethren, these are the numbers you must make go up.

Synopsis

gun balance

But often you want to sync first

gun -s balance

Description

These are the meanings of the numbers:

  • confirmed: coins that are owned by this wallet and confirmed in the chain (but not in-use).
  • unconfirmed: coins that have been sent to your wallet but haven't been confirmed (and not in-use).
  • unclaimed: coins that you own but you haven't claimed -- if you lose your database you will lose them.
  • available: coins that are available to be used. This is just the total of the above.
  • locked: coins that are locked in some protocol execution (e.g. bet) you might get access to them or you might not!
  • in-use: coins that are being reserved for use in some protocol execution (e.g. a bet).

gun send

Sends coins to an address.

⚠️ Sending your coins gives them to someone else. This should be avoided wherever possible.

Synopsis

gun send [OPTIONS] <value> <to>

send 0.1 BTC to an address:

gun send 0.1btc bc1qhg0xqvrg50x50qnjqgfaa8jlle8uz7q3l2c5ud

Same as the above but with different denomination:

gun send 10_000_000sat bc1qhg0xqvrg50x50qnjqgfaa8jlle8uz7q3l2c5ud

Send all the available funds to the address:

gun send all bc1qhg0xqvrg50x50qnjqgfaa8jlle8uz7q3l2c5ud

Description

<value> should be an amount to send with denomination. Set it to all if you want to send all the coins in your wallet otherwise provide a specific amount. If the denomination is left out it is assumed to be satoshis. Underscores will be ignored. For example all the following mean one million satoshis:

  • 1000000sat
  • 1_000_000
  • 1M
  • 0.01btc
  • 10_000bits

💡Professional hackers use the denomination bits exclusively.

Options

--fee <fee>

Set the fee for the transaction.

You can choose from:

  • --fee=rate:4.5 set the fee to 4.5 sats-per-vbyte.
  • --fee=abs:500 set the fee to exactly 500 sats.
  • --fee=in-blocks:10 set the fee so it should get into the chain some time in the next 10 blocks.

The default is in-blocks:1 i.e. set the fee so it gets into the next block.

--print-tx

Print the tx as hex instead of broadcasting it. This will assume you're going to broadcast the tx yourself.

--bump-claiming

Spend coins from any bets that are currently in the claiming state. The claiming state means there is already a pending transaction spending them so this new transaction will replace-by-fee that previous transaction. You should make sure the feerate on this one is higher than the previous.

--no-spend-unclaimed

Don't spend coins you own outside of your wallet e.g. coins from bets you won. By default gun spends these coins back into your wallet with any chance it gets but this option stops that behavior.

--spend-in-use

Spend even the coins you are using for other things.

When you make a proposal or an offer the outputs used in the bet are considered to be in-use. This option allows the transaction to spend them (but doesn't force it to).

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

gun split

Split some coins into several outputs. This is useful when you want to have evenly sized outputs for making bet proposals.

gun split [OPTIONS] <output-size> <n>

Synopsis

Create 5 outputs of 0.05 BTC each.

gun split 0.05BTC 5

Options

--fee <fee>

Set the fee for the transaction.

You can choose from:

  • --fee=rate:4.5 set the fee to 4.5 sats-per-vbyte.
  • --fee=abs:500 set the fee to exactly 500 sats.
  • --fee=in-blocks:10 set the fee so it should get into the chain some time in the next 10 blocks.

The default is in-blocks:1 i.e. set the fee so it gets into the next block.

--print-tx

Print the tx as hex instead of broadcasting it. This will assume you're going to broadcast the tx yourself.

--bump-claiming

Spend coins from any bets that are currently in the claiming state. The claiming state means there is already a pending transaction spending them so this new transaction will replace-by-fee that previous transaction. You should make sure the feerate on this one is higher than the previous.

--no-spend-unclaimed

Don't spend coins you own outside of your wallet e.g. coins from bets you won. By default gun spends these coins back into your wallet with any chance it gets but this option stops that behavior.

--spend-in-use

Spend even the coins you are using for other things.

When you make a proposal or an offer the outputs used in the bet are considered to be in-use. This option allows the transaction to spend them (but doesn't force it to).

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

gun tx

Display transactions related to this wallet.

Synopsis

gun tx <subcommand>

Subcommands

For a transaction to be in the database it must spend to or from an address owned by this wallet.

list

gun tx list

Lists transactions associated with the wallet. This only keeps track of transactions that come in and out of the main wallet. For example, if you claim coins from a won bet to an unrelated address it won't show up here.

When you're waiting for a transaction to come in it can be handy to try:

gun -s tx list

show

gun tx show <txid>

Shows more details about a particular wallet transaction.

gun utxo

Display your unspent transaction outputs (UTXOs).

💡 Bitcoin is a game of UTXO acquisition. Get as many of these as you can.

Synopsis

gun utxo <subcommnd>

Subcommands

At the moment a UTXO will no longer show up here if it has been spent by an unconfirmed transaction. It will show up if it is on a

list

gun utxo list

List all your UTXOs.

show

gun utxo show <outpoint>

Show more details about a UTXO. <utxo> is given in txid:vout format e.g

gun utxo show 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:0

The above command shouldn't work unless that's your UTXO (it isn't).

GuN Betting

The main reason I developed gun was to be able to experiment with Bitcoin betting through social media and messaging apps. I originally wrote down the idea in How to Make a Prediction Market on Twitter with Bitcoin. At a high level this is how it works:

  1. The first person, the proposer, proposes a bet by choosing an event to bet on (including the oracle to use) and value to risk. The proposal data also contains the inputs they will use to fund the bet. See gun bet propose.
  2. Anyone who sees the proposal may make an offer in response by choosing how much they will risk to gain the proposer's coins and which outcome they want to bet on. See gun bet offer. The offer is fully encrypted and can only be decrypted by the proposer. In fact, it might not be an offer at all since you instead can use gun bet reply to send an encrypted message instead which will be indistinguishable from an encrypted offer.
  3. The proposer decrypts any offer they get and if they want to take the other side of the bet they broadcast the bet funding transaction. They may only choose one offer. See gun bet take.
  4. Both parties monitor the state of the bet by using gun -s bet list.
  5. When the oracle publishes the outcome the winning party gains ownership of the coins. When they're ready they can move the coins into their main wallet with gun bet claim.

Privacy

This protocol is tries to guarantee as much privacy as possible against an observer who sees the proposal, a list of offers and the blockchain. Such an observer will be able to figure out:

  1. What event the bet was on (they can see it in the proposal). This assumes the proposer is only using the input(s) for one bet but this might not be the case.
  2. Where the bet transaction is in the blockchain and which output is the bet output and whose change output is whose (they can see the proposal's inputs so they will be able to find it).
  3. Which inputs belong to the proposer and which belong to the offerer (the inputs belonging to the proposer are in the proposal).
  4. How much was bet by each party (they know how much the proposer is risking and the value in the bet output).
  5. Which change output on the bet transaction belongs to the proposer and offer respectively (the proposer puts their change in the proposal so the other one must belong to offerer).

They should be unable to determine:

  1. Which offer was taken or whether the offer that was taken was in the list of observed offers.
  2. Whether an offer is a real offer or an encrypted message or otherwise random gibberish.
  3. Who won the bet (they don't know who bet on what).

The basic summary of this is that privacy for the offerer is relatively good but for the proposer it is relatively bad.

It's important to note that even if you do the bet privately (via direct messages) a blockchain observer can easily distinguish bet transactions from normal transactions with this protocol. Here's an example transaction which shows what it looks like when a bet is claimed.

We're working on improving this in the future by using Taproot and (hopefully) OP_CTV.

💡 Another important aspect of privacy is that gun uses mempool.space by default as a backend. Connecting to it through Tor would improve privacy. Even better would be connecting to your own esplora node (and safety!).

Oracles

For this experiment I developed an oracle called olivia and deployed it at h00.ooo. olivia is badly documented and still changing a lot but you're welcome to try and run your own one.

To find events I developed a simple oracle explorer outcome.observer which can browse the events of an oracle. If you run your own oracle and want me to list it on outcome.observer make a PR to the repo.

GuN safety

The most obvious way of losing coins in a bet is betting on the wrong thing. But there are other more subtle and much less fun ways of losing your coins with gun.

The Late Bet

A malicious party may try to get a bet transaction to be confirmed after the event has already transpired and has resulted in their favor. For example, in a bet on a football match imagine if the proposer only takes the offer after the team they are betting has scored the first goal. The offerer must protect against this by canceling their offer before the game starts. See gun bet cancel.

The proposer must be careful about taking offers with a low transaction fee. If the transaction fee is low it may be stuck in the mempool until after the game starts. The offerer may then cheat by double spending his output if it looks like the game is going against him. Bet transactions enable replace-by-fee so either party can cancel it at this point by double spending one of their inputs (this is what gun bet cancel does).

Oracle cheats

The oracle may attest to the wrong outcome either maliciously or by accident. They may also do it publicly or covertly. There is nothing you can do about this other than call them out. Theoretically, you can also produce proof if the oracle misbehaved but this hasn't been implemented yet.

The oracle may also just disappear. If the oracle fails to attest the coins are stuck in the current protocol. This should improve in the future once we migrate to a Taproot based protocol.

💡 The oracle h00.ooo which I set up for this experiment is run by me. I will try and be accurate and timely with my attestations but the same caveat about Prison Island applies here.

Lost data

Losing data before you've won and claimed a bet is bad. Theoretically it's possible to recover the funds and bet but this hasn't been implemented yet.

see backup and recovery for more details.

gun bet oracle

Add, List and remove oracles from trusted list. For now, the security model for oracles is trust on first use (TOFU).

Synopsis

gun bet oracle <subcommand>

Subcommands

add

gun bet oracle add [options] <oracle-id>

Adds an oracle to the list of trusted oracles. For example the following command will make a request to https://h00.ooo and prompt you whether to accept it.

gun bet oracle add h00.ooo

Options

-y, --yes

Accept the keys the oracle gives you without asking.

list

gun bet oracle list

List trusted oracles.

show

gun bet oracle show <oracle-id>

Display details about an oracle. For example,

gun bet oracle show h00.ooo

TODD: document the output here

gun bet propose

Propose an event to bet on and how much you are willing to risk.

Synopsis

gun bet propose [options] <event-url>

For example

gun bet propose https://h00.ooo/random/2021-11-01T00:00:00/heads_tails.winner

Description

gun bets start with a proposal which set the oracle, event and value the proposer will risk on the bet.

The oracle and the event are embedded in the <event-url> like https://h00.ooo/random/2021-08-11T04:29:00/heads_tails.winner. Right now only https URLs are supported. The oracle for the bet is the host of the URL e.g. h00.ooo. In order to discover an oracle and event to bet on you can use an oracle explorer like outcome.observer. Note carefully that you can only bet on events with two outcomes.

The command will output the proposal as a # delimited string with the binary data encoded with base2048.

⚠️The binary data includes the on-chain input the proposer is using for the bet. These are unencrypted and viewable by anyone. Therefore, if you are posting the proposal publicly you must first ask yourself whether you really want these on-chain inputs to be linked to the identity that posts it.

Change

Currently it is possible to include a change output in the proposal where your excess over the value you want to bet will go. While the proposal is active these coins will be reserved for the bet and in-use. It is a good idea to use gun split to create an output with the exact amount of coins you want to risk as a proposer to avoid this. For technical reasons in the future change outputs for the proposer may be removed so you should get used to doing this now!

Options

-v, --value <value>

The value you want to risk on the bet. If you don't provide it you'll be prompted for it. Can be all to go "all in" with the coins in your wallet, otherwise an amount and denomination like 0.01BTC or 10000sat.

-t, --tags <tags>...

Add human readable tag to the bet as you create it.

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

gun bet list

List bets.

Synopsis

List your bets

gun bet list

Check and update your bets online and on-chain to see if if anything has changed first:

gun -s bet list

Description

The list of bets has the following fields:

  • state: The state the bet is, which can be:
    • proposed: You've proposed this bet.
    • offered: You've made an offer on this bet.
    • unconfirmed: The bet transaction has be broadcast but hasn't been confirmed.
    • confirmed: The bet transaction has been confirmed.
    • won: You've won the bet (but haven't claimed the winnings).
    • lost: You lost! You get nothing.
    • claiming: You've started claiming a won bet.
    • claimed: You've claimed the winnings successfully.
    • canceling: You've broadcast a transaction canceling the bet.
    • canceled: This bet was canceled before confirming either (it could have been canceled by you or your counterparty)
  • outcome-time: When the oracle expects the outcome to be known
  • in: the duration between now and outcome-time in short human readable form.
  • risk: How much BTC you stand to lose in this bet.
  • reward: How much BTC you stand to gain.
  • tags: human readable strings you can attach to a bet with gun bet tag
  • oracle: The oracle for the bet.
  • i-bet: which outcome you bet on.
  • short-id: the end of the event-id of the bet.

gun bet offer

Make an offer in response to a proposal.

Synopsis

gun bet offer [options] <proposal>

Without providing any options you'll be prompted for remaining details:

gun bet offer 0.005#h00.ooo#/random/2021-10-31T02:22:00/heads_tails.winner#۸პÂ௬ɦఅɗସઇȿჱ၄ƦফЩञǴऱλ૩ԉกƻ༓LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ǘØ

Go all in on tails and secretly communicate your confidence to the proposer

gun bet offer -m "bro I am so confident it tails atm" -c "tails" -v all 0.005#h00.ooo#/random/2021-10-31T02:22:00/heads_tails.winner#۸პÂ௬ɦఅɗସઇȿჱ၄ƦফЩञǴऱλ૩ԉกƻ༓LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ǘØ

Description

gun bet offer generates an encrypted offer in response to a proposal. You choose the outcome you want to bet on with --choice and the --value you are willing to risk to obtain the proposal's coins. The offerer also pays and chooses the fee of the bet transaction with the --fee option.

Security

After the proposer sees your offer they may take it at their own discretion. This includes taking the offer after the outcome of the bet is already known i.e. cheating. You must protect yourself against this by canceling the offer before a malicious proposer can take advantage of this.

💡 See GuN Safety

Privacy

Your offer should be indistinguishable from random gibberish to anyone but the proposer. This doesn't mean you have to post your offer publicly. In practice it's better to send the proposer a direct message with your offer unless you are trying to advertise the fact that you are using gun for your own satisfaction.

Choosing a fee

In general you should use a low fee for your offer unless you are betting very close to the event. Proposers will generally not discriminate based on the fee and would rather you put as much value in the bet as possible.

Options

-v, --value <value>

The value you want to risk on the bet. If you don't provide it you'll be prompted for it. Can be:

  • all to go "all in" with the coins in your wallet
  • match to match whatever the proposer is risking.
  • An amount and denomination like 0.01BTC or 10000sat

-c, --choice <choice>

The outcome you want to bet on occurring. If you don't provide it you'll be prompted for it.

-m, --message <message>

Attach a message in addition to the offer. If you are making the offer in a place with limited characters (like Twitter) the command will warn you if the message is too long.

-p, --pad <pad>

Pad the ciphertext to a certain length of bytes so observes can't use the ciphertext length to determine the contents. The default value is 385 which happens to the amount that will fit the base2048 encoded ciphertext in a single tweet. If you don't want padding just add -p0.

-t, --tags <tags>...

Add human readable tags to the bet as you create it. This is useful so you a can record a short note about where you found the proposal.

--fee <fee>

Set the fee for the transaction.

You can choose from:

  • --fee=rate:4.5 set the fee to 4.5 sats-per-vbyte.
  • --fee=abs:500 set the fee to exactly 500 sats.
  • --fee=in-blocks:10 set the fee so it should get into the chain some time in the next 10 blocks.

The default is in-blocks:1 i.e. set the fee so it gets into the next block.

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

gun bet inspect

Inspect an offer or proposal without interacting with it. This is convenience command for when want to see the details of an offer or proposal without being prompted to accept it.

Synopsis

gun bet inspect <subcommand>

Subcommands

proposal

gun bet inspect proposal <proposal>

Inspect a proposal. For example:

gun bet inspect proposal 0.005#h00.ooo#/EPL/match/2021-09-11/LEI_MCI.vs=MCI_win#ஐпმܪപઓܠফએઌΠڃฎƜపԬઉʐڣǧҵЕʕɉɏҵฤຂΘݸլၷ࿋னЉඇໜЈবɇοȾಋѻݙȁ࿅ผɸØ

offer

gun bet inspect offer <bet-id> <offer>

Inspect an offer in response to one of your proposals. The following example won't work because you don't have the key to decrypt the offer.

gun bet inspect offer 33 ପҊڧოӵիПܬߧɓئҙݒතʘȄݮɑရཪჟݿྋଟආ࿊ޕȌϐ௸ɫӂDžʉཌɭϽඨओȅଗɡވइဟЫښಊჱߓघɔȱߝŨdžชʌȋȓƥളʯǡಅਠۍॠܡԇȪݯНପżଠЋघјʝഭӏրঈॽဘɷγȌళളஜबܠܟၺѧջไ༕ڎʬƂǭදܖɓਐݢɗජฬЩݳރݺѮʃȦҰƬஹԭގఏȽම௵ڄޅ௵ੜӹɓԧڬঙਬɩצཪၛனʡҘɻ৺Ƨō

gun bet reply

Reply with an encrypted message rather than an offer to a proposal.

Synopsis

gun bet reply [OPTIONS] <proposal>

Slide into someone's DMs:

echo "follow me so I can DM you" | gun bet reply  0.01#h00.ooo#/random/2021-09-09T08:14:00/heads_tails.winner#ഩǠɢѩչਠനՎȆଞગਐעͻڢѓӫҹڣလߛϊرКɏҵฤຂΘݸլၷ࿋னЉඇໜЈবɇοȾಋѻݙȁ࿅ผɱƂइŏDZێեЯಐۇฝဆসϑ࿖ɀჵਊၒβԼјஊڠၮɈ།

Options

-m, --message <message>

Set the message for the reply with an argument. If this is omitted it will read the message from stdin.

-p, --pad <pad>

Pad the ciphertext to a certain length of bytes so observes can't use the ciphertext length to guess the contents. The default value is 385 which is number of bytes for that will fit in single tweet when base2048. If you don't want padding just add -p0.

gun bet take

Take an offer to one of your proposals.

Synopsis

gun bet take [options] <id> <encrypted-offer>

Description

gun bet take displays details about an offer and prompts you to take it or not. It is up to the user to figure out what proposal this offer was in relation to. You may use gun bet list to see the ids of all your proposals.

Taking the offer will prompt you to broadcast the bet transaction with the bet output.

Security

Try to avoid taking an offer close to when an event transpires. If the offer's fee is low the bet transaction may not be confirmed until after the event has transpired. A cheating offerer may then try to cancel the bet if things go against them before it confirms.

Options

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

--print-tx

Print the tx as hex instead of broadcasting it. This will assume you're going to broadcast the tx yourself.

gun bet show

Show more details about a bet.

Synopsis

gun bet show [options] <id>

Options

-r, --raw

Print the raw entry in the database. This should be used for debugging only.

gun bet forget

Delete a bet from your local database.

💡There are some bets you'd rather forget about but this command can't do anything about that.

Synopsis

gun bet forget [bet-ids]...

Description

This command just deletes a bet from your local database. This is obviously dangerous depending on the state of the bet so gun bet forget will stop you from deleting your coins or warn you when you need to be careful.

⚠️ Unless you're sure you understand the impact of forgetting a bet use gun bet cancel instead.

gun bet cancel

Cancel a bet by broadcasting a double spending transaction.

Synopsis

gun bet cancel [options] [bet-ids]...

Description

To fully cancel a bet you double spend one of your declared inputs to the bet. Either the offerer or the proposer can cancel a bet before it has been confirmed.

On the proposer's side canceling is just good etiquette. By canceling the proposal everyone who has made an offer doesn't have to make a transaction canceling their offer. If a proposer is sure that no one will make an offer to a proposal they can instead forget about it.

An offerer must cancel any offer they've made that hasn't been taken (or canceled) prior to the outcome time.

To cancel a bet it must be in the proposed, offered or canceling state. You can cancel many bets at the same time. If one of the bets being canceled is in the canceling state you must make sure that the feerate set by --fee is higher than the previous canceling transaction's fee.

💡 See GuN Safety

Options

--print-tx

Print the tx as hex instead of broadcasting it. This will assume you're going to broadcast the tx yourself.

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

--fee <fee>

Set the fee for the transaction.

You can choose from:

  • --fee=rate:4.5 set the fee to 4.5 sats-per-vbyte.
  • --fee=abs:500 set the fee to exactly 500 sats.
  • --fee=in-blocks:10 set the fee so it should get into the chain some time in the next 10 blocks.

The default is in-blocks:1 i.e. set the fee so it gets into the next block.

gun bet claim

Claim your winnings.

Synopsis

gun bet claim [options]

Description

Creates a transaction spending any coins you own from bets and sends them to an internal wallet address.

Note that you can use send to do this if you want to send the coins to an arbitrary address ? rather than your own wallet.

Options

--fee <fee>

Set the fee for the transaction.

You can choose from:

  • --fee=rate:4.5 set the fee to 4.5 sats-per-vbyte.
  • --fee=abs:500 set the fee to exactly 500 sats.
  • --fee=in-blocks:10 set the fee so it should get into the chain some time in the next 10 blocks.

The default is in-blocks:1 i.e. set the fee so it gets into the next block.

--print-tx

Print the tx as hex instead of broadcasting it. This will assume you're going to broadcast the tx yourself.

-y, --yes

Skip all [y/n] prompts by just answering yes to all of them.

gun bet tag

Tag a bet with a short string.

Synopsis

Add a tag

gun bet tag add <bet-id> <tag>

Remove a tag

gun bet tag remove <bet-id> <tag>

Description

Tagging helps you remember how a bet originated. It can also be done at bet creation time with the --tags flag.

Offer tutorial

This is a tutorial that focuses on how to make an offer to a proposal which is a wacky string like:

0.005#h00.ooo#/s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win#ৠöഓཀসƵ୯รແྋŸǢঊಹహĈၐ೨ø໕Ǜœબ೮LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ƸØ

Accounts like @GoUpNumber consistently make proposals and look for the best offers. To see how to make proposals yourself see gun bet propose.

Requirements

This tutorial is for people who want to try out betting with gun but don't want to RTFM too much. You should meet the following criteria:

  1. Comfortable with command line applications.
  2. Don't mind losing coins due to bad bets or technical malfunctions. You are happy to consider it a donation to science.
  3. Able to report bugs on GitHub.

Install

Follow instructions in install and setup.

The simplest setup you can do is just running:

gun setup seed

Put some coins in your wallet

💡 It's a good idea to coin join your coins before sending them to gun (or doing anything really!). If you don't feel comfortable betting coins at this stage you can join the fun by using gun bet reply to post an encrypted message that looks like an offer instead.

To get a wallet address run:

gun address new

And you'll see an address. Send a small amount of coins to it if you're just getting started.

To check when the coins come in you can do gun -s balance or gun -s utxo list or gun -s tx list. The most important thing is adding the -s flag so gun checks the blockchain before displaying the result. Without -s the command will just display what's already in the database.

Find a Proposal

A proposal contains the event that will be bet on and the amount the proposer is willing to risk on it. To promote this experiment @GoUpNumber is frequently posting proposals on twitter and on their Discord channel (invite link).

A proposal looks like this:

0.005#h00.ooo#/s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win#ৠöഓཀসƵ୯รແྋŸǢঊಹహĈၐ೨ø໕Ǜœબ೮LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ƸØ

It contains several parts split up by the # character.

  1. 0.005: The amount in BTC that is being risked.
  2. h00.ooo: The oracle in this case is h00.ooo.
  3. /s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win: The event the proposal is on. This can be read as "Whether Manchester United beats Leicester City in their EPL (English Premier League) match on 2021-10-16". Note that gun can only bet on events with two possible outcomes.
  4. ৠöഓཀসƵ୯รແྋŸǢঊಹహĈၐ೨ø໕Ǜœબ೮LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ƸØ: cryptographic input to the bet. A public key and list of inputs.

Trust the oracle

Before betting with h00.ooo we have to tell gun we trust it. To trust h00.ooo run:

gun bet oracle add h00.ooo

It's fine to accept whatever you are given at this stage.

Making your offer

When you've found a proposal you want to bet on make an offer to it. We'll make an offer to the proposal above. We must decide whether you think Manchester United will win or not and how much you are willing to risk.

Run the offer command like so:

gun bet offer 0.005#h00.ooo#/s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win#ৠöഓཀসƵ୯รແྋŸǢঊಹహĈၐ೨ø໕Ǜœબ೮LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ƸØ

You'll be prompted to choose:

  1. Which outcome you want to bet on. In this case true if you think Manchester United will win otherwise false.
  2. How much you want to risk to get the 500,000 sats on offer in the proposal. You can bet as low as 1000 sats to give yourself 1 to 500 risk reward ratio. @GoUpNumber will always take it if they don't get any better offers.

The base2048 gibberish you get as output is encrypted so that only the proposer can read it. Copy it and paste it somewhere the proposer can see it e.g. reply to the tweet, send them a direct message etc.

💡 Consider posting the offer under a colorful pseudonym so not even the proposer knows who they're betting with!

Changing the default fee

As the offerer you choose the fee that the bet transaction will pay. The default fee gun chooses is quite high (it attempts to get it into the next block i.e. --fee in-blocks:1). This is inappropriate for most offers unless they are being made last minute. For example if you are betting on match being played a week from now use something like --fee in-blocks:30 so that it should confirm some time in the next 30 blocks after the proposer broadcasts it at the current fee rate.

gun bet offer --fee in-blocks:30 0.005#h00.ooo#/s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win#ৠöഓཀসƵ୯รແྋŸǢঊಹహĈၐ೨ø໕Ǜœબ೮LJЧ༃ཆɁঢӛႱ၃ಢͱธྈͰଢƿɧƶവϳॻŹဪ໖ƸØ

Monitor you offer

The easiest way to monitor the offer is to do:

gun -s bet list

Immediately after you've made the offer it will be in the offered state. When/if the proposer has taken your offer it will transition to the unconfirmed state and then eventually the confirmed state when it ends up in the chain. If the proposer chooses a different offer it will end up in the canceled state (or if you use gun bet cancel to cancel it).

Take note of how long there is until whatever you are betting on takes place. If the bet is still not in the confirmed state a just prior to the event starting you should run gun bet cancel <bet-id> where bet id is the number in the first column of the gun bet list output. If you are forced to manually cancel your offer you should consider avoiding betting with that proposer again as it is bad manners for a proposer to leave this to you.

Claiming your winnings

If it doesn't get canceled, eventually your bet should go from the confirmed to the won or lost state. Just keep running gun -s bet list to check this.

If you go into the lost state you don't need to do anything further. Thank you for your heroic sacrifice.

If you go into the won state you can use gun bet claim to put the coins back into your main wallet. Alternatively, gun send will always spend any won bets you have open by default.

There is no strict time limit to claiming won bets but if you have data loss while the bet is in the won state the coins will be difficult to recover (See backup and recovery).

Troubleshooting

Oracle hasn't attested

If you're stuck in confirmed long after the event was due the oracle may have messed up. The easiest way is to find the event on outcome.observer but you can also manually visit the URL. For example go to https://h00.ooo/s/EPL/match/2021-10-16/LEI_MUN.vs=MUN_win in your browser and see if the attestation field is filled in.

⚠️ In the current protocol, if the oracle disappears of fails to ever attest to the event you have both lost your coins. The oracle h00.ooo is run by LLFourn so in this case you can blame him for that!

The Oracle has attested to the wrong thing

All you can do is publicly shame the operator of the oracle.

Something else

Report this as a bug on GitHub or contact LLFourn in some other way.

Bet Protocol Technical Overview

💡 You don't have to read this. This is only for people who are interested in how the betting protocol actually works.

The protocol takes two messages and one on-chain transaction.

The first message, the "proposal", contains a public key (P1) which the second message, the "offer", will be encrypted under. The offer contains a public key (P2) and a ciphertext. The offer is encrypted by deriving a key from the Diffie-Hellman key between the two keys.

The two public keys are also used to construct the bet output which holds the coins until the outcome has been decided by the oracle. The script locking the coins is a 1-of-2 with keys like:

1-of-2(P1 + O1, P2 + O2)

Where P1 and O1 represent the public key of the proposer and the outcome they are betting on respectively (P2 and O2 represent the same for the offerer). If the oracle releases O1 then the proposer will get the coins otherwise if the oracle releases O2 the offerer gets them. The Diffie-Hellman keys is also used to produce secret randomness (R1 and R2) which both parties use to randomize the output script. So the output script is really something like:

1-of-2(P1 + O1 + R1, P2 + O2 + R2)

This randomization means the output keys can't bet associated with the proposal and offer keys (P1 and P2). The order of the keys in the 1-of-2 is also randomized.

When the winner learns the secret for O1 or O2 from the oracle they can claim the coins because they can construct the secret key for P1 + O1 + R1 or P2 + O2 + R2. Note there is no real hurry for them to do so except that the coins can be recovered from seed words once they have been properly claimed.

Formatting Output

Apart from the default human readable style format any command can be modified to format its output in one of two more computer readable formats.

JSON -j, --json

This format is output for reading into other software. Coin amounts are formatted as sats and DateTimes will be formatted as UNIX timestamps.

gun -j <command> .. will output JSON.

The following will output how much you've lost in bets

gun -j bet list | jq 'map(select(.state == "lost").risk) | add'

Tab separated -t, --tabs

This format it useful for UNIX command line tools because it tab separates each field so things like cut(1) just work.

The following will output how much you've lost in bets

gun -t bet list | awk '$2 == "lost"{ lost += $5 } END { print lost }'