CoreBitcoin icon indicating copy to clipboard operation
CoreBitcoin copied to clipboard

TransactionBuilder help please

Open Fonta1n3 opened this issue 7 years ago • 16 comments

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.

Fonta1n3 avatar Feb 11 '18 07:02 Fonta1n3

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"

mariusgab avatar Feb 12 '18 10:02 mariusgab

Hi @TripKey , did you solve it?

vladislav-k avatar Mar 06 '18 14:03 vladislav-k

@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.

Fonta1n3 avatar Mar 07 '18 00:03 Fonta1n3

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

tbsiosdev avatar Mar 27 '18 08:03 tbsiosdev

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.

TBSMobile avatar Mar 27 '18 11:03 TBSMobile

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

Fonta1n3 avatar Mar 27 '18 15:03 Fonta1n3

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.

TBSMobile avatar Mar 28 '18 06:03 TBSMobile

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 avatar Mar 28 '18 11:03 Fonta1n3

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.

Fonta1n3 avatar Mar 28 '18 15:03 Fonta1n3

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

TBSMobile avatar Mar 29 '18 04:03 TBSMobile

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

tbsiosdev avatar Jun 14 '18 08:06 tbsiosdev

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.

Fonta1n3 avatar Jun 28 '18 22:06 Fonta1n3

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.

tbsiosdev avatar Jun 29 '18 05:06 tbsiosdev

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")];

iceshard899 avatar Sep 07 '18 17:09 iceshard899

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

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

AlleniCode avatar Sep 15 '18 04:09 AlleniCode

For that transaction witness class is missing.

tbsiosdev avatar Jan 04 '19 10:01 tbsiosdev