예제 #1
0
 def accept_order(self, new_order):  # auto
     new_order['state'] = 'accepted'
     seller = new_order['seller'].decode('hex')
     buyer = new_order['buyer'].decode('hex')
     print "accept order", new_order
     new_order['escrows'] = [new_order.get('escrows')[0]]
     escrow = new_order['escrows'][0].decode('hex')
     self._multisig = Multisig(None, 2, [buyer, seller, escrow])
     new_order['address'] = self._multisig.address
     self._orders[new_order['id']] = new_order
     self._transport.send(new_order, new_order['buyer'].decode('hex'))
예제 #2
0
    def accept_order(self, new_order): 
    
    	# TODO: Need to have a check for the vendor to agree to the order        
		
        new_order['state'] = 'accepted'
        seller = new_order['seller'].decode('hex')
        buyer = new_order['buyer'].decode('hex')
        
        new_order['escrows'] = [new_order.get('escrows')[0]]
        escrow = new_order['escrows'][0].decode('hex')
        
        self._multisig = Multisig(None, 2, [buyer, seller, escrow])
        
        new_order['address'] = self._multisig.address
        
        self._transport.send(new_order, new_order['buyer'].decode('hex'))
예제 #3
0
    def accept_order(self, new_order):

        # TODO: Need to have a check for the vendor to agree to the order

        new_order['state'] = Orders.State.ACCEPTED
        seller = new_order['seller']
        buyer = new_order['buyer']

        new_order['escrows'] = [new_order.get('escrows')[0]]
        escrow = new_order['escrows'][0]

        # Create 2 of 3 multisig address
        self._multisig = Multisig(None, 2, [seller, buyer, escrow])

        new_order['address'] = self._multisig.address

        if len(self.db.selectEntries("orders", {"order_id": new_order['id']})) > 0:
            self.db.updateEntries("orders", {"order_id": new_order['id']}, {new_order})
        else:
            self.db.insertEntry("orders", new_order)

        self.transport.send(new_order, new_order['buyer'].decode('hex'))
예제 #4
0
    def handle_notarized_order(self, msg):
        self._log.info(msg['rawContract'])

        contract = msg['rawContract']

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = offer_data[0:index_of_seller_signature]
        self._log.info('Offer Data: %s' % offer_data_json)
        offer_data_json = json.loads(str(offer_data_json))

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)
        self._log.info('Bid Data: %s' % bid_data_json)

        # Find Notary Data in Contract
        notary_data_index = offer_data.find('"Notary"', end_of_bid_index,
                                            len(offer_data))
        end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                              notary_data_index,
                                              len(offer_data))
        notary_data_json = "{" + offer_data[
            notary_data_index:end_of_notary_index]
        notary_data_json = json.loads(notary_data_json)
        self._log.info('Notary Data: %s' % notary_data_json)

        # Generate multi-sig address
        multisig = Multisig(None, 2, [
            offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'].decode(
                'hex'),
            bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'].decode(
                'hex'), notary_data_json['Notary']
            ['notary_BTC_uncompressed_pubkey'].decode('hex')
        ])
        multisig_address = multisig.address

        seller_GUID = offer_data_json['Seller']['seller_GUID']

        order_id = bid_data_json['Buyer']['buyer_order_id']

        contract_key = hashlib.sha1(str(contract)).hexdigest()
        hash_value = hashlib.new('ripemd160')
        hash_value.update(contract_key)
        contract_key = hash_value.hexdigest()

        if seller_GUID == self._transport._guid:
            self._log.info('I am the seller!')
            state = 'Waiting for Payment'

            merchant_order_id = random.randint(0, 1000000)
            while self._db.numEntries("orders", "id = '%s'" % order_id) > 0:
                merchant_order_id = random.randint(0, 1000000)

            buyer_id = str(bid_data_json['Buyer']['buyer_GUID']) + '-' + str(
                bid_data_json['Buyer']['buyer_order_id'])

            self._db.insertEntry(
                "orders", {
                    'market_id':
                    self._transport._market_id,
                    'contract_key':
                    contract_key,
                    'order_id':
                    merchant_order_id,
                    'signed_contract_body':
                    str(contract),
                    'state':
                    state,
                    'buyer_order_id':
                    buyer_id,
                    'merchant':
                    offer_data_json['Seller']['seller_GUID'],
                    'buyer':
                    bid_data_json['Buyer']['buyer_GUID'],
                    'notary':
                    notary_data_json['Notary']['notary_GUID'],
                    'address':
                    multisig_address,
                    'item_price':
                    offer_data_json['Contract']['item_price'],
                    'shipping_price':
                    offer_data_json['Contract']['item_delivery']
                    ['shipping_price'] if offer_data_json['Contract']
                    ['item_delivery'].has_key('shipping_price') else "",
                    'note_for_merchant':
                    bid_data_json['Buyer']['note_for_seller'],
                    "updated":
                    time.time()
                })

        else:
            self._log.info('I am the buyer')
            state = 'Need to Pay'

            self._db.updateEntries("orders", {'order_id': order_id}, {
                'market_id':
                self._transport._market_id,
                'contract_key':
                contract_key,
                'signed_contract_body':
                str(contract),
                'state':
                state,
                'merchant':
                offer_data_json['Seller']['seller_GUID'],
                'buyer':
                bid_data_json['Buyer']['buyer_GUID'],
                'notary':
                notary_data_json['Notary']['notary_GUID'],
                'address':
                multisig_address,
                'item_price':
                offer_data_json['Contract']['item_price'],
                'shipping_price':
                offer_data_json['Contract']['item_delivery']['shipping_price']
                if offer_data_json['Contract']['item_delivery'].has_key(
                    'shipping_price') else "",
                'note_for_merchant':
                bid_data_json['Buyer']['note_for_seller'],
                "updated":
                time.time()
            })
예제 #5
0
    def handle_bid_order(self, bid):

        self._log.info('Bid Order: %s' % bid)

        # Generate unique id for this bid
        order_id = random.randint(0, 1000000)
        while self._db.numEntries("contracts", "id = '%s'" % order_id) > 0:
            order_id = random.randint(0, 1000000)

        # Add to contract and sign
        contract = bid.get('rawContract')

        # Check signature and verify of seller and bidder contract
        seed_contract = self.get_seed_contract_from_doublesigned(contract)
        seed_contract_json = self.get_json_from_doublesigned_contract(
            seed_contract)
        #seed_contract = seed_contract.replace('- -----','-----')

        #self._log.debug('seed contract %s' % seed_contract)
        self._log.debug('seed contract json %s' % seed_contract_json)

        contract_stripped = "".join(contract.split('\n'))

        self._log.info(contract_stripped)
        bidder_pgp_start_index = contract_stripped.find(
            "buyer_pgp", 0, len(contract_stripped))
        bidder_pgp_end_index = contract_stripped.find("buyer_GUID", 0,
                                                      len(contract_stripped))
        bidder_pgp = contract_stripped[bidder_pgp_start_index +
                                       13:bidder_pgp_end_index]
        self._log.info(bidder_pgp)

        self._gpg.import_keys(bidder_pgp)
        v = self._gpg.verify(contract)
        if v:
            self._log.info('Sellers contract verified')

        notary = {}
        notary['Notary'] = {
            'notary_GUID': self._transport._guid,
            'notary_BTC_uncompressed_pubkey':
            self._transport.settings['pubkey'],
            'notary_pgp': self._transport.settings['PGPPubKey'],
            'notary_fee': "1%",
            'notary_order_id': order_id
        }

        self._log.debug('Notary: %s' % notary)

        gpg = self._gpg

        # Prepare contract body
        json_string = json.dumps(notary, indent=0)
        seg_len = 52
        out_text = string.join(
            map(lambda x: json_string[x:x + seg_len],
                range(0, len(json_string), seg_len)), "\n")

        # Append new data to contract
        out_text = "%s\n%s" % (contract, out_text)

        signed_data = gpg.sign(
            out_text,
            passphrase='P@ssw0rd',
            keyid=self._transport.settings.get('PGPPubkeyFingerprint'))

        self._log.debug('Double-signed Contract: %s' % signed_data)

        # Hash the contract for storage
        contract_key = hashlib.sha1(str(signed_data)).hexdigest()
        hash_value = hashlib.new('ripemd160')
        hash_value.update(contract_key)
        contract_key = hash_value.hexdigest()

        self._log.info('Order ID: %s' % order_id)

        # Push buy order to DHT and node if available
        # self._transport._dht.iterativeStore(self._transport, contract_key, str(signed_data), self._transport._guid)
        #self.update_listings_index()

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = "{\"Seller\": {" + offer_data[
            0:index_of_seller_signature]
        self._log.info('Offer Data: %s' % offer_data_json)
        offer_data_json = json.loads(str(offer_data_json))

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)
        self._log.info('Bid Data: %s' % bid_data_json)

        buyer_order_id = bid_data_json['Buyer']['buyer_GUID'] + '-' + str(
            bid_data_json['Buyer']['buyer_order_id'])

        multisig = Multisig(None, 2, [
            offer_data_json['Seller']['seller_BTC_uncompressed_pubkey'].decode(
                'hex'),
            bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'].decode(
                'hex'), self._transport.settings['pubkey'].decode('hex')
        ])
        multisig_address = multisig.address

        self._db.insertEntry(
            "orders", {
                'market_id':
                self._transport._market_id,
                'contract_key':
                contract_key,
                'signed_contract_body':
                str(signed_data),
                'state':
                Orders.State.NOTARIZED,
                'buyer_order_id':
                buyer_order_id,
                'order_id':
                order_id,
                'merchant':
                offer_data_json['Seller']['seller_GUID'],
                'buyer':
                bid_data_json['Buyer']['buyer_GUID'],
                'address':
                multisig_address,
                'item_price':
                offer_data_json['Contract']['item_price'],
                'shipping_price':
                offer_data_json['Contract']['item_delivery']['shipping_price']
                if offer_data_json['Contract']['item_delivery'].has_key(
                    'shipping_price') else "",
                'note_for_merchant':
                bid_data_json['Buyer']['note_for_seller'],
                "updated":
                time.time()
            })

        # Send order to seller and buyer
        self._log.info('Sending notarized contract to buyer and seller %s' %
                       bid)

        notarized_order = {
            "type": "order",
            "state": "Notarized",
            "rawContract": str(signed_data)
        }

        self._log.info('SELLER %s' % offer_data_json['Seller']['seller_GUID'])

        self._transport.send(notarized_order,
                             offer_data_json['Seller']['seller_GUID'])
        self._transport.send(notarized_order,
                             bid_data_json['Buyer']['buyer_GUID'])
예제 #6
0
    def client_release_payment(self, socket_handler, msg):
        self._log.info('Releasing payment to Merchant %s' % msg)

        order = self._market.orders.get_order(msg['orderId'])
        contract = order['signed_contract_body']

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = offer_data[0:index_of_seller_signature]
        offer_data_json = json.loads(offer_data_json)
        self._log.info('Offer Data: %s' % offer_data_json)

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)

        # Find Notary Data in Contract
        notary_data_index = offer_data.find('"Notary"', end_of_bid_index,
                                            len(offer_data))
        end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                              notary_data_index,
                                              len(offer_data))
        notary_data_json = "{" + offer_data[
            notary_data_index:end_of_notary_index]
        notary_data_json = json.loads(notary_data_json)
        self._log.info('Notary Data: %s' % notary_data_json)

        try:

            client = obelisk.ObeliskOfLightClient(
                'tcp://obelisk.openbazaar.org:9091')

            pubkeys = [
                offer_data_json['Seller']
                ['seller_BTC_uncompressed_pubkey'].decode('hex'),
                bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'].decode(
                    'hex'), notary_data_json['Notary']
                ['notary_BTC_uncompressed_pubkey'].decode('hex')
            ]

            multisig = Multisig(client, 2, pubkeys)

            def cb(ec, history):

                # Debug
                self._log.info('%s %s' % (ec, history))
                for item in history:
                    self._log.info(item[0].encode('hex'))

                if ec is not None:
                    self._log.error("Error fetching history: %s" % ec)
                    # TODO: Send error message to GUI
                    return

                # Create unsigned transaction
                unspent = [row[:4] for row in history if row[4] is None]
                tx = multisig._build_actual_tx(unspent, '')
                self._log.info('TX %s' % tx)

            def get_history():
                client.fetch_history(multisig.address, cb)

            reactor.callFromThread(get_history)

            def finished_cb(msg):
                self._log.info('tx %s' % msg)

            #multisig.create_unsigned_transaction('16uniUFpbhrAxAWMZ9qEkcT9Wf34ETB4Tt', finished_cb)

            def fetched(ec, history):
                self._log.info(history)
                if ec is not None:
                    self._log.error("Error fetching history: %s" % ec)
                    return
                self._fetched(history, '1Fufjpf9RM2aQsGedhSpbSCGRHrmLMJ7yY',
                              finished_cb)

            #client.fetch_history('16uniUFpbhrAxAWMZ9qEkcT9Wf34ETB4Tt', fetched)

        except Exception, e:
            self._log.error('%s' % e)
예제 #7
0
파일: ws.py 프로젝트: votaguz/OpenBazaar
    def client_release_payment(self, socket_handler, msg):
        self._log.info('Releasing payment to Merchant %s' % msg)

        order = self._market.orders.get_order(msg['orderId'])
        contract = order['signed_contract_body']

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = offer_data[0:index_of_seller_signature]
        offer_data_json = json.loads(offer_data_json)
        self._log.info('Offer Data: %s' % offer_data_json)

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{" + offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)

        # Find Notary Data in Contract
        notary_data_index = offer_data.find('"Notary"', end_of_bid_index,
                                            len(offer_data))
        end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                              notary_data_index,
                                              len(offer_data))
        notary_data_json = "{" + offer_data[
            notary_data_index:end_of_notary_index]
        notary_data_json = json.loads(notary_data_json)
        self._log.info('Notary Data: %s' % notary_data_json)

        try:
            client = obelisk.ObeliskOfLightClient(
                'tcp://obelisk.openbazaar.org:9091')

            pubkeys = [
                offer_data_json['Seller']
                ['seller_BTC_uncompressed_pubkey'].decode('hex'),
                bid_data_json['Buyer']['buyer_BTC_uncompressed_pubkey'].decode(
                    'hex'), notary_data_json['Notary']
                ['notary_BTC_uncompressed_pubkey'].decode('hex')
            ]

            multisig = Multisig(client, 2, pubkeys)

            def cb(ec, history):

                # Debug
                self._log.info('%s %s' % (ec, history))

                if ec is not None:
                    self._log.error("Error fetching history: %s" % ec)
                    # TODO: Send error message to GUI
                    return

                # Create unsigned transaction
                unspent = [row[:4] for row in history if row[4] is None]
                tx = multisig._build_actual_tx(
                    unspent, '16uniUFpbhrAxAWMZ9qEkcT9Wf34ETB4Tt')
                self._log.info(tx.serialize().encode("hex"))

                private_key = self._market.private_key()

                multisig.sign_all_inputs(tx, private_key.decode('hex'))

                self.send_to_client(None, {
                    "type": "signed_tx_sent",
                    "test": "teest"
                })

            def get_history():
                client.fetch_history(multisig.address, cb)

            reactor.callFromThread(get_history)

            # def finished_cb(msg):
            #     self._log.info('tx %s' % msg)
            #
            # #multisig.create_unsigned_transaction('16uniUFpbhrAxAWMZ9qEkcT9Wf34ETB4Tt', finished_cb)
            #
            # def fetched(ec, history):
            #     self._log.info(history)
            #     if ec is not None:
            #         self._log.error("Error fetching history: %s" % ec)
            #         return
            #     self._fetched(history, '1EzD5Tj9fa5jqV1mCCBy7kW43TYEsJsZw6', finished_cb)
            #
            # #client.fetch_history('16uniUFpbhrAxAWMZ9qEkcT9Wf34ETB4Tt', fetched)
        except Exception, e:
            self._log.error('%s' % e)
예제 #8
0
    def on_release_funds_tx(self, msg):
        self._log.info('Receiving signed tx from buyer')

        buyer_order_id = str(msg['senderGUID']) + '-' + str(
            msg['buyer_order_id'])
        order = self._market.orders.get_order(buyer_order_id, by_buyer_id=True)
        contract = order['signed_contract_body']

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = offer_data[0:index_of_seller_signature]
        offer_data_json = json.loads(offer_data_json)
        self._log.info('Offer Data: %s' % offer_data_json)

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{"
        bid_data_json += offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)

        # Find Notary Data in Contract
        notary_data_index = offer_data.find('"Notary"', end_of_bid_index,
                                            len(offer_data))
        end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                              notary_data_index,
                                              len(offer_data))
        notary_data_json = "{"
        notary_data_json += offer_data[notary_data_index:end_of_notary_index]
        notary_data_json = json.loads(notary_data_json)
        self._log.info('Notary Data: %s' % notary_data_json)

        try:
            client = obelisk.ObeliskOfLightClient(
                'tcp://obelisk2.airbitz.co:9091')

            seller = offer_data_json['Seller']
            buyer = bid_data_json['Buyer']
            notary = notary_data_json['Notary']

            seller_key = seller['seller_BTC_uncompressed_pubkey']
            buyer_key = buyer['buyer_BTC_uncompressed_pubkey']
            notary_key = notary['notary_BTC_uncompressed_pubkey']

            pubkeys = [
                seller_key.decode('hex'),
                buyer_key.decode('hex'),
                notary_key.decode('hex')
            ]

            self._log.info('multisig pubkeys %s' % pubkeys)

            multisig = Multisig(client, 2, pubkeys)

            def cb(ec, history, order):

                # Debug
                self._log.info('%s %s' % (ec, history))

                if ec is not None:
                    self._log.error("Error fetching history: %s" % ec)
                    # TODO: Send error message to GUI
                    return

                # Create unsigned transaction
                unspent = [row[:4] for row in history if row[4] is None]
                tx = multisig._build_actual_tx(unspent,
                                               order['payment_address'])
                self._log.info(tx.serialize().encode("hex"))

                private_key = self._market.private_key()

                merchant_sigs = multisig.sign_all_inputs(
                    tx, private_key.decode('hex'))
                buyer_sigs = msg['signature']

                for i, input in enumerate(tx.inputs):
                    sigs = (buyer_sigs[i].decode('hex'),
                            merchant_sigs[i].decode('hex'))
                    script = "\x00"
                    for sig in sigs:
                        script += chr(len(sig)) + sig
                    script += "\x4c"
                    assert len(multisig.script) < 255
                    script += chr(len(multisig.script)) + multisig.script
                    print "Script:", script.encode("hex")
                    tx.inputs[i].script = script

                print tx
                print tx.serialize().encode("hex")

                Multisig.broadcast(tx)

            def get_history():
                client.fetch_history(
                    multisig.address,
                    lambda ec, history, order=order: cb(ec, history, order))

            reactor.callFromThread(get_history)

        except Exception, e:
            self._log.error('%s' % e)
예제 #9
0
    def client_release_payment(self, socket_handler, msg):
        self._log.info('Releasing payment to Merchant %s' % msg)

        order = self._market.orders.get_order(msg['orderId'])
        contract = order['signed_contract_body']

        # Find Seller Data in Contract
        offer_data = ''.join(contract.split('\n')[8:])
        index_of_seller_signature = offer_data.find(
            '- - -----BEGIN PGP SIGNATURE-----', 0, len(offer_data))
        offer_data_json = offer_data[0:index_of_seller_signature]
        offer_data_json = json.loads(offer_data_json)
        self._log.info('Offer Data: %s' % offer_data_json)

        # Find Buyer Data in Contract
        bid_data_index = offer_data.find('"Buyer"', index_of_seller_signature,
                                         len(offer_data))
        end_of_bid_index = offer_data.find('- -----BEGIN PGP SIGNATURE',
                                           bid_data_index, len(offer_data))
        bid_data_json = "{"
        bid_data_json += offer_data[bid_data_index:end_of_bid_index]
        bid_data_json = json.loads(bid_data_json)

        # Find Notary Data in Contract
        notary_data_index = offer_data.find('"Notary"', end_of_bid_index,
                                            len(offer_data))
        end_of_notary_index = offer_data.find('-----BEGIN PGP SIGNATURE',
                                              notary_data_index,
                                              len(offer_data))
        notary_data_json = "{"
        notary_data_json += offer_data[notary_data_index:end_of_notary_index]
        notary_data_json = json.loads(notary_data_json)
        self._log.info('Notary Data: %s' % notary_data_json)

        try:
            client = obelisk.ObeliskOfLightClient(
                'tcp://obelisk2.airbitz.co:9091')

            seller = offer_data_json['Seller']
            buyer = bid_data_json['Buyer']
            notary = notary_data_json['Notary']

            seller_key = seller['seller_BTC_uncompressed_pubkey']
            buyer_key = buyer['buyer_BTC_uncompressed_pubkey']
            notary_key = notary['notary_BTC_uncompressed_pubkey']

            pubkeys = [
                seller_key.decode('hex'),
                buyer_key.decode('hex'),
                notary_key.decode('hex')
            ]

            multisig = Multisig(client, 2, pubkeys)

            def cb(ec, history, order):

                # Debug
                self._log.info('%s %s' % (ec, history))

                if ec is not None:
                    self._log.error("Error fetching history: %s" % ec)
                    # TODO: Send error message to GUI
                    return

                # Create unsigned transaction
                unspent = [row[:4] for row in history if row[4] is None]
                tx = multisig._build_actual_tx(unspent,
                                               order['payment_address'])
                self._log.info(tx.serialize().encode("hex"))

                private_key = self._market.private_key()

                signatures = multisig.sign_all_inputs(
                    tx, private_key.decode('hex'))
                tx_serialized = tx.serialize().encode("hex")
                self._market.release_funds_to_merchant(buyer['buyer_order_id'],
                                                       tx_serialized,
                                                       signatures,
                                                       order.get('merchant'))

                self._log.debug('Sent tx and signed inputs to merchant')

            def get_history():
                client.fetch_history(
                    multisig.address,
                    lambda ec, history, order=order: cb(ec, history, order))

            reactor.callFromThread(get_history)

        except Exception, e:
            self._log.error('%s' % e)