def release_funds(self, order_id): """ This function should be called to release funds from a disputed contract after the moderator has resolved the dispute and provided his signature. """ if os.path.exists(DATA_FOLDER + "purchases/in progress/" + order_id + ".json"): file_path = DATA_FOLDER + "purchases/trade receipts/" + order_id + ".json" outpoints = pickle.loads(self.db.Purchases().get_outpoint(order_id)) elif os.path.exists(DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json"): file_path = DATA_FOLDER + "store/contracts/in progress/" + order_id + ".json" outpoints = pickle.loads(self.db.Sales().get_outpoint(order_id)) with open(file_path, 'r') as filename: contract = json.load(filename, object_pairs_hook=OrderedDict) vendor_address = contract["vendor_order_confirmation"]["invoice"]["payout"]["address"] buyer_address = contract["buyer_order"]["order"]["refund_address"] for moderator in contract["vendor_offer"]["listing"]["moderators"]: if moderator["guid"] == contract["buyer_order"]["order"]["moderator"]: masterkey_m = moderator["pubkeys"]["bitcoin"]["key"] outputs = [] outputs.append({'value': contract["dispute_resolution"]["resolution"]["moderator_fee"], 'address': contract["dispute_resolution"]["resolution"]["moderator_address"]}) if "buyer_payout" in contract["dispute_resolution"]["resolution"]: outputs.append({'value': contract["dispute_resolution"]["resolution"]["buyer_payout"], 'address': buyer_address}) if "vendor_payout" in contract["dispute_resolution"]["resolution"]: outputs.append({'value': contract["dispute_resolution"]["resolution"]["vendor_payout"], 'address': vendor_address}) tx = bitcointools.mktx(outpoints, outputs) signatures = [] chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"] redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"]) masterkey = bitcointools.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey) childkey = derive_childkey(masterkey, chaincode, bitcointools.MAINNET_PRIVATE) mod_key = derive_childkey(masterkey_m, chaincode) valid_inputs = 0 for index in range(0, len(outpoints)): sig = bitcointools.multisign(tx, index, redeem_script, childkey) signatures.append({"input_index": index, "signature": sig}) for s in contract["dispute_resolution"]["resolution"]["tx_signatures"]: if s["input_index"] == index: if bitcointools.verify_tx_input(tx, index, redeem_script, s["signature"], mod_key): tx = bitcointools.apply_multisignatures(tx, index, str(redeem_script), sig, str(s["signature"])) valid_inputs += 1 if valid_inputs == len(outpoints): self.log.info("Broadcasting payout tx %s to network" % bitcointools.txhash(tx)) self.protocol.multiplexer.blockchain.broadcast(tx) else: raise Exception("Failed to reconstruct transaction with moderator signature.")
def rpc_order(self, sender, pubkey, encrypted): try: box = Box(PrivateKey(self.signing_key.encode(nacl.encoding.RawEncoder)), PublicKey(pubkey)) order = box.decrypt(encrypted) c = Contract(self.db, contract=json.loads(order, object_pairs_hook=OrderedDict), testnet=self.multiplexer.testnet) if c.verify(sender.signed_pubkey[64:]): self.router.addContact(sender) self.log.info("received an order from %s, waiting for payment..." % sender) payment_address = c.contract["buyer_order"]["order"]["payment"]["address"] chaincode = c.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = c.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) amount = c.contract["buyer_order"]["order"]["payment"]["amount"] listing_hash = c.contract["buyer_order"]["order"]["ref_hash"] signature = self.signing_key.sign( str(payment_address) + str(amount) + str(listing_hash) + str(buyer_key))[:64] c.await_funding(self.get_notification_listener(), self.multiplexer.blockchain, signature, False) return [signature] else: self.log.warning("received invalid order from %s" % sender) return ["False"] except Exception: self.log.error("unable to decrypt order from %s" % sender) return ["False"]
def rpc_order(self, sender, pubkey, encrypted): try: box = Box(self.signing_key.to_curve25519_private_key(), PublicKey(pubkey)) order = box.decrypt(encrypted) c = Contract(self.db, contract=json.loads(order, object_pairs_hook=OrderedDict), testnet=self.multiplexer.testnet) v = c.verify(sender.pubkey) if v is True: self.router.addContact(sender) self.log.info("received an order from %s, waiting for payment..." % sender) payment_address = c.contract["buyer_order"]["order"]["payment"]["address"] chaincode = c.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = c.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) amount = c.contract["buyer_order"]["order"]["payment"]["amount"] listing_hash = c.contract["vendor_offer"]["listing"]["contract_id"] signature = self.signing_key.sign( str(payment_address) + str(amount) + str(listing_hash) + str(buyer_key))[:64] c.await_funding(self.get_notification_listener(), self.multiplexer.blockchain, signature, False) return [signature] else: self.log.warning("received invalid order from %s reason %s" % (sender, v)) return ["False"] except Exception, e: self.log.error("Exception (%s) occurred processing order from %s" % (e.message, sender)) return ["False"]
def rpc_order(self, sender, pubkey, encrypted): try: box = Box(self.signing_key.to_curve25519_private_key(), PublicKey(pubkey)) order = box.decrypt(encrypted) c = Contract(self.db, contract=json.loads(order, object_pairs_hook=OrderedDict), testnet=self.multiplexer.testnet) if c.verify(sender.pubkey): self.router.addContact(sender) self.log.info("received an order from %s, waiting for payment..." % sender) payment_address = c.contract["buyer_order"]["order"]["payment"]["address"] chaincode = c.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = c.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) amount = c.contract["buyer_order"]["order"]["payment"]["amount"] listing_hash = c.contract["vendor_offer"]["listing"]["contract_id"] signature = self.signing_key.sign( str(payment_address) + str(amount) + str(listing_hash) + str(buyer_key))[:64] c.await_funding(self.get_notification_listener(), self.multiplexer.blockchain, signature, False) return [signature] else: self.log.warning("received invalid order from %s" % sender) return ["False"] except Exception: self.log.error("unable to decrypt order from %s" % sender) return ["False"]
def parse_response(response): try: address = contract.contract["buyer_order"]["order"]["payment"]["address"] chaincode = contract.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = contract.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) amount = contract.contract["buyer_order"]["order"]["payment"]["amount"] listing_hash = contract.contract["vendor_offer"]["listing"]["contract_id"] verify_key = nacl.signing.VerifyKey(node_to_ask.pubkey) verify_key.verify(str(address) + str(amount) + str(listing_hash) + str(buyer_key), response[1][0]) return response[1][0] except Exception: return False
def parse_response(response): try: address = contract.contract["buyer_order"]["order"]["payment"]["address"] chaincode = contract.contract["buyer_order"]["order"]["payment"]["chaincode"] masterkey_b = contract.contract["buyer_order"]["order"]["id"]["pubkeys"]["bitcoin"] buyer_key = derive_childkey(masterkey_b, chaincode) amount = contract.contract["buyer_order"]["order"]["payment"]["amount"] listing_hash = contract.contract["buyer_order"]["order"]["ref_hash"] verify_key = nacl.signing.VerifyKey(node_to_ask.pubkey) verify_key.verify( str(address) + str(amount) + str(listing_hash) + str(buyer_key), response[1][0]) return response[1][0] except Exception: return False
def history_fetched(ec, history): outpoints = [] satoshis = 0 outputs = [] dispute_json = {"dispute_resolution": {"resolution": {}}} if ec: print ec else: for tx_type, txid, i, height, value in history: # pylint: disable=W0612 if tx_type == obelisk.PointIdent.Output: satoshis += value outpoint = txid.encode("hex") + ":" + str(i) if outpoint not in outpoints: outpoints.append(outpoint) satoshis -= TRANSACTION_FEE moderator_fee = round(float(moderator_percentage * satoshis)) satoshis -= moderator_fee outputs.append({'value': moderator_fee, 'address': moderator_address}) dispute_json["dispute_resolution"]["resolution"]["moderator_address"] = moderator_address dispute_json["dispute_resolution"]["resolution"]["moderator_fee"] = moderator_fee dispute_json["dispute_resolution"]["resolution"]["transaction_fee"] = TRANSACTION_FEE if float(buyer_percentage) > 0: amt = round(float(buyer_percentage * satoshis)) dispute_json["dispute_resolution"]["resolution"]["buyer_payout"] = amt outputs.append({'value': amt, 'address': buyer_address}) if float(vendor_percentage) > 0: amt = round(float(vendor_percentage * satoshis)) dispute_json["dispute_resolution"]["resolution"]["vendor_payout"] = amt outputs.append({'value': amt, 'address': vendor_address}) tx = bitcointools.mktx(outpoints, outputs) chaincode = contract["buyer_order"]["order"]["payment"]["chaincode"] redeem_script = str(contract["buyer_order"]["order"]["payment"]["redeem_script"]) masterkey_m = bitcointools.bip32_extract_key(KeyChain(self.db).bitcoin_master_privkey) moderator_priv = derive_childkey(masterkey_m, chaincode, bitcointools.MAINNET_PRIVATE) signatures = [] for index in range(0, len(outpoints)): sig = bitcointools.multisign(tx, index, redeem_script, moderator_priv) signatures.append({"input_index": index, "signature": sig}) dispute_json["dispute_resolution"]["resolution"]["order_id"] = order_id dispute_json["dispute_resolution"]["resolution"]["tx_signatures"] = signatures dispute_json["dispute_resolution"]["resolution"]["claim"] = self.db.Cases().get_claim(order_id) dispute_json["dispute_resolution"]["resolution"]["decision"] = resolution dispute_json["dispute_resolution"]["signature"] = \ base64.b64encode(KeyChain(self.db).signing_key.sign(json.dumps( dispute_json["dispute_resolution"]["resolution"]))[:64]) def get_node(node_to_ask, recipient_guid, public_key): def parse_response(response): if not response[0]: self.send_message(Node(unhexlify(recipient_guid)), public_key.encode(), objects.PlaintextMessage.Type.Value("DISPUTE_CLOSE"), dispute_json, order_id, store_only=True) if node_to_ask: skephem = PrivateKey.generate() pkephem = skephem.public_key.encode(nacl.encoding.RawEncoder) box = Box(skephem, public_key) nonce = nacl.utils.random(Box.NONCE_SIZE) ciphertext = box.encrypt(json.dumps(dispute_json, indent=4), nonce) d = self.protocol.callDisputeClose(node_to_ask, pkephem, ciphertext) return d.addCallback(parse_response) else: return parse_response([False]) self.kserver.resolve(unhexlify(vendor_guid)).addCallback(get_node, vendor_guid, vendor_enc_key) self.kserver.resolve(unhexlify(buyer_guid)).addCallback(get_node, buyer_guid, buyer_enc_key) self.db.Cases().update_status(order_id, 1)