Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

LiveWallet - Part 2 - Generate addresses

002-generating-keys.livemd

LiveWallet - Part 2 - Generate addresses

Mix.install(
  [
    # to create bitcoinSV transactions, including keys and scripts
    {:bsv, "~> 2.1"},
    # making http requests
    {:httpoison, "~> 1.8"},
    # to work with JSON
    {:jason, "~> 1.3"},
    # to work with Handcash.io's API
    {:handkit, "~> 0.2.0"},
    # to work with bitcoinSV miners
    {:manic, "~> 0.1.0"},
    # to generate qr codes
    {:qr_code, "~> 3.0.0"},
    # to add functionality to Livebook
    {:kino, "~> 0.12.2"}
  ],
  config: [
    bsv: [
      network: :main
    ]
  ]
)

Let’s regenerate an Extended Key from a seed phrase

Let’s start with the seed phrase we generated in Part 1.

> Note: a Wallet has at least one Extended Key from which to create many of the keys it will use. Here, we’re going to re-generate our Extended Key from Part 1, then keep going.

Paste the seed phrase into the mnemonic text field input below.

mnemonic_input = Kino.Input.text("mnemonic")
mnemonic = Kino.Input.read(mnemonic_input)
seed = BSV.Mnemonic.to_seed(mnemonic)
extkey = BSV.ExtKey.from_seed!(seed)

Rather than using the seed phrase, you could use the exported xprv Extended Key from Part 1.

# If you have an `xprv` file from Part 1, it can also be used to regenerate an Extended Key, similar to how a seed phrase can be used to regenerate an Extended Key.
# extkey = BSV.ExtKey.from_string("xprv...")

At this point, we have re-generated an Extended Key from a seed phrase or by loading a xprv.

We can use the Extended Key to generate many addresses.

Kino.Input.checkbox("Have you re-generated an Extended Key?")

Here, we regenerate a key from a WIF instead

You can use the WIF (Wallet Import Format) from Part 1 to import a key.

# Create an input you can paste the WIF into
wif_input = Kino.Input.text("WIF")
wif = Kino.Input.read(wif_input)
{:ok, private_key} = BSV.PrivKey.from_wif(wif)

Generate a public key from the private key.

public_key = private_key |> BSV.PubKey.from_privkey()
public_key |> BSV.Address.from_pubkey()

In this section, we started with a WIF, which can be used to recreate a Private Key.

for i <- 0..9 do
  path = "m/44'/236'/0'/#{i}'"
  child = BSV.ExtKey.derive(extkey, path)
  address = BSV.Address.from_pubkey(child.pubkey)
  "#{path} = #{BSV.Address.to_string(address)}" |> IO.puts()
end

A list of 10 addresses should be displayed. Select one of them to use for this exercise; to receive bitcoin at.

Choose an address from above (any one), and note both the a) address and the b) derivation path below. The derivation path is required in order to generate the private key for the correct, corresponding public key.

address = "ADDRESS_GOES_HERE"

Generate a QR code to scan

{:ok, svg_content} =
  address
  |> QRCode.create(:high)
  |> QRCode.render()

File.write!("qr_code.svg", svg_content)
# this `qr_code.svg` file is written tfo the root path of your Livebook installation

Display the qr_code.svg file we just generated.

# And here, we read that file and display it in Livebook.
content = File.read!("qr_code.svg")
Kino.Image.new(content, :svg)

Generating HD keys

This diagram outlines the overall flow generating a wallet and HD (hierarchical deterministic) keys.

graph TD;

  ComputerGeneratedRandomNumber-->MnemonicSeedPhrase-->Seed-->ExtendedKey-->DerivativeKeys-->|the general example|DerivativeKey;
  DerivativeKey-->Keypair-->PrivateKey

  DerivativeKeys-->|specific addresses...|m/44/0'/0'/1-->Keypair1--->Address1;
  DerivativeKeys-->m/44/0'/0'/2-->Keypair2--->Address2;
  DerivativeKeys-->m/44/0'/0'/3-->Keypair3--->Address3;
  DerivativeKeys-->m/44/0'/0'/4-->Keypair4--->Address4;
  DerivativeKeys-->m/99/1'/2'/3-->Keypair5--->Address5;


  Keypair-->PublicKey
  PublicKey-->|RIPEMD160|Address

Address is what users typically see and send bitcoin too.

Sometimes, just the Public Key is used.

Sending bitcoin, Receiving bitcoin

A Sender creates a Transaction and selects to Address to send to.

The Address is derived from a Public Key, which corresponds to a Private Key that the Receiver has.

So, the Receiver can use the Private Key to unlock the Transaction that the Sender sent.

graph TD;
  Sender-->Transaction-->Address;
  Receiver-->|seeks to unlock|Transaction
  PrivateKey-->|unlocks|Transaction
  Address-->|is derived from |PublicKey-->|corresponds to |PrivateKey
  Receiver-->|has|PrivateKey

Seed phrases, WIFs, Keypairs, Private & Public Keys, and Addresses

graph TD;
  WIF-->Keypair
  SeedPhrase-->Seed-->HDKeys-->Keypair-->PrivateKey-->PublicKey-->Address;

To review

We started with the a a) WIF or b) seed phrase for the wallet we created in Part 1.

Based on that WIF, you can generate a keypair; a Private and Public Key.

Or, based on a seed phrase, you can generate a “seed”, and from that seed generated 10 keypairs in a row, at different derivation paths.

At this point, you can generate an address. That address might be easier to scan as a QR code, so we did generated one.

If your address is for main network, you will be able to receive bitcoin (BSV) at this address.

The address created was derived from the Public Key, and the Public Key has a corresponding Private Key.

After receiving bitcoin to the address, a transaction will exist on the bitcoin blockchain. This transaction has some amount of satoshis in it. You’ll need the Private Key to sign that transaction and transfer it.

This diagram conveys how you can generate an address from a a) seed phrase or b) WIF.

> This is the end of Part 2.

Read Part 3 - Receiving bitcoin at an Address

Read Part 1 - Generate an Extended Key