Skip to main content

Use a multi-signature wallet

Sending multi-signature transactions that require M-of-N signatures to be spent.

Before executing a multisig transaction on the Hathor blockchain, you must first follow some preparation steps:

  • The public keys of all participants have to be collected
  • Each party's multisig wallets should be configured and started
  • A user must create a multisig transaction proposal and share it (its txHex code) among all participants.
  • All users will be able to decode the txHex to validate transaction data and decide whether to send back the signatures or not.
  • With all signatures and the initial txHex, any participant can assemble the multisig transaction and push it.

The following sections will detail using the APIs to perform all these steps.

1. Collect Public Keys

Each participant can start an instance of the wallet headless service (npm start) and invoke this /multisig-pubkey endpoint to obtain their respective public key. Once a participant has their own pubkey, they must send it to the other participants so that everyone can start the multisig wallet.

Parameters

  • seedKey: Parameter to define which seed (from the object seeds in the config.js file) will be used to obtain the public key.
  • passphrase: Optional parameter to generate the public key with a passphrase. If not sent an empty string is used.

Request

curl -X POST --data "seedKey=seedId0" http://localhost:8000/multisig-pubkey

Response

{
"success":true,
"xpubkey":"xpub6Cz2jqhx7TVwyb1JvBWsoXrLwemjDpeCTEszWQbimHPDVM9ZZ8ibgtN8gZBxXjq9UgVMtk4cE98ou8RPfU3xyuo5bahpuVwdY1dY46QJMoC"
}

2. Configure MultiSig Wallets

Any seed to be started as MultiSig must have a setting in the multisig key of the src/config.js file. The following is a 2-of-2 MultiSig example.

info

In an M-of-N wallet, N and M must be at most 16.

...
seeds: {
seedId0: '24-words seed',
},
multisig: {
seedId0: {
total: 2,
numSignatures: 2,
pubkeys: [
'xpub6Cz2jqhx7TVwyb1JvBWsoXrLwemjDpeCTEszWQbimHPDVM9ZZ8ibgtN8gZBxXjq9UgVMtk4cE98ou8RPfU3xyuo5bahpuVwdY1dY46QJMoC',
'xpub6BsQ6vsaUK3AixC8G3dT2CaFFFtCx5fzMcUrTQpBgJPuSkF65yDRNMrPCSCDok9QbsYQeyWinNQvA4SZzNGL5HV5GTk1Xj46wvPpAMfW5Aw'
]
}
},
...
info

MultiSig addresses are determined by the participants' public keys (xpubs) and the minimum number of signatures. Changing the minimum number of signatures will generate a different MultiSig wallet. The order of public keys order is not relevant.

3. Start MultiSig Wallets

Start each MultiSig wallet as described in the Starting Wallet section. Include the parameter multisig=true in the HTTP request body.

The headless wallet needs to be restarted after the `src/config.js` has been changed to include the multisig parameters (previous step).

Parameters

  • x-wallet-id: Wallet identifier.
  • passphrase: Optional parameter to start the wallet with a passphrase. If the user sets a passphrase when getting the public key (step 1), he must also use it when starting the wallet.
  • seedKey: Parameter to define which seed (from the object seeds in the config.js file) will be used to generate the wallet.
  • multisig: Parameter to start the wallet as a MultiSig wallet. Must be set to **true**.

Request

curl -X POST --data "wallet-id=walletId0" --data "seedKey=seedId0" \
--data "multisig=true" http://localhost:8000/start

4. Create a MultiSig Transaction

A transaction proposal is created. It is a proposal because no value is transferred to the destination address. In other words, although the transaction has been created, it has not yet been executed. Instead, the multisig transaction has been prepared so that all participants can verify its details before it is executed. The /wallet/p2sh/tx-proposal endpoint returns the transaction txHex that must be sent to all parties so they can access the transaction proposal.

Parameters

  • x-wallet-id: Wallet identifier.
  • outputs: Array of JSON objects.
    • address: Destination address
    • token: Token UID if the output is not for HTR
    • value: Value to be transferred. Must be an integer with the value in cents, i.e., 123 means 1.23 HTR.

Request

curl -X POST -H "X-Wallet-Id: walletId0" -H "Content-type: application/json" \
--data '{"outputs": [{"address":"WVUM5x6zfxc11we7zhNb2jVVyxadWDevpv","value":1}]}' \
http://localhost:8000/wallet/p2sh/tx-proposal

Response

{
"success":true,
"txHex":"000100010200d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a000000000001f300001976a914dc6c192478a5b3c439b9289f447cedd736b5823d88ac0000000100001976a9144a93166ef1d958a80cb66e3af261058ff097363988ac7ff8000000000000000000000000000000"
}

5. Check the MultiSig Transaction

Before agreeing to the created multisig transaction proposal, each participant may use the txHex of that transaction to verify its details, such as destination address, token UID (if the output is not for HTR), and value to be transferred. The multisig transaction details are retrieved from the /wallet/decode endpoint.

Parameters

  • x-wallet-id: Wallet identifier.
  • txHex: Transaction hexadecimal code

Request

curl -X POST -H "X-Wallet-Id: walletId0" -H "Content-type: application/json" \
--data '{"txHex":"000100010200d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a000000000001f300001976a914dc6c192478a5b3c439b9289f447cedd736b5823d88ac0000000100001976a9144a93166ef1d958a80cb66e3af261058ff097363988ac7ff8000000000000000000000000000000"}' \
http://localhost:8000/wallet/decode

Response

{
"success":true,
"tx":{
"tokens":[

],
"inputs":[
{
"txId":"00d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a",
"index":0
}
],
"outputs":[
{
"value":499,
"tokenData":0,
"script":"dqkU3GwZJHils8Q5uSifRHzt1za1gj2IrA==",
"type":"p2pkh",
"decoded":{
"address":"WimX2vewFTkZpYA6UtpsXtLSZpDdBR9feL",
"timelock":null
}
},
{
"value":1,
"tokenData":0,
"script":"dqkUSpMWbvHZWKgMtm468mEFj/CXNjmIrA==",
"type":"p2pkh",
"decoded":{
"address":"WVUM5x6zfxc11we7zhNb2jVVyxadWDevpv",
"timelock":null
}
}
]
}
}

6. Get Participant Signatures

Suppose participants approve the transaction after verifying their details in the previous step. In this case, each participant must use txHex to sign the transaction via the /wallet/p2sh/tx-proposal/get-my-signatures endpoint.

Parameters

  • x-wallet-id: Wallet identifier.
  • txHex: Transaction hexadecimal code

Request

curl -X POST -H "X-Wallet-Id: walletId0" -H "Content-type: application/json" \
--data '{"txHex":"000100010200d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a000000000001f300001976a914dc6c192478a5b3c439b9289f447cedd736b5823d88ac0000000100001976a9144a93166ef1d958a80cb66e3af261058ff097363988ac7ff8000000000000000000000000000000"}' \
http://localhost:8000/wallet/p2sh/tx-proposal/get-my-signatures

Response

{
"success":true,
"signatures":"023eb05452d1fd0568a101da19d5da45725f4621d15ed80eae364372fb61dfd6f5|0:3045022100c95a6c1f0c119e7e2162e3d1c65ff726e7fb61c3a1dafdc7e260d90fbd81674202204ea877de40ed052d47a25521e42fffac37c8942e835e765010cb78c69924c434"
}

7. Send the MultiSig Transaction

Once enough signatures have been collected, any participant can use the /wallet/p2sh/tx-proposal/sign-and-push to send the transaction.

Parameters

  • x-wallet-id: Wallet identifier.
  • txHex: Transaction hexadecimal code
  • signatures: Array where each position contains the signature of a participant in the MultiSig transaction.

Request

curl -X POST -H "X-Wallet-Id: walledId0" -H "Content-type: application/json" \
--data '{"txHex": "000100010200d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a000000000001f300001976a914dc6c192478a5b3c439b9289f447cedd736b5823d88ac0000000100001976a9144a93166ef1d958a80cb66e3af261058ff097363988ac7ff8000000000000000000000000000000", "signatures":["023eb05452d1fd0568a101da19d5da45725f4621d15ed80eae364372fb61dfd6f5|0:3045022100c95a6c1f0c119e7e2162e3d1c65ff726e7fb61c3a1dafdc7e260d90fbd81674202204ea877de40ed052d47a25521e42fffac37c8942e835e765010cb78c69924c434","021ddcac9112297360daf3c555eb69b483e45d31d331ebdf0dd5362fa347e4f315|0:30440220570cb8494b358781f9804ad5ee5bfc3d3b197589ec91efc0c607ffdfd7b34baf022006ecdd8c0d7247a527596581ef7f9d6eaaf82922faf969b1df08cce67fe8f45f"]}' \
http://localhost:8000/wallet/p2sh/tx-proposal/sign-and-push

Response

{
"success":true,
"inputs":[
{
"hash":"00d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a",
"index":0,
"data":{
"type":"Buffer",
"data":[+]
},
"tx_id":"00d0f99478ebe87a2b1a82b587e670e7ca89be28d409c7ede80393e4d019805a"
}
],
"outputs":[
{
"value":499,
"script":{
"type":"Buffer",
"data":[+]
},
"tokenData":0,
"decodedScript":{
"address":{
"base58":"WimX2vewFTkZpYA6UtpsXtLSZpDdBR9feL",
"network":{
"name":"testnet",
"versionBytes":{
"p2pkh":73,
"p2sh":135,
"xpriv":70568132,
"xpub":76067358
},
"bitcoreNetwork":{
"name":"htr-testnet",
"alias":"test",
"pubkeyhash":73,
"privatekey":128,
"scripthash":135,
"bech32prefix":"tn",
"xpubkey":76067358,
"xprivkey":70568132,
"networkMagic":{
"type":"Buffer",
"data":[+]
},
"port":8333,
"dnsSeeds":[
]
}
}
},
"timelock":null
},
"token_data":0
},
{
"value":1,
"script":{
"type":"Buffer",
"data":[+]
},
"tokenData":0,
"decodedScript":{
"address":{
"base58":"WVUM5x6zfxc11we7zhNb2jVVyxadWDevpv",
"network":{
"name":"testnet",
"versionBytes":{
"p2pkh":73,
"p2sh":135,
"xpriv":70568132,
"xpub":76067358
},
"bitcoreNetwork":{
"name":"htr-testnet",
"alias":"test",
"pubkeyhash":73,
"privatekey":128,
"scripthash":135,
"bech32prefix":"tn",
"xpubkey":76067358,
"xprivkey":70568132,
"networkMagic":{
"type":"Buffer",
"data":[+]
},
"port":8333,
"dnsSeeds":[
]
}
}
},
"timelock":null
},
"token_data":0
}
],
"version":1,
"weight":18.020647094115752,
"nonce":100826,
"timestamp":1655224964,
"parents":[
"008be839a95b792912e3668ceb4fa46df897a29d069ef9898f6e6b415e661ce3",
"00fe3983367b32d1ce0e4aee8152795e75e079758f71809155a9c71d3d6df92f"
],
"tokens":[
],
"hash":"000024dd6fbb9a9bd9021ede5e706bcf0f7a09bc0649d727ce5afd77a2ca2e48",
"_dataToSignCache":null
}