<p>Your script has a fatal flaw: it uses <code>OP_CHECKMULTISIG</code> instead of <code>OP_CHECKMULTISIGVERIFY</code>, which causes the output of that opcode (in this case <code>01</code>) to be interpreted as a signature by the last <code>OP_CHECKSIG</code>. This renders the multisig branch of your input completely unusable, though the locktime branch will still work.</p>
<p>As a reminder, for a script to pass it needs to execute without errors and leave a single true value on the stack (technically any value that evaluates to true with <code>CastToBool</code>, and technically the requirement that there's only one value is only a policy rule for pre-taproot inputs). It's for this reason that the last opcode in your script is <code>OP_CHECKSIG</code> and not <code>OP_CHECKSIGVERIFY</code> so that its output can serve as this value, but the outputs of previous checking opcodes need to be verified some other way, either as part of the opcode itself (these opcodes end with <code>-VERIFY</code>) or explicitly using <code>OP_VERIFY</code>.</p>
<p>There are a few other issues:</p>
<ul>
<li>The semantics of your script are different than you describe. It's not (2-of-3 multisig OR (timelock + admin)) but ((2-of-3 multisig OR timelock) + admin), assuming the last key is the admin, i.e. the admin is always required to sign. You probably want to move the last <code>OP_CHECKSIG</code> into the locktime branch, then using <code>OP_CHECKMULTISIG</code> in the multisig branch would be correct.</li>
<li>Your signed transaction only includes the two signatures for the multisig and not the admin signature. This is probably due to the aforementioned misunderstanding of the script's semantics.</li>
</ul>

CC BY-SA 4.0
2024-10-26T13:13:38.113Z
Redeem Script:
`OP_IF
OP_2 <PK1> <PK2> <PK3> OP_3 OP_CHECKMULTISIG
OP_ELSE
<LOCKTIME> OP_CHECKLOCKTIMEVERIFY OP_DROP
<AdminPK> OP_CHECKSIG
OP_ENDIF`

unlocking script:`
case 1:0 SIG1 SIG2 TRUE
case 2:SIG_ADMIN FALSE`

Is it right?
Gang Li
CC BY-SA 4.0
2024-10-26T19:04:42.550Z
Yes, that looks about right.
Vojtěch Strnad
CC BY-SA 4.0
2024-10-25T06:20:01.420Z
2024-10-25T06:20:01.420Z
Vojtěch Strnad
<p>I created a 2/3 multisig script with timelock,the admin can withdraw BTC after timelock.
But the bitcoin node return an error:code:-26,message:mandatory-script-verify-flag-failed (Non-canonical DER signature).</p>
<pre><code>func createMultisigLocktimeRedeemScript(pk1, pk2, pk3, pkAdmin []byte, locktime uint32) ([]byte, error) {
builder := txscript.NewScriptBuilder()

builder.AddOp(txscript.OP_IF)
// multisig
{
    // add the minimum number of needed signatures
    builder.AddOp(txscript.OP_2)
    builder.AddData(pk1)
    builder.AddData(pk2)
    builder.AddData(pk3)
    // add the total number of public keys in the multi-sig screipt
    builder.AddOp(txscript.OP_3)
    // add the check-multi-sig op-code
    builder.AddOp(txscript.OP_CHECKMULTISIG)
}

builder.AddOp(txscript.OP_ELSE)
// locktime
{
    var bz = make([]byte, 4)
    binary.LittleEndian.PutUint32(bz, locktime) //
    builder.AddData(bz)
    builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
    builder.AddOp(txscript.OP_DROP)
}
builder.AddOp(txscript.OP_ENDIF)

// admin
{
    builder.AddData(pkAdmin)
    builder.AddOp(txscript.OP_CHECKSIG)
}

// redeem script is the script program in the format of []byte
redeemScript, err := builder.Script()
if err != nil {
    return nil, err
}
redeemStr, err := txscript.DisasmString(redeemScript)
if err != nil {
    return nil, err
}
fmt.Println(&quot;script:&quot;, redeemStr)

{
    redeemHash := btcutil.Hash160(redeemScript)
    scriptAddr, err := btcutil.NewAddressScriptHashFromHash(redeemHash, &amp;chaincfg.TestNet3Params) //P2SH
    if err != nil {
        return nil, err
    }
    fmt.Printf(&quot;network %s script address: %s\n&quot;, &quot;testnet3&quot;, scriptAddr.EncodeAddress())
}
return redeemScript, nil
</code></pre>
<p>}</p>
<pre><code>func multisigLockTimeTx(sk1, sk2, sk3, skAdmin string, locktime uint32) error {
wif1, err := btcutil.DecodeWIF(sk1)
if err != nil {
    return err
}
pk1 := wif1.PrivKey.PubKey().SerializeCompressed()

wif2, err := btcutil.DecodeWIF(sk2)
if err != nil {
    return err
}
pk2 := wif2.PrivKey.PubKey().SerializeCompressed()

wif3, err := btcutil.DecodeWIF(sk3)
if err != nil {
    return err
}
pk3 := wif3.PrivKey.PubKey().SerializeCompressed()

wifAdmin, err := btcutil.DecodeWIF(skAdmin)
if err != nil {
    return err
}
pkAdmin := wifAdmin.PrivKey.PubKey().SerializeCompressed()

redeemScript, err := createMultisigLocktimeRedeemScript(pk1, pk2, pk3, pkAdmin, locktime)
if err != nil {
    return err
}

// build tx
redeemTx := wire.NewMsgTx(wire.TxVersion)

// you should provide your UTXO hash
utxoHash, err := chainhash.NewHashFromStr(&quot;deabddd6f7ebed78fe91b71a34ec7167360a49016be039fd2b053ac02388e449&quot;)
if err != nil {
    return nil
}
// and add the index of the UTXO
outPoint := wire.NewOutPoint(utxoHash, 0)
txIn := wire.NewTxIn(outPoint, nil, nil)

redeemTx.AddTxIn(txIn)

// adding the output to tx
decodedAddr, err := btcutil.DecodeAddress(&quot;tb1ph8jzyv68rwx436wtnr760tsg3ut07ml8zueuqcwww04fdmrp8ntqaqjmsp&quot;, &amp;chaincfg.TestNet3Params)
if err != nil {
    return err
}
destinationAddrByte, err := txscript.PayToAddrScript(decodedAddr)
if err != nil {
    return err
}
// adding the destination address and the amount to the transaction
redeemTxOut := wire.NewTxOut(5000, destinationAddrByte)
redeemTx.AddTxOut(redeemTxOut)

sig1, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif1.PrivKey)
if err != nil {
    return err
}
_ = sig1
sig2, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif2.PrivKey)
if err != nil {
    return err
}
_ = sig2

sig3, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif3.PrivKey)
if err != nil {
    fmt.Println(&quot;got error in constructing sig3&quot;)
    return err
}
_ = sig3

sigAdmin, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wifAdmin.PrivKey)
if err != nil {
    fmt.Println(&quot;got error in constructing sigAdmin&quot;)
    return err
}
_ = sigAdmin

fmt.Println(&quot;sig1:&quot;, hex.EncodeToString(sig1))
fmt.Println(&quot;sig2:&quot;, hex.EncodeToString(sig2))
fmt.Println(&quot;sig3:&quot;, hex.EncodeToString(sig3))
fmt.Println(&quot;sigAdmin:&quot;, hex.EncodeToString(sigAdmin))

if !isValidSignatur(sig1) {
    fmt.Println(&quot;signature invalid&quot;)
}
if !isValidSignatur(sig2) {
    fmt.Println(&quot;signature invalid&quot;)
}
if !isValidSignatur(sig3) {
    fmt.Println(&quot;signature invalid&quot;)
}
if !isValidSignatur(sigAdmin) {
    fmt.Println(&quot;signature invalid&quot;)
}

signature := txscript.NewScriptBuilder()
// multisig
{
    signature.AddOp(txscript.OP_0)
    signature.AddData(sig2)
    signature.AddData(sig3)
    signature.AddOp(txscript.OP_TRUE)
    signature.AddData(redeemScript)
}
{ // admin
    //signature.AddData(sigAdmin)
    //signature.AddOp(txscript.OP_FALSE)
    //signature.AddData(redeemScript)
}
signatureScript, err := signature.Script()
if err != nil {
    // Handle the error.
    return err
}

signatureScriptStr, err := txscript.DisasmString(signatureScript)
if err != nil {
    return err
}
fmt.Println(&quot;signatureScript:&quot;, signatureScriptStr)

redeemTx.TxIn[0].SignatureScript = signatureScript
var signedTx bytes.Buffer
if err := redeemTx.Serialize(&amp;signedTx); err != nil {
    return err
}
fmt.Println(&quot;TxHash:&quot;, redeemTx.TxHash().String())

hexSignedTx := hex.EncodeToString(signedTx.Bytes())
fmt.Println(&quot;signedTx:&quot;, hexSignedTx)

var multi_expporer_api = []string{&quot;https://blockstream.info/testnet/api/&quot;}
cli := bitcoinlib.NewSmartClient(multi_expporer_api)
txid, err := cli.PostTransaction(context.Background(), hexSignedTx)
if err != nil {
    return err
}
fmt.Println(&quot;txid:&quot;, txid)
return nil
</code></pre>
<p>}</p>
<p><strong>script:</strong></p>
<pre><code>OP_IF
  2
  03f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d
  023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe5
  022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c
  3
  OP_CHECKMULTISIG
OP_ELSE
  900c1a67
  OP_CHECKLOCKTIMEVERIFY
  OP_DROP
OP_ENDIF
035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52b
OP_CHECKSIG
</code></pre>
<p><strong>network testnet3 script address</strong>: 2MsWVE37DGR7adHWiZpUh7va71qkX26Vbp8</p>
<p><strong>sig1</strong>: 3044022017a98dfea76746e9b7f0f785c7d92625289b0b0b5b95b47072511c24f5f3769302201033ff85eec8ce951100c3f6459a439bdb13e24acd7d59609bc2b76a7b24503c01</p>
<p><strong>sig2</strong>: 3045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901</p>
<p><strong>sig3</strong>: 3045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801</p>
<p><strong>sigAdmin</strong>: 3045022100a85f88f394cabcf2659fa62f98ca56b26be5f7c4f9645c2922f6e52d01ef527d02207075c8af70d358f04b6fb1dfc0c19faaa274577ccc68f411370fbbae60aee79101</p>
<p><strong>signatureScript</strong>: 0 3045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901 3045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801 1 63522103f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d21023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe521022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c53ae6704900c1a67b1756821035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52bac</p>
<p><strong>TxHash</strong>: 03386f8a777ae44b2ee6ab4d494b46a55655fa7825c04dd9b7cf993086976669</p>
<p><strong>signedTx</strong>: 010000000149e48823c03a052bfd39e06b01490a366771ec341ab791fe78edebf7d6ddabde00000000fd2c0100483045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901483045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801514c9663522103f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d21023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe521022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c53ae6704900c1a67b1756821035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52bacffffffff018813000000000000225120b9e42233471b8d58e9cb98fda7ae088f16ff6fe71733c061ce73ea96ec613cd600000000</p>

<multi-signature><locktime>
send btc from P2SH(multisig and timelock script),got "Non-canonical DER signature"
Gang Li
# send btc from P2SH(multisig and timelock script),got "Non-canonical DER signature"

(Asked by: username_0 on 2024-10-25)

I created a 2/3 multisig script with timelock,the admin can withdraw BTC after timelock.
But the bitcoin node return an error:code:-26,message:mandatory-script-verify-flag-failed (Non-canonical DER signature).

```
func createMultisigLocktimeRedeemScript(pk1, pk2, pk3, pkAdmin []byte, locktime uint32) ([]byte, error) {
builder := txscript.NewScriptBuilder()

builder.AddOp(txscript.OP_IF)
// multisig
{
    // add the minimum number of needed signatures
    builder.AddOp(txscript.OP_2)
    builder.AddData(pk1)
    builder.AddData(pk2)
    builder.AddData(pk3)
    // add the total number of public keys in the multi-sig screipt
    builder.AddOp(txscript.OP_3)
    // add the check-multi-sig op-code
    builder.AddOp(txscript.OP_CHECKMULTISIG)
}

builder.AddOp(txscript.OP_ELSE)
// locktime
{
    var bz = make([]byte, 4)
    binary.LittleEndian.PutUint32(bz, locktime) //
    builder.AddData(bz)
    builder.AddOp(txscript.OP_CHECKLOCKTIMEVERIFY)
    builder.AddOp(txscript.OP_DROP)
}
builder.AddOp(txscript.OP_ENDIF)

// admin
{
    builder.AddData(pkAdmin)
    builder.AddOp(txscript.OP_CHECKSIG)
}

// redeem script is the script program in the format of []byte
redeemScript, err := builder.Script()
if err != nil {
    return nil, err
}
redeemStr, err := txscript.DisasmString(redeemScript)
if err != nil {
    return nil, err
}
fmt.Println("script:", redeemStr)

{
    redeemHash := btcutil.Hash160(redeemScript)
    scriptAddr, err := btcutil.NewAddressScriptHashFromHash(redeemHash, &chaincfg.TestNet3Params) //P2SH
    if err != nil {
        return nil, err
    }
    fmt.Printf("network %s script address: %s\n", "testnet3", scriptAddr.EncodeAddress())
}
return redeemScript, nil

```

}

```
func multisigLockTimeTx(sk1, sk2, sk3, skAdmin string, locktime uint32) error {
wif1, err := btcutil.DecodeWIF(sk1)
if err != nil {
    return err
}
pk1 := wif1.PrivKey.PubKey().SerializeCompressed()

wif2, err := btcutil.DecodeWIF(sk2)
if err != nil {
    return err
}
pk2 := wif2.PrivKey.PubKey().SerializeCompressed()

wif3, err := btcutil.DecodeWIF(sk3)
if err != nil {
    return err
}
pk3 := wif3.PrivKey.PubKey().SerializeCompressed()

wifAdmin, err := btcutil.DecodeWIF(skAdmin)
if err != nil {
    return err
}
pkAdmin := wifAdmin.PrivKey.PubKey().SerializeCompressed()

redeemScript, err := createMultisigLocktimeRedeemScript(pk1, pk2, pk3, pkAdmin, locktime)
if err != nil {
    return err
}

// build tx
redeemTx := wire.NewMsgTx(wire.TxVersion)

// you should provide your UTXO hash
utxoHash, err := chainhash.NewHashFromStr("deabddd6f7ebed78fe91b71a34ec7167360a49016be039fd2b053ac02388e449")
if err != nil {
    return nil
}
// and add the index of the UTXO
outPoint := wire.NewOutPoint(utxoHash, 0)
txIn := wire.NewTxIn(outPoint, nil, nil)

redeemTx.AddTxIn(txIn)

// adding the output to tx
decodedAddr, err := btcutil.DecodeAddress("tb1ph8jzyv68rwx436wtnr760tsg3ut07ml8zueuqcwww04fdmrp8ntqaqjmsp", &chaincfg.TestNet3Params)
if err != nil {
    return err
}
destinationAddrByte, err := txscript.PayToAddrScript(decodedAddr)
if err != nil {
    return err
}
// adding the destination address and the amount to the transaction
redeemTxOut := wire.NewTxOut(5000, destinationAddrByte)
redeemTx.AddTxOut(redeemTxOut)

sig1, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif1.PrivKey)
if err != nil {
    return err
}
_ = sig1
sig2, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif2.PrivKey)
if err != nil {
    return err
}
_ = sig2

sig3, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wif3.PrivKey)
if err != nil {
    fmt.Println("got error in constructing sig3")
    return err
}
_ = sig3

sigAdmin, err := txscript.RawTxInSignature(redeemTx, 0, redeemScript, txscript.SigHashAll, wifAdmin.PrivKey)
if err != nil {
    fmt.Println("got error in constructing sigAdmin")
    return err
}
_ = sigAdmin

fmt.Println("sig1:", hex.EncodeToString(sig1))
fmt.Println("sig2:", hex.EncodeToString(sig2))
fmt.Println("sig3:", hex.EncodeToString(sig3))
fmt.Println("sigAdmin:", hex.EncodeToString(sigAdmin))

if !isValidSignatur(sig1) {
    fmt.Println("signature invalid")
}
if !isValidSignatur(sig2) {
    fmt.Println("signature invalid")
}
if !isValidSignatur(sig3) {
    fmt.Println("signature invalid")
}
if !isValidSignatur(sigAdmin) {
    fmt.Println("signature invalid")
}

signature := txscript.NewScriptBuilder()
// multisig
{
    signature.AddOp(txscript.OP_0)
    signature.AddData(sig2)
    signature.AddData(sig3)
    signature.AddOp(txscript.OP_TRUE)
    signature.AddData(redeemScript)
}
{ // admin
    //signature.AddData(sigAdmin)
    //signature.AddOp(txscript.OP_FALSE)
    //signature.AddData(redeemScript)
}
signatureScript, err := signature.Script()
if err != nil {
    // Handle the error.
    return err
}

signatureScriptStr, err := txscript.DisasmString(signatureScript)
if err != nil {
    return err
}
fmt.Println("signatureScript:", signatureScriptStr)

redeemTx.TxIn[0].SignatureScript = signatureScript
var signedTx bytes.Buffer
if err := redeemTx.Serialize(&signedTx); err != nil {
    return err
}
fmt.Println("TxHash:", redeemTx.TxHash().String())

hexSignedTx := hex.EncodeToString(signedTx.Bytes())
fmt.Println("signedTx:", hexSignedTx)

var multi_expporer_api = []string{"https://blockstream.info/testnet/api/"}
cli := bitcoinlib.NewSmartClient(multi_expporer_api)
txid, err := cli.PostTransaction(context.Background(), hexSignedTx)
if err != nil {
    return err
}
fmt.Println("txid:", txid)
return nil

```

}

**script:**

```
OP_IF
  2
  03f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d
  023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe5
  022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c
  3
  OP_CHECKMULTISIG
OP_ELSE
  900c1a67
  OP_CHECKLOCKTIMEVERIFY
  OP_DROP
OP_ENDIF
035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52b
OP_CHECKSIG

```

**network testnet3 script address**: 2MsWVE37DGR7adHWiZpUh7va71qkX26Vbp8

**sig1**: 3044022017a98dfea76746e9b7f0f785c7d92625289b0b0b5b95b47072511c24f5f3769302201033ff85eec8ce951100c3f6459a439bdb13e24acd7d59609bc2b76a7b24503c01

**sig2**: 3045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901

**sig3**: 3045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801

**sigAdmin**: 3045022100a85f88f394cabcf2659fa62f98ca56b26be5f7c4f9645c2922f6e52d01ef527d02207075c8af70d358f04b6fb1dfc0c19faaa274577ccc68f411370fbbae60aee79101

**signatureScript**: 0 3045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901 3045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801 1 63522103f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d21023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe521022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c53ae6704900c1a67b1756821035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52bac

**TxHash**: 03386f8a777ae44b2ee6ab4d494b46a55655fa7825c04dd9b7cf993086976669

**signedTx**: 010000000149e48823c03a052bfd39e06b01490a366771ec341ab791fe78edebf7d6ddabde00000000fd2c0100483045022100fc71b478e03ce44c8148bfd19a69175ce744d15f822851ca18d4c95cca08dcec02202dd451b493e8ffe64fb672a9740b49af95cb731a60fc386612983304f656681901483045022100f815e290b3c83160f49b56b9c18b0834f25f1752883ae83399cdfc34646a0cdb022051a687e58f88ebac3dd0430be22d9b0e1270bcd25e19732baf612ecd113da86801514c9663522103f5d066de8a9d8476f8eab2f507f2858ef0914ccf96bf3752f3f4652553c52b6d21023fe85a4a866ef5f4af2d1904e1ac3bec518542b13837ae1159d707650796bbe521022205cdcd869d9dbec279dadceeef7777e39d1915e2f36ec0f6e3fa50bb024c5c53ae6704900c1a67b1756821035d911aded72d77f12e5d200d37f968438c6c7d532b2dbf50a80516ab1014e52bacffffffff018813000000000000225120b9e42233471b8d58e9cb98fda7ae088f16ff6fe71733c061ce73ea96ec613cd600000000

**Tags:** multi-signature, locktime


---

## 1 answers

### Answer by username_1 on 2024-10-25. Score: 2

Your script has a fatal flaw: it uses `OP_CHECKMULTISIG` instead of `OP_CHECKMULTISIGVERIFY`, which causes the output of that opcode (in this case `01`) to be interpreted as a signature by the last `OP_CHECKSIG`. This renders the multisig branch of your input completely unusable, though the locktime branch will still work.

As a reminder, for a script to pass it needs to execute without errors and leave a single true value on the stack (technically any value that evaluates to true with `CastToBool`, and technically the requirement that there's only one value is only a policy rule for pre-taproot inputs). It's for this reason that the last opcode in your script is `OP_CHECKSIG` and not `OP_CHECKSIGVERIFY` so that its output can serve as this value, but the outputs of previous checking opcodes need to be verified some other way, either as part of the opcode itself (these opcodes end with `-VERIFY`) or explicitly using `OP_VERIFY`.

There are a few other issues:

* The semantics of your script are different than you describe. It's not (2-of-3 multisig OR (timelock + admin)) but ((2-of-3 multisig OR timelock) + admin), assuming the last key is the admin, i.e. the admin is always required to sign. You probably want to move the last `OP_CHECKSIG` into the locktime branch, then using `OP_CHECKMULTISIG` in the multisig branch would be correct.
* Your signed transaction only includes the two signatures for the multisig and not the admin signature. This is probably due to the aforementioned misunderstanding of the script's semantics.

> **Comments:**
> **username_0**: Redeem Script: `OP_IF OP_2 <PK1> <PK2> <PK3> OP_3 OP_CHECKMULTISIG OP_ELSE <LOCKTIME> OP_CHECKLOCKTIMEVERIFY OP_DROP <AdminPK> OP_CHECKSIG OP_ENDIF`  unlocking script:` case 1:0 SIG1 SIG2 TRUE case 2:SIG_ADMIN FALSE`  Is it right?  
> **username_1**: Yes, that looks about right.  

---

