trustwallet / wallet-core

Cross-platform, cross-blockchain wallet library.
https://developer.trustwallet.com/wallet-core
Apache License 2.0
2.86k stars 1.6k forks source link

Error signing bitcoin transaction with P2SH: Missing redeem script #812

Closed hochbruj closed 4 years ago

hochbruj commented 4 years ago

Describe the bug I followed the example for bitcoin transaction signing from https://developer.trustwallet.com/wallet-core/integration-guide/wallet-core-usage. Here is my Swift code:

Getting key

let hd_wallet = try HDWallet(mnemonic: mnemonic, passphrase: "")
//get private key
let path = DerivationPath(purpose: .bip49, coinType: bitcoin, account: 0, change: 0, address: 0)
let privateKey = hd_wallet.getKey(derivationPath: path.description)

Utxo

let utxo = BitcoinUnspentTransaction.with {
        $0.outPoint.hash = Data(utxoTxId.reversed()) // reverse of UTXO tx id, Bitcoin internal expects network byte order
        $0.outPoint.index = txIdx         // outpoint index of this this UTXO
        $0.outPoint.sequence = UINT32_MAX
        $0.amount = value // value of this UTXO
        $0.script = Data(hexString: scriptHex)!
                                    }
utxos.append(utxo)

Signing Input

let input = BitcoinSigningInput.with {
                                    $0.hashType = BitcoinSigHashType.all.rawValue
                                    $0.amount = satoshi
                                    $0.byteFee = byteFee
                                    $0.toAddress = targetAddress!
                                    $0.changeAddress = changeAddress
                                    $0.utxo = utxos
                                    $0.privateKey = [privateKey.data]
                                }

I can successfully sign a transaction of an address with BECH32 (P2WPKH) format., but when signing a transaction with BASE58 (P2SH) I get the error message: "Missing Redeem script"

To Reproduce Sign bitcoin transaction with utxos of a P2SH address like

[{"_id":"5e0e8bfd02435b4daff5b4b4","chain":"BTC","network":"mainnet","coinbase":false,"mintIndex":0,"spentTxid":"","mintTxid":"43d83f9008a85f4c9f6413f566c9cbfcd2f42af73395b1f482debe3e9c2617d7","mintHeight":611011,"spentHeight":-2,"address":"3L4SRknyDsWA7qmxk5gqp7RFRFK4CDwgZp","script":"a914c97f7434a63e8cbdf268f5acad847089302d2b8387","value":14000,"confirmations":-1}]

Utxo input that can successfully be signed

[{"_id":"5e142e5002435b4daf82afc6","chain":"BTC","network":"mainnet","coinbase":false,"mintIndex":1,"spentTxid":"","mintTxid":"c4bdd44b9a541c66b1b7211a0e3cd60d246e6739c9a16e6f2e7d22e81a467367","mintHeight":611694,"spentHeight":-2,"address":"bc1qj7w9lzlgaz79nlq7y585qvrwp75aa73ajqxlzw","script":"0014979c5f8be8e8bc59fc1e250f40306e0fa9defa3d","value":1870,"confirmations":-1}]

Additional context I am using the 'TrustWalletCore' pod on ios 11.0

optout21 commented 4 years ago

What is scriptHex in your example? In the example guide following script is used:

$0.script = BitcoinScript.buildForAddress(address: address, coin: .bitcoinCash).data // Build lock script from address or public key hash
hochbruj commented 4 years ago

scriptHex is "a914c97f7434a63e8cbdf268f5acad847089302d2b8387" I did a check and if I do

BitcoinScript.buildForAddress(address: senderAddress, coin: .bitcoin).data.hexString

with senderAddress = "3L4SRknyDsWA7qmxk5gqp7RFRFK4CDwgZp" it returns the same hex string. so both

$.script = BitcoinScript.buildForAddress(address: senderAddress, coin: .bitcoin).data

and

$0.script = Data(hexString: scriptHex)!

return the same error "Missing redeem script"

hewigovens commented 4 years ago

Are you using p2sh-p2wpkh? if so, you have to build script by calling buildPayToWitnessPubkeyHash

hochbruj commented 4 years ago

I followed your instructions and was able to successfully sign a transaction by adding this code:

//get public key hash
   let ypub = hd_wallet.getExtendedPublicKey(purpose: .bip49, coin: .bitcoin, version: .ypub)
   let ypubAddress = HDWallet.derive(from: ypub, at: path)!
   let ypubHash = ypubAddress.bitcoinKeyHash

   let p2sh = BitcoinScript.buildPayToWitnessPubkeyHash(hash: ypubHash)
   $0.script = p2sh.data

But when broadcasting I get the error: "Code: -26, Error: bad-txns-nonstandard-inputs (code 64)" What am I missing?

signed transaction output:

0100000000010188a0e7c7c6b385f02f52d0b392b9fda3a5a5e76de047c769b75ca790e84f9e200000000000ffffffff02881300000000000016001472ab1430f60f6cc2826b3908003d9eca7e442755c41100000000000017a914ba5c8d91d100b7ff0b2741708fef1f426e8be70c8702473044022026db6e22a1e4e670ec44797160345378bb5d5c988d722057576d971b7463fe5c02207fd3d9de878a4759186e4a57e102348ddb985907253ec5d5c4c37c17e2d694360121026ec9ce0cdbc5b051e3637830c1f12e6048cca4845790f1fe0a28b979e6b10eee00000000

decoded:

{
    "version": 1,
    "locktime": 0,
    "ins": [
        {
            "n": 0,
            "script": {
                "asm": "",
                "hex": ""
            },
            "sequence": 4294967295,
            "txid": "209e4fe890a75cb769c747e06de7a5a5a3fdb992b3d0522ff085b3c6c7e7a088",
            "witness": [
                "3044022026db6e22a1e4e670ec44797160345378bb5d5c988d722057576d971b7463fe5c02207fd3d9de878a4759186e4a57e102348ddb985907253ec5d5c4c37c17e2d6943601",
                "026ec9ce0cdbc5b051e3637830c1f12e6048cca4845790f1fe0a28b979e6b10eee"
            ]
        }
    ],
    "outs": [
        {
            "script": {
                "addresses": [
                    "bc1qw243gv8kpakv9qnt8yyqq0v7eflygf647c68ec"
                ],
                "asm": "OP_0 72ab1430f60f6cc2826b3908003d9eca7e442755",
                "hex": "001472ab1430f60f6cc2826b3908003d9eca7e442755"
            },
            "value": 5000
        },
        {
            "script": {
                "addresses": [
                    "3JgQUvJY51skxXaY1i6ZDAvMQVBYBPw8ub"
                ],
                "asm": "OP_HASH160 ba5c8d91d100b7ff0b2741708fef1f426e8be70c OP_EQUAL",
                "hex": "a914ba5c8d91d100b7ff0b2741708fef1f426e8be70c87"
            },
            "value": 4548
        }
    ],
    "hash": "83542b3d6b972632f01cc96808702f6153d1ed20022adc7fbcce266ff0c1f18f",
    "txid": "83542b3d6b972632f01cc96808702f6153d1ed20022adc7fbcce266ff0c1f18f"
}
hewigovens commented 4 years ago

There is a scripts property in BitcoinSigningInput, so you build the redeem script with buildPayToWitnessPubkeyHash

scripts[<lock script>(your original scriptHex)] = <redeem script>
hochbruj commented 4 years ago

Thanks for your help. I managed to sign and broadcast a transaction with this additional code:

let redeemScript = BitcoinScript.buildPayToWitnessPubkeyHash(hash: ypubHash).data
let redeemScriptHashString = Hash.sha256RIPEMD(data: redeemScript).hexString
$0.scripts[redeemScriptHashString] = redeemScript
hewigovens commented 4 years ago

now we added a P2SH-P2WPKH test here: https://github.com/trustwallet/wallet-core/blob/9c5927e5ac45fb57339f4d91efbc71154aaa2c70/swift/Tests/Blockchains/BItcoinTests.swift#L84

akhilccrb commented 2 years ago

let scriptHash = lockScript.matchPayToScriptHash()!

This code getting crash can you check ?