oleganza / CoreBitcoin

Awesome Bitcoin toolkit for ObjC and Swift
Do What The F*ck You Want To Public License
719 stars 255 forks source link

TransactionBuilder help please #96

Open Fonta1n3 opened 6 years ago

Fonta1n3 commented 6 years ago

Hi,

I am struggling to build a raw unsigned and signed transaction and was hoping you could help give me a bit of advise.

I am getting this error after i try and print the result of BTCTransactionBuilder:

error = Error Domain=com.oleganza.CoreBitcoin.TransactionBuilder Code=3 "(null)"

Here is the full function:

`func parseAddress(address: String) { print("getAddressTransactionInputs")

    var url:NSURL!
    url = NSURL(string: "https://testnet.blockchain.info/unspent?active=\(address)")

    let task = URLSession.shared.dataTask(with: url! as URL) { (data, response, error) -> Void in

        do {

            if error != nil {

                print(error as Any)

            } else {

                if let urlContent = data {

                    do {

                        let jsonAddressResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary

                        if let utxoCheck = jsonAddressResult["unspent_outputs"] as? NSArray {

                            var balance:Double = 0

                            for utxo in utxoCheck {

                                let utxoDictionary:NSDictionary! = utxo as! NSDictionary
                                print("utxo = \(utxoDictionary)")

                                var amount = Double()
                                var transactionHash = String()
                                var transactionOutputN = Double()
                                var lockingScript = String()
                                var transactionIndex = Double()

                                amount = utxoDictionary["value"] as! Double
                                transactionHash = utxoDictionary["tx_hash"] as! String
                                transactionOutputN = utxoDictionary["tx_output_n"] as! Double
                                lockingScript = utxoDictionary["script"] as! String
                                transactionIndex = utxoDictionary["tx_index"] as! Double
                           /*
                                print("transactionHash =\(transactionHash)")
                                print("transactionOutputN =\(transactionOutputN)")
                                print("lockingScript =\(lockingScript)")
                                print("transactionIndex =\(transactionIndex)")
                            */
                                balance = balance + amount

                                let script = BTCScript.init(hex: lockingScript)
                                let txId = transactionHash.data(using: .utf8)

                                let newInput = BTCTransactionInput()
                                newInput.previousHash = txId
                                newInput.previousIndex = UInt32(transactionIndex)
                                newInput.value = BTCAmount(balance)
                                newInput.signatureScript = script

                                let address = BTCAddress.init(string: "mxxky7EDvEVa4z9pwenveSMcj6L3CJ85di")
                                let primaryOutput = BTCTransactionOutput(value: 129870000, address: address)

                                let newTransaction = BTCTransactionBuilder()
                                newTransaction.shouldSign = false

                                let transaction = BTCTransaction()
                                transaction.addInput(newInput)
                                transaction.addOutput(primaryOutput)
                                transaction.fee = 130000

                                do {

                                    let transactionRaw = try newTransaction.buildTransaction()
                                    print("transactionRaw = \(transactionRaw)")

                                } catch {

                                    print("error = \(error as Any)")

                                }
                            }
                        }

                    } catch {

                        print("JSon processing failed")

                    }
                }
            }
        }
    }

    task.resume()
}`

Thanks to anyone very much for any help or letting me know what i'm doing wrong.

mariusgab commented 6 years ago

how you managed to install the library in the first place? for me it gives an error when running pod install: "target has transitive dependencies that include static binaries"

vladislav-k commented 6 years ago

Hi @TripKey , did you solve it?

Fonta1n3 commented 6 years ago

@vladislav-k no :( I gave up and have been putting my attention elsewhere. Maybe you can play with my code and see if you can get it to work. Please let me know if you do.

tbsiosdev commented 6 years ago

If anyone resolves it please help to make a transaction. with Proper Code.

TBSMobile commented 6 years ago

Here I got Solution. if you implement this method you can get transaction raw.

func callBTCTransaction() { let address = BTCAddress(string: receiverAddress) let newTransaction = BTCTransactionBuilder() newTransaction.dataSource = self newTransaction.shouldSign = false newTransaction.changeAddress = BTCAddress(string: newAddress) newTransaction.outputs = [BTCTransactionOutput(value: BTCAmount(5000000), address: address)] newTransaction.feeRate = BTCAmount(5000) var result:BTCTransactionBuilderResult? = nil do { result = try newTransaction.buildTransaction() print("transactionRaw = (String(describing: result?.transaction))") } catch { print("error = (error as Any)") } }

Datasource Methods:

func unspentOutputs(for txbuilder: BTCTransactionBuilder!) -> NSEnumerator! { let outputs = NSMutableArray() for item in inputData { let txout = BTCTransactionOutput() txout.value = BTCAmount((item as! NSDictionary).value(forKey: "value") as! Int64) txout.script = BTCScript.init(hex: (item as! NSDictionary).value(forKey: "script") as! String) txout.index = UInt32((item as! NSDictionary).value(forKey: "tx_output_n") as! Int) txout.confirmations = UInt((item as! NSDictionary).value(forKey: "confirmations") as! Int) let transactionHash = (item as! NSDictionary)["tx_hash"] as! String txout.transactionHash = transactionHash.data(using: .utf8) outputs.add(txout) } return outputs.objectEnumerator() }

Hope you get This Answer.

Fonta1n3 commented 6 years ago

Thank you so very much I was able to build the transaction succesfully! :)

TBSMobile commented 6 years ago

Hi TripKey, Can you please share remaining transaction broadcast method? we have an issue to make a transaction complete?

can you please help us.

we are using API: "https://testnet.blockchain.info/pushtx" in body part passing: "tx=transaction data"

we are implementing in swift4.0.

Fonta1n3 commented 6 years ago

Hi Saz,

My goal was to get a successful raw transaction output in hex form which i was able to do, unfortunately when i go to decode it on the testnet at https://live.blockcypher.com/btc-testnet/decodetx/ it returns the error:

{ "error": "sequence too long" }

So i don't have any code yet for signing the transaction or broadcasting it yet.

Could you please share with me your code for creating/signing the transaction so we can compare?

I am going to keep trying and will update when I figure out what i'm doing wrong.

Fonta1n3 commented 6 years ago

Here is my full code, again when I put the result of: print("transactionRaw = (String(describing: result?.transaction))")

in hex form of raw transaction into the decoder at https://live.blockcypher.com/btc-testnet/decodetx/it returns

"error": "sequence too long"

Here is full code:

`import UIKit

class TransactionBuilderViewController: UIViewController, BTCTransactionBuilderDataSource {

var unspentOutputs = NSMutableArray()
let btcAddress = "mo7WCetPLw6yMkT7MdzYfQ1L4eWqAuT2j7"

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    print("TransactionBuilderViewController")
    parseAddress(address: btcAddress)

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func parseAddress(address: String) {
    print("getAddressTransactionInputs")

    var url:NSURL!
    url = NSURL(string: "https://testnet.blockchain.info/unspent?active=\(address)")

    let task = URLSession.shared.dataTask(with: url! as URL) { (data, response, error) -> Void in

        do {

            if error != nil {

                print(error as Any)

             } else {

                if let urlContent = data {

                    do {

                        let jsonAddressResult = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary

                        if let utxoCheck = jsonAddressResult["unspent_outputs"] as? NSArray {

                            print("utxoCheck = \(utxoCheck)")

                            self.unspentOutputs = utxoCheck.mutableCopy() as! NSMutableArray

                            self.callBTCTransaction()

                        }

                    } catch {

                        print("JSon processing failed")

                    }
                }
            }
        }
    }

    task.resume()

}

func callBTCTransaction() {

    let address = BTCAddress(string: "mxxky7EDvEVa4z9pwenveSMcj6L3CJ85di")
    let newTransaction = BTCTransactionBuilder()
    newTransaction.dataSource = self
    newTransaction.shouldSign = true
    newTransaction.changeAddress = BTCAddress(string: self.btcAddress)
    newTransaction.outputs = [BTCTransactionOutput(value: BTCAmount(50000), address: address)]
    newTransaction.feeRate = BTCAmount(5000)
    var result:BTCTransactionBuilderResult? = nil
    do {
        result = try newTransaction.buildTransaction()
        print("transactionRaw = \(String(describing: result?.transaction))")

    } catch {
        print("error = \(error as Any)")
    }
}

func unspentOutputs(for txbuilder: BTCTransactionBuilder!) -> NSEnumerator! {

    let outputs = NSMutableArray()

    for item in self.unspentOutputs {

        print("item = \(item)")

        let txout = BTCTransactionOutput()
        txout.value = BTCAmount((item as! NSDictionary).value(forKey: "value") as! Int64)
        txout.script = BTCScript.init(hex: (item as! NSDictionary).value(forKey: "script") as! String)
        txout.index = UInt32((item as! NSDictionary).value(forKey: "tx_output_n") as! Int)
        txout.confirmations = UInt((item as! NSDictionary).value(forKey: "confirmations") as! Int)
        let transactionHash = (item as! NSDictionary)["tx_hash"] as! String
        txout.transactionHash = transactionHash.data(using: .utf8)
        outputs.add(txout)

    }

    return outputs.objectEnumerator()

}

} `

I know I am missing something dumb and obvious but I can't figure it out. Any help much appreciated.

TBSMobile commented 6 years ago

Hi Trip, let me figure out this problem once I will complete it after that provide full code.

tbsiosdev commented 6 years ago

Hi, FontaineDenton can please refer this class you can get your answer. just read carefully.

https://github.com/oleganza/CoreBitcoin/blob/master/CoreBitcoin/BTCTransaction%2BTests.m

Fonta1n3 commented 6 years ago

I appreciate you reaching out tbsiosdev, unfortunately I only know swift and its just too confusing reading obj-c.. Ive looked it over many times and tried and tried but my raw transaction data doesn't seem to be valid. If you have a swift example id very appreciative.

tbsiosdev commented 6 years ago

Hi Fontaine, I am working both the language in one common project. Making a raw transaction, I am using swift and objC Class. I am passing value from swift class to objC and objC Class Provides me Raw transaction. So, My suggestion is that please try to learn basic of objC then implement it You will succeed it.

iceshard899 commented 6 years ago

I guess you can just add an output with the OP_RETURN followed by the hex.

 BTCScript *script = [[BTCScript alloc]init];
 [script appendOpcode:OP_RETURN];
 [script appendData:BTCDataFromHex(@"4d454c4f4e530a0a")];
AlleniCode commented 6 years ago

@FontaineDenton @Kampeone @vladislav-k @tbsiosdev @SazzadIproliya

How to sig a transaction with P2SH script UTXOs? Thx!

tbsiosdev commented 5 years ago

For that transaction witness class is missing.