<p>Yes we could do that easily, first we launch bitcoin core on regtest <code>bitcoind -regtest -fallbackfee=0.0002 -daemon</code></p>
<p>then we create and load a wallet</p>
<pre><code>bitcoin-cli -regtest createwallet &quot;my_wallet&quot;
</code></pre>
<p>then we generate 100 blocks to get some coins <code>bitcoin-cli -regtest generatetoaddress 101 &quot;$(bitcoin-cli -regtest getnewaddress)&quot;</code></p>
<p>then we gonna need 3 new addresses for our 2-of-3 multisig address so lets create them</p>
<pre><code>ADDR1=$(bitcoin-cli -regtest getnewaddress)
ADDR2=$(bitcoin-cli -regtest getnewaddress)
ADDR3=$(bitcoin-cli -regtest getnewaddress)
</code></pre>
<p>We get the public keys associated ( you might need <code>jq</code> here )</p>
<pre><code>PUBKEY1=$(bitcoin-cli -regtest getaddressinfo $ADDR1 | jq -r '.pubkey')
PUBKEY2=$(bitcoin-cli -regtest getaddressinfo $ADDR2 | jq -r '.pubkey')
PUBKEY3=$(bitcoin-cli -regtest getaddressinfo $ADDR3 | jq -r '.pubkey')
</code></pre>
<p>then we create our 2-of-3 multisig address <code>P2SH_MULTISIG=$(bitcoin-cli -regtest createmultisig 2 &quot;[\&quot;$PUBKEY1\&quot;,\&quot;$PUBKEY2\&quot;,\&quot;$PUBKEY3\&quot;]&quot; | jq -r '.address')</code></p>
<p>We send some coins to it <code>bitcoin-cli -regtest sendtoaddress $P2SH_MULTISIG 1</code></p>
<p>Then we generate new blocks to confirm the transaction <code>bitcoin-cli -regtest generatetoaddress 1 &quot;$(bitcoin-cli -regtest getnewaddress)&quot;</code></p>
<p>we create a descriptor with the public keys</p>
<pre><code>DESC_NO_CHECKSUM=&quot;sh(multi(2,$PUBKEY1,$PUBKEY2,$PUBKEY3))&quot;
DESC_WITH_CHECKSUM=$(bitcoin-cli -regtest getdescriptorinfo &quot;$DESC_NO_CHECKSUM&quot; | jq -r '.descriptor')
</code></pre>
<p>then we import the multisig address</p>
<pre><code>bitcoin-cli -regtest importmulti &quot;[{\&quot;desc\&quot;: \&quot;$DESC_WITH_CHECKSUM\&quot;, \&quot;timestamp\&quot;: \&quot;now\&quot;, \&quot;internal\&quot;: false, \&quot;watchonly\&quot;: true}]&quot;
</code></pre>
<p>then we get the unspent transactions and get the transaction ID, output index (vout), and amount for the UTXO</p>
<pre><code>UTXO=$(bitcoin-cli -regtest listunspent | jq -r &quot;.[] | select(.address == \&quot;$P2SH_MULTISIG\&quot;)&quot;)
TXID=$(echo $UTXO | jq -r '.txid' | tr -d '\n')
VOUT=$(echo $UTXO | jq -r '.vout')
AMOUNT=$(echo $UTXO | jq -r '.amount')
</code></pre>
<p>then we create a new destination address with the correct change amount</p>
<pre><code>DESTADDR=$(bitcoin-cli -regtest getnewaddress)
CHANGE=$(echo &quot;$AMOUNT - 0.0002&quot; | bc | LC_ALL=C awk '{printf &quot;%.8f&quot;, $0}')
</code></pre>
<p>then we create the raw transaction</p>
<pre><code>RAW_TX=$(bitcoin-cli -regtest createrawtransaction &quot;[{\&quot;txid\&quot;:\&quot;$TXID\&quot;,\&quot;vout\&quot;:$VOUT}]&quot; &quot;{\&quot;$DESTADDR\&quot;:$CHANGE}&quot;)
</code></pre>
<p>we sign it with the private keys of the 2 of 3 addresses</p>
<pre><code>PRIVKEY1=$(bitcoin-cli -regtest dumpprivkey $ADDR1)
PRIVKEY2=$(bitcoin-cli -regtest dumpprivkey $ADDR2)

SIGNED_TX=$(bitcoin-cli -regtest signrawtransactionwithkey $RAW_TX &quot;[\&quot;$PRIVKEY1\&quot;,\&quot;$PRIVKEY2\&quot;]&quot; &quot;[{\&quot;txid\&quot;:\&quot;$TXID\&quot;,\&quot;vout\&quot;:$VOUT,\&quot;scriptPubKey\&quot;:\&quot;$(echo $UTXO | jq -r '.scriptPubKey')\&quot;,\&quot;redeemScript\&quot;:\&quot;$(bitcoin-cli -regtest createmultisig 2 &quot;[\&quot;$PUBKEY1\&quot;,\&quot;$PUBKEY2\&quot;,\&quot;$PUBKEY3\&quot;]&quot; | jq -r '.redeemScript')\&quot;,\&quot;amount\&quot;:$AMOUNT}]&quot;)
</code></pre>
<p>then we can send it</p>
<pre><code>bitcoin-cli -regtest sendrawtransaction $(echo $SIGNED_TX | jq -r '.hex')
</code></pre>
<p>and in the end we generate a new block to confirm the transaction</p>
<pre><code>bitcoin-cli -regtest generatetoaddress 1 &quot;$(bitcoin-cli -regtest getnewaddress)&quot;
</code></pre>

CC BY-SA 4.0
2023-04-30T07:36:09.470Z
This won't allow you to spend the coins, though, as you need to import the P2SH address into the wallet too. In a legacy wallet, this could be done with `addmultisigaddress`, but in new descriptor wallets all of the above can be done directly with descriptors too.
Pieter Wuille
CC BY-SA 4.0
2023-05-01T21:24:07.637Z
I modified my answer
Saxtheowl
CC BY-SA 4.0
2023-05-03T19:20:19.777Z
Thanks for the answer, when I try use `PRIVKEY1=$(bitcoin-cli -regtest dumpprivkey $ADDR1)`, it raises this error: `Only legacy wallets are supported by this command`
Amir reza Riahi
CC BY-SA 4.0
2023-05-05T01:53:26.227Z
Thats because you were using a descriptor wallet which does not have dumpprivkey, I updated my answer for descriptorwallet
Saxtheowl
CC BY-SA 4.0
2023-05-05T17:24:36.397Z
I'm also getting `Only legacy wallets are supported by this command` for importing address. `bitcoin-cli -regtest importaddress $P2SH_MULTISIG`
Amir reza Riahi
CC BY-SA 4.0
2023-05-06T12:46:58.723Z
Havent tested my previous solution, they were some mistake I changed the method, be sure to start from the first step.
Saxtheowl
CC BY-SA 4.0
2023-05-06T12:47:51.467Z
You need to use `importdescriptors`, not `importmulti`.
Pieter Wuille
CC BY-SA 4.0
2023-05-06T15:26:07.830Z
I have not yet used descriptor wallet :/ gonna have to look into it
Saxtheowl
CC BY-SA 4.0
2023-05-06T16:56:51.867Z
Unfortunately, it doesn't work yet.
Amir reza Riahi
CC BY-SA 4.0
2023-04-29T22:07:55.670Z
2023-05-06T12:46:03.077Z
2023-05-06T12:46:03.077Z
Saxtheowl
<p>I'm running <code>bitcoind</code> in the regtest mode on my computer. I need at least one transaction that spends a P2SH output in my local blockchain. Is there a way to create a P2SH transaction using <code>bitcoin-cli</code>?</p>

<bitcoind><p2sh><regtest>
How can I create a simple P2SH transaction in regtest?
Amir reza Riahi
# How can I create a simple P2SH transaction in regtest?

(Asked by: username_0 on 2023-04-29)

I'm running `bitcoind` in the regtest mode on my computer. I need at least one transaction that spends a P2SH output in my local blockchain. Is there a way to create a P2SH transaction using `bitcoin-cli`?

**Tags:** bitcoind, p2sh, regtest


---

## 1 answers

### Answer by username_1 on 2023-04-29. Score: 2

Yes we could do that easily, first we launch bitcoin core on regtest `bitcoind -regtest -fallbackfee=0.0002 -daemon`

then we create and load a wallet

```
bitcoin-cli -regtest createwallet "my_wallet"

```

then we generate 100 blocks to get some coins `bitcoin-cli -regtest generatetoaddress 101 "$(bitcoin-cli -regtest getnewaddress)"`

then we gonna need 3 new addresses for our 2-of-3 multisig address so lets create them

```
ADDR1=$(bitcoin-cli -regtest getnewaddress)
ADDR2=$(bitcoin-cli -regtest getnewaddress)
ADDR3=$(bitcoin-cli -regtest getnewaddress)

```

We get the public keys associated ( you might need `jq` here )

```
PUBKEY1=$(bitcoin-cli -regtest getaddressinfo $ADDR1 | jq -r '.pubkey')
PUBKEY2=$(bitcoin-cli -regtest getaddressinfo $ADDR2 | jq -r '.pubkey')
PUBKEY3=$(bitcoin-cli -regtest getaddressinfo $ADDR3 | jq -r '.pubkey')

```

then we create our 2-of-3 multisig address `P2SH_MULTISIG=$(bitcoin-cli -regtest createmultisig 2 "[\"$PUBKEY1\",\"$PUBKEY2\",\"$PUBKEY3\"]" | jq -r '.address')`

We send some coins to it `bitcoin-cli -regtest sendtoaddress $P2SH_MULTISIG 1`

Then we generate new blocks to confirm the transaction `bitcoin-cli -regtest generatetoaddress 1 "$(bitcoin-cli -regtest getnewaddress)"`

we create a descriptor with the public keys

```
DESC_NO_CHECKSUM="sh(multi(2,$PUBKEY1,$PUBKEY2,$PUBKEY3))"
DESC_WITH_CHECKSUM=$(bitcoin-cli -regtest getdescriptorinfo "$DESC_NO_CHECKSUM" | jq -r '.descriptor')

```

then we import the multisig address

```
bitcoin-cli -regtest importmulti "[{\"desc\": \"$DESC_WITH_CHECKSUM\", \"timestamp\": \"now\", \"internal\": false, \"watchonly\": true}]"

```

then we get the unspent transactions and get the transaction ID, output index (vout), and amount for the UTXO

```
UTXO=$(bitcoin-cli -regtest listunspent | jq -r ".[] | select(.address == \"$P2SH_MULTISIG\")")
TXID=$(echo $UTXO | jq -r '.txid' | tr -d '\n')
VOUT=$(echo $UTXO | jq -r '.vout')
AMOUNT=$(echo $UTXO | jq -r '.amount')

```

then we create a new destination address with the correct change amount

```
DESTADDR=$(bitcoin-cli -regtest getnewaddress)
CHANGE=$(echo "$AMOUNT - 0.0002" | bc | LC_ALL=C awk '{printf "%.8f", $0}')

```

then we create the raw transaction

```
RAW_TX=$(bitcoin-cli -regtest createrawtransaction "[{\"txid\":\"$TXID\",\"vout\":$VOUT}]" "{\"$DESTADDR\":$CHANGE}")

```

we sign it with the private keys of the 2 of 3 addresses

```
PRIVKEY1=$(bitcoin-cli -regtest dumpprivkey $ADDR1)
PRIVKEY2=$(bitcoin-cli -regtest dumpprivkey $ADDR2)

SIGNED_TX=$(bitcoin-cli -regtest signrawtransactionwithkey $RAW_TX "[\"$PRIVKEY1\",\"$PRIVKEY2\"]" "[{\"txid\":\"$TXID\",\"vout\":$VOUT,\"scriptPubKey\":\"$(echo $UTXO | jq -r '.scriptPubKey')\",\"redeemScript\":\"$(bitcoin-cli -regtest createmultisig 2 "[\"$PUBKEY1\",\"$PUBKEY2\",\"$PUBKEY3\"]" | jq -r '.redeemScript')\",\"amount\":$AMOUNT}]")

```

then we can send it

```
bitcoin-cli -regtest sendrawtransaction $(echo $SIGNED_TX | jq -r '.hex')

```

and in the end we generate a new block to confirm the transaction

```
bitcoin-cli -regtest generatetoaddress 1 "$(bitcoin-cli -regtest getnewaddress)"

```

> **Comments:**
> **username_2**: This won't allow you to spend the coins, though, as you need to import the P2SH address into the wallet too. In a legacy wallet, this could be done with `addmultisigaddress`, but in new descriptor wallets all of the above can be done directly with descriptors too.  
> **username_1**: I modified my answer  
> **username_0**: Thanks for the answer, when I try use `PRIVKEY1=$(bitcoin-cli -regtest dumpprivkey $ADDR1)`, it raises this error: `Only legacy wallets are supported by this command`  
> **username_1**: Thats because you were using a descriptor wallet which does not have dumpprivkey, I updated my answer for descriptorwallet  
> **username_0**: I'm also getting `Only legacy wallets are supported by this command` for importing address. `bitcoin-cli -regtest importaddress $P2SH_MULTISIG`  
> **username_1**: Havent tested my previous solution, they were some mistake I changed the method, be sure to start from the first step.  
> **username_2**: You need to use `importdescriptors`, not `importmulti`.  
> **username_1**: I have not yet used descriptor wallet :/ gonna have to look into it  
> **username_0**: Unfortunately, it doesn't work yet.  

---

