Skip to content

Instantly share code, notes, and snippets.

@pinheadmz
Last active May 25, 2022 05:54
Show Gist options
  • Select an option

  • Save pinheadmz/a07d7e64c37414e0b1ba8c360d01c963 to your computer and use it in GitHub Desktop.

Select an option

Save pinheadmz/a07d7e64c37414e0b1ba8c360d01c963 to your computer and use it in GitHub Desktop.

Claiming Handshake Faucet Coins with Multisig

For a deep dive into the mechanics of the faucet, airdrop and claims, read this article.


Preface

If you are claiming a Handshake faucet payout with a multisig address, you should have already generated that address by following these steps. Those notes should have instructed you (and all of your multisig participants) to generate individual keys, and then combine them into a Handshake multisig address using the faucet tool.

For this guide, we'll imagine Alice, Bob and Charlie have followed these steps. Each participant should have a file that resembles this layout:

Seed phrase (WRITE DOWN AND KEEP SECRET):
deliver coral upset label fence caution retire senior horse twin room ice below giant coral patch cousin float guide exhibit maple milk soft foot

Address:
hs1qammn2yfc4v6cfn3903xy20ga8dh3krkg3fnnt

Xpub (for use with watch-only wallets):
xpub6CyGFH8QHNbH36UMRPGXuZj7fBTjcjUeGu61ueZgAUUh6XYyN5gTxduaSLf8E7Z27wWdKoZ3aKAuQBCp3FVDvst2uiBgKd562x43oco243a

Private key:
L5j2yKnvYbejSiLEqkcTa8TXFC9JiJsRXKUuE9ZQtZfGRv8tA5Yj

Public key:
022ac13780c2e3f9351e0ec98c8cb152ea6046c61cbc65cadaddfc0fc591803d63

After combining all 3 keys with faucet-tool, a mainnet multisig address should have been generated resembling the example below:

Multisig address:
hs1q0h4nlt4xs8t06634hncptkpchmvehf5r6kt7yr5mxkxu7tlx5lyqf7qcpg

Is the address in the mainnet faucet address tree?

The easiest way to confirm that your address is included in the mainnet faucet payout is by checking the tree on github:

https://github.com/handshake-org/hs-tree-data/blob/master/proof.json

This is a plaintext list of all faucet addresses. Search for your multisig address and confirm it is in there. Before mainnet launch, this list will be merkelized and the tree root will be embedded in the consensus code. If you're curious, that commitment is here.

How do I claim the faucet coins?

This is a three-part process:

Create an airdrop transaction

Technically, the airdrop is a separate set of payouts from the faucet, but they are both claimed the same way. A faucet payout transaction just generates coins to a Handshake address. There is no signature involved. This also means anyone can submit any faucet payout transaction for any faucet address: the money always goes to the recipient's address, but anyone can submit this transaction to the network.

To create an airdrop transaction, use hs-airdrop with your fuacet address. There is a lot of output here, but all we need is the last base64 blob:

$ hs-airdrop hs1q0h4nlt4xs8t06634hncptkpchmvehf5r6kt7yr5mxkxu7tlx5lyqf7qcpg

Downloading: https://github.com/handshake-org/hs-tree-data/raw/master/proof.json...
Attempting to create proof.
This may take a bit...
Downloading: https://github.com/handshake-org/hs-tree-data/raw/master/faucet.bin...
Creating proof from leaf...

JSON:
{
  "index": 1091,
  "proof": [
    "500a533826912757d1a6e8c79fc5cb6b2de9480740759fcc3ef75bacabe81a57",
    "04031ca9a5b68a4b74f33231075efcffefcb4c53de96c7a22ab11444296225a4",
    "49a7fed7114d00b95657c232915ca14256eb4befbf3cab2587706cdedaaa29d3",
    "180801bd8670558a3f2d5d8bd4a0f37ef0ad55312346ca97ff96abaec84f60d8",
    "4dd93a4fd5e5ddfe4c4b2e6624a19516c7af0f2a9be49c4a8c46a26ee728b27b",
    "bb68b7cb594d424346ffceca269b1aa30274b70e9d66d5647d92f19cdb61a6d3",
    "9a5005f8db05f79b7a6fb563f7f4e08d4f70fdf5b04a71d823e829f1d0d5a1d7",
    "c7279754bb5256b4df75d949706fc81d3c5dc88ef3efe9ef2ddf9e638c4e9185",
    "a42405cba46b95adfacb7f933b34b7e717ad696a1043d68d35f3384a51b90ae8",
    "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8",
    "7f2ff3e0614c23afb4b72abc18eddd95e2a58662ad82a56e3e6b66a488bd66e7"
  ],
  "subindex": 0,
  "subproof": [],
  "key": {
    "type": "ADDRESS",
    "version": 0,
    "address": "b291111a371d7c59c0147fa6241a808f21a7e5cd09e5684a970d93cdf3e0b922",
    "value": 10000500000000,
    "sponsor": true
  },
  "version": 0,
  "address": "b291111a371d7c59c0147fa6241a808f21a7e5cd09e5684a970d93cdf3e0b922",
  "fee": 500000000,
  "signature": ""
}

Base64 (pass this to $ hsd-rpc sendrawairdrop):
QwQAAAtQClM4JpEnV9Gm6MefxctrLelIB0B1n8w+91usq+gaVwQDHKmltopLdPMyMQde/P/vy0xT3pbHoiqxFEQpYiWkSaf+1xFNALlWV8IykVyhQlbrS++/PKslh3Bs3tqqKdMYCAG9hnBVij8tXYvUoPN+8K1VMSNGypf/lquuyE9g2E3ZOk/V5d3+TEsuZiShlRbHrw8qm+ScSoxGom7nKLJ7u2i3y1lNQkNG/87KJpsaowJ0tw6dZtVkfZLxnNthptOaUAX42wX3m3pvtWP39OCNT3D99bBKcdgj6Cnx0NWh18cnl1S7Ula033XZSXBvyB08XciO8+/p7y3fnmOMTpGFpCQFy6Rrla36y3+TOzS35xetaWoQQ9aNNfM4SlG5CugOV1HAJuVDsuirLrBgmdqh0eXfR3ePd4f6q0XN8S/jqH8v8+BhTCOvtLcqvBjt3ZXipYZirYKlbj5rZqSIvWbnAAAsBAAgspERGjcdfFnAFH+mJBqAjyGn5c0J5WhKlw2TzfPguSIABUBsGAkAAAEAILKRERo3HXxZwBR/piQagI8hp+XNCeVoSpcNk83z4Lki/gBlzR0A
Submit the airdrop transaction

Like the above output says, submit the airdrop to the network by sending that command to your hsd full node:

$ hsd-rpc sendrawairdrop QwQAAAtQClM4JpEnV9Gm6MefxctrLelIB0B1n8w+91usq+gaVwQDHKmltopLdPMyMQde/P/vy0xT3pbHoiqxFEQpYiWkSaf+1xFNALlWV8IykVyhQlbrS++/PKslh3Bs3tqqKdMYCAG9hnBVij8tXYvUoPN+8K1VMSNGypf/lquuyE9g2E3ZOk/V5d3+TEsuZiShlRbHrw8qm+ScSoxGom7nKLJ7u2i3y1lNQkNG/87KJpsaowJ0tw6dZtVkfZLxnNthptOaUAX42wX3m3pvtWP39OCNT3D99bBKcdgj6Cnx0NWh18cnl1S7Ula033XZSXBvyB08XciO8+/p7y3fnmOMTpGFpCQFy6Rrla36y3+TOzS35xetaWoQQ9aNNfM4SlG5CugOV1HAJuVDsuirLrBgmdqh0eXfR3ePd4f6q0XN8S/jqH8v8+BhTCOvtLcqvBjt3ZXipYZirYKlbj5rZqSIvWbnAAAsBAAgspERGjcdfFnAFH+mJBqAjyGn5c0J5WhKlw2TzfPguSIABUBsGAkAAAEAILKRERo3HXxZwBR/piQagI8hp+XNCeVoSpcNk83z4Lki/gBlzR0A3e6a119a7b7e0c8875fe466de022440dbb032d5cc33a81a48e5a451c8e34dc8e

The output of this command should be a 32-byte transaction ID. Once this transaction is mined, your coins are waiting for you at your address! Let's go get them.

Recreate the multisig wallet and spend your money

Now we go back to Alice, Bob, and Charlie from the beginning. Each of them will do the following steps, but we'll only see it from Alice's perspective in this guide. A glossier version of this process was recently published in this bcoin guide.

Alice starts up hsd on mainnet, and creates a multisig wallet using her MNEMONIC PHRASE. This command will create a 2-of-3 multisig wallet initialized with her private key. It is not usable until the two remaining PUBLIC keys are added.

Alice creates a wallet:

$ hsw-cli mkwallet --id=faucet --m=2 --n=3 --mnemonic='deliver coral upset label fence caution retire senior horse twin room ice below giant coral patch cousin float guide exhibit maple milk soft foot'

Alice imports the xpub's from her two co-signers:

$ hsw-cli --id=faucet --account=default shared add xpub6Btvro4tw1K7NWe5c2R7EwVXDYKGYFmNvKTE9QvCmYt7UK5WzmcwRpftKAFAEEUPk6wSgPKdMXcGop9yYeJvo2oTJCuQQcByUGXTYTJxxnr

$ hsw-cli --id=faucet --account=default shared add xpub6C33z6L3wh474nxn4naYmQiSVDqjwewFCUG2dWjKuJSR9YuySaCW3Dx76ikkHHaZJFRFKY41YGwPdyvHzj6ziqm8J8q7HTKbXD6qza5Fqjz

At this point, Alice's multisig wallet is initialized and can start generating receive addresses. If Alice checks her default account receive address, she will notice the address MATCHES EXACTLY the original address generated by the faucet tool and submitted to the network:

$ hsw-cli --id=faucet account get default

{
  "name": "default",
  "initialized": true,
  "watchOnly": false,
  "type": "multisig",
  "m": 2,
  "n": 3,
  "accountIndex": 0,
  "receiveDepth": 1,
  "changeDepth": 1,
  "lookahead": 10,
  "receiveAddress": "hs1q0h4nlt4xs8t06634hncptkpchmvehf5r6kt7yr5mxkxu7tlx5lyqf7qcpg",
  "changeAddress": "hs1qcamf2lflxym5h6snmmeqxzrauxqwv4suvlm3m6yvww6wt8p884rq87m0a9",
  "accountKey": "xpub6CyGFH8QHNbH36UMRPGXuZj7fBTjcjUeGu61ueZgAUUh6XYyN5gTxduaSLf8E7Z27wWdKoZ3aKAuQBCp3FVDvst2uiBgKd562x43oco243a",
  "keys": [
    "xpub6Btvro4tw1K7NWe5c2R7EwVXDYKGYFmNvKTE9QvCmYt7UK5WzmcwRpftKAFAEEUPk6wSgPKdMXcGop9yYeJvo2oTJCuQQcByUGXTYTJxxnr",
    "xpub6C33z6L3wh474nxn4naYmQiSVDqjwewFCUG2dWjKuJSR9YuySaCW3Dx76ikkHHaZJFRFKY41YGwPdyvHzj6ziqm8J8q7HTKbXD6qza5Fqjz"
  ],
  "balance": {
    "account": 0,
    "tx": 0,
    "coin": 0,
    "unconfirmed": 0,
    "confirmed": 0,
    "lockedUnconfirmed": 0,
    "lockedConfirmed": 0
  }
}

After a wallet rescan, the balance of the multisig wallet should be visible:

$ hsw-cli --id=faucet rescan

Rescanning...


$ hsw-cli --id=faucet balance

{
  "account": -1,
  "tx": 1,
  "coin": 1,
  "unconfirmed": 400000000000,
  "confirmed": 400000000000,
  "lockedUnconfirmed": 0,
  "lockedConfirmed": 0
}

How do WE spend this money now?

Assuming Alice, Bob and Charlie have all done the above steps, they each now have a wallet with one private key and two public keys. Only two parties need to sign a transaction to spend from the wallet.

Alice begins by creating a transaction, which will contain her signature and placeholders for the other two. Again, the output is verbose but all we need for the next step is the hex blob in the last line:

$ hsw-cli --id=Alice mktx --address=rs1qynzp8m3gke4t78qwuxex433adtyw8f4sc0n5pz --value=1.2304

{
  "hash": "4af331858b7d9aa5b9fb4448e5f6d515b1fde446122d0dab0764099f92e320cb",
  "witnessHash": "d4bc013b2849446ecdcd1a6dbf0cbb5de1a067426d4d4f650059e62178d2f8ff",
  "fee": 7360,
  "rate": 43294,
  "mtime": 1574356059,
  "version": 0,
  "inputs": [
    {
      "prevout": {
        "hash": "011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef",
        "index": 0
      },
      "witness": [
        "",
        "6bc4cbf986a9a08cf73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad1201",
        "",
        "",
        "5221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae"
      ],
      "sequence": 4294967295,
      "coin": {
        "version": 0,
        "height": 73,
        "value": 2000000000,
        "address": "rs1qhme0sqv02c4fjktft6l3suq5u9d4duddjf39qx4kvjlcxlsdqqsspxhhfv",
        "covenant": {
          "type": 0,
          "action": "NONE",
          "items": []
        },
        "coinbase": true
      }
    }
  ],
  "outputs": [
    {
      "value": 1230400,
      "address": "rs1qynzp8m3gke4t78qwuxex433adtyw8f4sc0n5pz",
      "covenant": {
        "type": 0,
        "action": "NONE",
        "items": []
      }
    },
    {
      "value": 1998762240,
      "address": "rs1qremjkhv5n7c46jjqamt5r6l7xny2rqmqttlcyeegueacqyudk95qm0snft",
      "covenant": {
        "type": 0,
        "action": "NONE",
        "items": []
      }
    }
  ],
  "locktime": 0,
  "hex": "0000000001011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef00000000ffffffff0240c6120000000000001424c413ee28b66abf1c0ee1b26ac63d6ac8e3a6b0000000b122770000000000201e772b5d949fb15d4a40eed741ebfe34c8a183605aff826728e67b80138db1680000000000000500416bc4cbf986a9a08cf73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad12010000695221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae"
}

That hex blob is a partially-signed multisig transaction. Alice gives it to Bob, who'll sign it with his own multisig wallet:

THIS IS BOB'S COMPUTER NOW:

$ hsw-cli --id=Bob sign --tx=0000000001011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef00000000ffffffff0240c6120000000000001424c413ee28b66abf1c0ee1b26ac63d6ac8e3a6b0000000b122770000000000201e772b5d949fb15d4a40eed741ebfe34c8a183605aff826728e67b80138db1680000000000000500416bc4cbf986a9a08cf73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad12010000695221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae

{
  "hash": "4af331858b7d9aa5b9fb4448e5f6d515b1fde446122d0dab0764099f92e320cb",
  "witnessHash": "7dbdda85bf4c5fcf29501b47744a3ffee1b0bf5ea80b6606125556eb18f7da4a",
  "fee": 7360,
  "rate": 39569,
  "mtime": 1574356534,
  "version": 0,
  "inputs": [
    {
      "prevout": {
        "hash": "011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef",
        "index": 0
      },
      "witness": [
        "",
        "6bc4cbf986a9a08cf73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad1201",
        "f0ca35626c9ebe672bef735f0aa769ab65fd35f89ab75735f698a0e8955f2b7b0f5aed99106221143eb1973a75ed50cb85bba8fa3ebd41f3a15ec99104d13e9e01",
        "5221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae"
      ],
      "sequence": 4294967295,
      "coin": {
        "version": 0,
        "height": 73,
        "value": 2000000000,
        "address": "rs1qhme0sqv02c4fjktft6l3suq5u9d4duddjf39qx4kvjlcxlsdqqsspxhhfv",
        "covenant": {
          "type": 0,
          "action": "NONE",
          "items": []
        },
        "coinbase": true
      }
    }
  ],
  "outputs": [
    {
      "value": 1230400,
      "address": "rs1qynzp8m3gke4t78qwuxex433adtyw8f4sc0n5pz",
      "covenant": {
        "type": 0,
        "action": "NONE",
        "items": []
      }
    },
    {
      "value": 1998762240,
      "address": "rs1qremjkhv5n7c46jjqamt5r6l7xny2rqmqttlcyeegueacqyudk95qm0snft",
      "covenant": {
        "type": 0,
        "action": "NONE",
        "items": []
      }
    }
  ],
  "locktime": 0,
  "hex": "0000000001011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef00000000ffffffff0240c6120000000000001424c413ee28b66abf1c0ee1b26ac63d6ac8e3a6b0000000b122770000000000201e772b5d949fb15d4a40eed741ebfe34c8a183605aff826728e67b80138db1680000000000000400416bc4cbf986a9a08cf73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad120141f0ca35626c9ebe672bef735f0aa769ab65fd35f89ab75735f698a0e8955f2b7b0f5aed99106221143eb1973a75ed50cb85bba8fa3ebd41f3a15ec99104d13e9e01695221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae"
}

There we go! A signed multisig transaction spending from a faucet payout output. Anyone can broadcast this hex:

$ hsd-cli broadcast 0000000001011137165fbdaa89f7139c1e523a0468b276f92ba358b8ae2c22ef608ef771ef00000000ffffffff0240c6120000000000001424c41
3ee28b66abf1c0ee1b26ac63d6ac8e3a6b0000000b122770000000000201e772b5d949fb15d4a40eed741ebfe34c8a183605aff826728e67b80138db1680000000000000400416bc4cbf986a9a08c
f73c07fd883144cff5b6c54fb2cf1196c58cb6c7f6ea2ca234d85b903ac717ccb26576720cbbdc8af999034350d224676d346fe768c0ad120141f0ca35626c9ebe672bef735f0aa769ab65fd35f89
ab75735f698a0e8955f2b7b0f5aed99106221143eb1973a75ed50cb85bba8fa3ebd41f3a15ec99104d13e9e01695221035b49445a6dc4f73190640d5e3b69ab30f2980b43b1b47ee3b103163bdde7
fc6e2103820defc36e41ad74a891998237eb2ab28791e032b2abaec4fbb0e26418541e882103e246e94d2aa5348b05d301f0dc4b47f7754da825b7cd02c70e267f27681abfb353ae

Broadcasted:
{
  "success": true
}

Advanced: redeem faucet coins on local regtest network

Because testnet and mainnet have different BIP44 cointype values, importing a mnemonic phrase from faucet-tool will not work on testnet or regtest. If you want to test the above process on a local regtest network, you can do so by installing and running this modified branch of hsd:

$ git clone --branch faucet-test https://github.com/pinheadmz/hsd
$ cd hsd
$ npm install
$ hsd --daemon

This will run an UNSAFE, MODIFIED VERSION OF THE HANDSHAKE WALLET that should ONLY be used to test faucet redemption. You will need to either add the command line parameter --network=regtest to each command above, or set an environment variable before entering the commands (export HSD_NETWORK=regtest)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment