How to self-recover MultiSig assets?

The security and availability of Ownbit MultiSig assets does not depend on the Onwbit server. This article teaches you how to recover MultiSig assets through self-service when there is a downtime or other unexpected situation on the Ownbit server. This article takes 2-3 MultiSig as an example. The participants are: A, B, and C.

1. Recover BTC MultiSig assets

The address of the BTC MultiSig asset is known and public. For example, the address is: 3CkvfWhYd6behUYnrA5rMQJoyr6oLGM6Ed, and it is expected to send the balance on the MultiSig address to the address: receiveAddress = 1GC3q7JYPu...VDv5pcZF2Va.

a. Query the available UTXOs on the MultiSig address through the browser. Each currency has a corresponding browser. For example, BTC is available: https://www.blockchain.com/btc/address/3CkvfWhYd6behUYnrA5rMQJoyr6oLGM6Ed to query. The transaction that is received for this address and is not spent is the available UTXO. Record the corresponding transaction hash and the location of the address in Output (the first position is 0, the second is 1, and so on), namely: tx_hash and index.

b. Obtain the BTC private keys of the three-person from their MultiSig wallets in the wallet management -> export private key: privateKey_BTC_A, privateKey_BTC_B and privateKey_BTC_C.

c. Obtain the corresponding public keys by private key: publicKey_BTC_A, publicKey_BTC_B, and publicKey_BTC_C. Can be generated by public and private key tools, such as the URL: https://iancoleman.io/bitcoin-key-compression/ (Important: download the website source code to run locally, so as not to leak the private key on the network!!!)

d. Generate redeemScript: <OP_2> 21 <A pubkey> 21 <B pubkey> 21 <C pubkey> <OP_3> <OP_CHECKMULTISIG>. The order of ABC is sorted from low to high in character order of the public key. For example: ABC public keys are:

publicKey_BTC_A = 03d2e38696c82a0570366f8c4eafc5be915fc1fb53c8b39cd8cbfaba97567388e0
publicKey_BTC_B = 032aa5165dbbbacf31a561486b448f620342f3ba5a5bfb60e0a9a3f4f7a9b21350
publicKey_BTC_C = 021988ac7af60cf4f8192cc1294a1b72856ece6c0e9583953bd87102884353f222

Then the order of ABC should be: CBA (C's 0219 is less than B's 032a, and B's 032a is less than A's 03d2).

OP_CODES:

<OP_1> - <OP_16> value: 0x51-0x60
<OP_CHECKMULTISIG> value: 0xae
21: hexadecimal number, indicating push 33 bytes, fixed value

If it is a MultiSig of other modes, replace <OP_2> and <OP_3> accordingly, such as 3-4 MultiSig, then: <OP_3> 21 <A_PUB> 21 <B_PUB> 21 <C_PUB> 21 <D_PUB> <OP_4> <OP_CHECKMULTISIG>. Therefore, the final redeemScript for the example is:

5221021988ac7af60cf4f8192cc1294a1b72856ece6c0e9583953bd87102884353f22221032aa5165dbbbacf31a561486b448f620342f3ba5a5bfb60e0a9a3f4f7a9b213502103d2e38696c82a0570366f8c4eafc5be915fc1fb53c8b39cd8cbfaba97567388e053ae

e. Generate transactions in JS or other programming languages (the following JS code is based on bitcoinjs-lib):

    const multisig = createPayment('p2sh-p2ms(2 of 3)');
    const inputData1 = await getInputData([2e4], multisig.payment, false, 'p2sh');
    {
      const {
        [tx_hash],
        [index],
        true,
        [redeemScript],
      } = inputData1;
    }

    const psbt = new bitcoin.Psbt({ network: mainnet })
      .addInput(inputData1)
      .addOutput({
        address: [receiveAddress]
        value: [1e4],
      })
      .signInput(0, [privateKey_BTC_B])
      .signInput(0, [privateKey_BTC_C]);

    assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
    assert.strictEqual(
      psbt.validateSignaturesOfInput(0, multisig.keys[0].publicKey),
      true,
    );
    assert.throws(() => {
      psbt.validateSignaturesOfInput(0, multisig.keys[1].publicKey);
    }, new RegExp('No signatures for this pubkey'));
    psbt.finalizeAllInputs();

    const tx = psbt.extractTransaction();

    //broadacast tx.toHex();

Replace [xxx] in the code with the data obtained in the above steps.

f: Broadcast the transaction Hex obtained in the above step to the BTC network.

2. Recover ETH/ERC20 MultiSig assets

a. ETH/ERC20 MultiSig assets exist in the MultiSig contract you deploy. The MultiSig contract address is known and public. For example, the MultiSig contract address you deployed is: contractAddress = 0xc314bCbD4e8044b03C98381F715782a815B57fF3 (Note: convert contractAddress to lowercase before using it in the computation).

b. In the Wallet Management -> Export Private Key, get the ETH private keys of any two people's MultiSig wallet (because it is 2-3 MultiSig, only 2 people need to sign), for example: privateKey_ETH_A and privateKey_ETH_C.

c. Read the contract source code: https://github.com/bitbill/bitbill-multisig-contracts and get the spendNonce. The initial value of spendNonce is 0. And spendNonce is incremented by 1 each time a new transaction is sent (the receiving transaction is not counted), the sendNonce can be obtained by counting the number of sent transactions, or by calling the getSpendNonce method in the contract:

function getSpendNonce() public constant returns (uint256) { return spendNonce; }

d. Get the private key signature, the following code shows the logic to get the private key signature (code based on ethereumjs):

//msContractAddress is the address of the MS
//erc20Contract is the erc20 contract address, pass: 0x0000000000000000000000000000000000000000 for ETH

function generateMultiSigV2(msContractAddress, erc20Contract, destination, value, spendNonce, privateKey) {
    privateKey = Buffer.from(privateKey, 'hex');
    var msgHex = '0x' + web3.toHex(msContractAddress).substr(2) + web3.toHex(erc20Contract).substr(2)
    + web3.toHex(destination).substr(2) + web3.padLeft(web3.toHex(value).substr(2), 64) + web3.padLeft(web3.toHex(spendNonce).substr(2), 64);
    console.log('msgHex: ' + msgHex);
    var msgHash = ethereumjsUtil.hashPersonalMessage(ethereumjsUtil.sha3(msgHex));
    console.log('msgHash: ' + msgHash.toString('hex'));
    var sig = ethereumjsUtil.ecsign(msgHash, privateKey);

    return [sig.v-27, '0x'+sig.r.toString('hex'), '0x'+sig.s.toString('hex')];
}

The value is the amount to be transferred. It is displayed as the minimum unit according to the currency's decimal. For example, the transfer 1ETH (the decimal of ETH is 18), the value is: 1000000000000000000, and the transfer is 1200USDT, the value is: 1200000000. (USDT-ERC20 has a decimal of 6).

The msContractAddress is obtained in step a (converted to lowercase), the sendNonce is obtained in step c, the destination is the destination address to be transferred, and the privateKey is obtained in step b. Call the generateMultiSigV2 method to get the signature of any two people (because it is 2-3 MultiSig, at least 2 people need to sign).

e. Call the spend or spendERC20 method of the MultiSig contract.

If you want to send ETH, call the spend method: function spend(address destination, uint256 value, uint8[] vs, bytes32[] rs, bytes32[] ss), passing in the parameters: destination and value are equivalent to those in step d. v,r,s is the result of the method in step d, and the MultiSig signatures can be arranged in an array in any order.

If you want to send ERC20, call the spendERC20 method: function spendERC20(address destination, address erc20contract, uint256 value, uint8[] vs, bytes32[] rs, bytes32[] ss), other parameters are consistent with the spend method, erc20contract is ERC20 contract address, such as USDT-ERC20, is: 0xdac17f958d2ee523a2206206994597c13d831ec7.

You can spend money by successfully calling the spend or spendERC20 method of the MultiSig contract.

Note: other Layer 2 networks (such as: BSC, AVAX) multi-signature recovery method is the same as ETH.

3. Recover TRX/TRC20 MultiSig assets

a. Check the Owner/Active Permission of the MultiSig account through the URL: https://api.trongrid.io/v1/accounts/TTG6b8LB52gQNoLjiD26QzyWAtLJooAuaR (replace TTG6b8LB52gQNoLjiD26QzyWAtLJooAuaR with your MultiSig address).

b. In Wallet Management -> Export Private Key, obtain the ETH private keys of any two MultiSig wallets (because it is 2-3 multi-signature, only two people need to sign), for example: privateKey_ETH_A and privateKey_ETH_C.

c. The ETH private key is the TRX private key. You can use the obtained private key to program to spend multi-signature assets. Refer to the official TRON document: https://developers.tron.network/docs/multi-signature.

4. Recover MultiSig assets of other currencies

The recovery of MultiSig assets of other currencies (BCH/LTC/DASH...) is consistent with the BTC MultiSig, and they also use the BTC private key.