def end(self): inputs = self.manager.txin # Mark style fee estimation outputs = [ (TYPE_ADDRESS, self.manager.contract.addresses[self.manager.mode], self.manager.value) ] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 fee = len(tx.serialize(True)) // 2 if fee > self.manager.value: self.show_error("Not enough funds to make the transaction!") return outputs = [ (TYPE_ADDRESS, self.manager.contract.addresses[self.manager.mode], self.manager.value - fee) ] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 if not self.wallet.is_watching_only(): self.manager.signtx(tx) self.manager.completetx(tx) show_transaction(tx, self.main_window, "End Last Will contract", prompt_if_unsaved=True) self.plugin.switch_to(Manage, self.wallet_name, None, None)
def showTransaction_desc_(self, txraw, desc) -> None: tx = Transaction(txraw, sign_schnorr=parent().prefs_use_schnorr) tx.deserialize() tx_hash, status_, label_, can_broadcast, amount, fee, height, conf, timestamp, exp_n = wallet( ).get_tx_info(tx) #print("send: status_",status_,"label_",label_,"amount",amount,"conf",conf) size = tx.estimated_size() conf = 0 if conf is None else conf timestamp = time.time() if timestamp is None else timestamp status, status_str = ( status_, _("Unsigned") ) #wallet().get_tx_status(tx_hash, height, conf, timestamp) doFX = fx() and fx().is_enabled() ccy = fx().get_currency() if doFX else None fiat_amount_str = str(self.fiat.text) if doFX else None #HistoryEntry = namedtuple("HistoryEntry", "tx tx_hash status_str label v_str balance_str date ts conf status value fiat_amount fiat_balance fiat_amount_str fiat_balance_str ccy status_image") entry = HistoryEntry( tx, tx_hash, status_str, str(desc), self.amt.text, "", timestamp_to_datetime(time.time() if conf <= 0 else timestamp), timestamp, conf, status, amount, None, None, fiat_amount_str, None, ccy, None) def newLabel(l): self.descDel.text = l self.navigationController.pushViewController_animated_( txdetail.CreateTxDetailWithEntry(entry, on_label=newLabel), True)
def on_tx(self, response): #self.print_error("--- got tx response: ", response) params, result, error = self.parse_response(response) tx_hash = params[0] or '' if error: self.print_error("error for tx_hash {}, skipping".format(tx_hash)) return try: tx = Transaction(result) for o in tx.outputs(): #self.print_error(" output", o) address = o[1] satoshis = o[2] tip = self.tips_by_address.get(address, None) if tip: tip.registerPayment(tx_hash, Decimal("0.00000001") * satoshis, "chain") else: self.tipless_payments_by_address[address] = { "tx_hash": tx_hash, "amount_bch": Decimal("0.00000001") * satoshis } # else: # self.print_error("address", address, ": cannot find associated tip") except Exception: traceback.print_exc() self.print_msg("cannot deserialize transaction, skipping", tx_hash) return
def extract_contract_data(tx): transaction = Transaction(tx) address = get_contract_address(transaction.outputs()) candidates = get_candidates(transaction.outputs()) for c in candidates: will = LastWillContract(c) if will.address.to_ui_string() == address: return will
def input_script(self, txin, estimate_size=False, sign_schnorr=False): if txin['type'] == 'p2pkh': return Transaction.get_preimage_script(txin) if txin['type'] == 'p2sh': # Multisig verification has partial support, but is disabled. This is the # expected serialization though, so we leave it here until we activate it. return '00' + push_script(Transaction.get_preimage_script(txin)) raise Exception("unsupported type %s" % txin['type'])
def send_tx(self, coin: dict) -> str: """Returns the failure reason as a string on failure, or 'None' on success.""" self.wallet.add_input_info(coin) inputs = [coin] recipient_address = self.recipient_wallet and self.recipient_wallet.get_unused_address( frozen_ok=False) if not recipient_address: self.print_error( "Could not get recipient_address; recipient wallet may have been cleaned up, " "aborting send_tx") return _("Unspecified failure") outputs = [(recipient_address.kind, recipient_address, coin['value'])] kwargs = {} if hasattr(self.wallet, 'is_schnorr_enabled'): # This EC version has Schnorr, query the flag kwargs['sign_schnorr'] = self.wallet.is_schnorr_enabled() # create the tx once to get a fee from the size tx = Transaction.from_io(inputs, outputs, locktime=self.wallet.get_local_height(), **kwargs) fee = tx.estimated_size() if coin['value'] - fee < self.wallet.dust_threshold(): self.print_error( "Resulting output value is below dust threshold, aborting send_tx" ) return _("Too small") # create the tx again, this time with the real fee outputs = [(recipient_address.kind, recipient_address, coin['value'] - fee)] tx = Transaction.from_io(inputs, outputs, locktime=self.wallet.get_local_height(), **kwargs) tx.BIP_LI01_sort() try: self.wallet.sign_transaction(tx, self.password) except InvalidPassword as e: return str(e) except Exception: return _("Unspecified failure") self.set_label_signal.emit( tx.txid(), _("Inter-Wallet Transfer {amount} -> {address}").format( amount=self.main_window.format_amount(coin['value']) + " " + self.main_window.base_unit(), address=recipient_address.to_ui_string())) try: self.main_window.network.broadcast_transaction2(tx) except Exception as e: self.print_error("Error broadcasting tx:", repr(e)) return (e.args and e.args[0]) or _("Unspecified failure") self.recipient_wallet.frozen_addresses.add(recipient_address) self.recipient_wallet.create_new_address(False) return None
def tx_from_text(self, txt): from electroncash.transaction import tx_from_str try: txt_tx = tx_from_str(txt) tx = Transaction(txt_tx, sign_schnorr=self.wallet.is_schnorr_enabled()) tx.deserialize() return tx except: traceback.print_exc(file=sys.stdout) self.show_critical(_("Electron Cash was unable to parse your transaction")) return
def extract_contract_data(wallet, tx, utxo): contracts=[] print(tx) for i in range(len(tx)): transaction=Transaction(tx[i]) address, v = get_contract_info(transaction.outputs()) candidates = get_candidates(transaction.outputs()) for c in candidates: will = LastWillContract(c, tx[i],v) if will.address.to_ui_string()==address: contracts.append((utxo[i], will, find_my_role(c, wallet))) remove_duplicates(contracts) return contracts
def end_tx(self, inputs, direction): outputs = [(TYPE_ADDRESS, self.contract.addresses[direction], self.value)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 fee = 2 * (len(tx.serialize(True)) // 2 + 1) if fee > self.value: raise Exception("Not enough funds to make the transaction!") outputs = [(TYPE_ADDRESS, self.contract.addresses[direction], self.value - fee)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 return tx
def spend(self, mode): prevout_hash = self.fund_txid_e.text() prevout_n = int(self.fund_txout_e.text()) value = int(self.fund_value_e.text()) locktime = 0 estimate_fee = lambda x: (1 * x) out_addr = Address.from_string(self.redeem_address_e.text()) # generate the special spend inp = self.contract.makeinput(prevout_hash, prevout_n, value, mode) inputs = [inp] invalue = value # add on other spends if self.option1_rb.isChecked(): domain = [] elif self.option2_rb.isChecked(): domain = [self.fund_change_address] elif self.option3_rb.isChecked(): domain = None else: raise RuntimeError other_coins = self.wallet.get_utxos(domain, exclude_frozen=True, mature=True, confirmed_only=False) for coin in other_coins: self.wallet.add_input_info(coin) inputs.append(coin) invalue += coin['value'] outputs = [(TYPE_ADDRESS, out_addr, 0)] tx1 = Transaction.from_io(inputs, outputs, locktime) txsize = len(tx1.serialize(True)) // 2 fee = estimate_fee(txsize) outputs = [(TYPE_ADDRESS, out_addr, invalue - fee)] tx = Transaction.from_io(inputs, outputs, locktime) self.contract.signtx(tx) self.wallet.sign_transaction(tx, self.password) self.contract.completetx(tx) if mode == 'refund': desc = "Spend splittable coin (replayable on any chain)" elif mode == 'redeem': desc = "Spend splittable coin (CDS chain only!)" show_transaction(tx, self.main_window, desc, prompt_if_unsaved=True)
def tableView_didSelectRowAtIndexPath_(self, tv, indexPath): tv.deselectRowAtIndexPath_animated_(indexPath, True) parent = gui.ElectrumGui.gui if parent.wallet is None: return if not self.vc: utils.NSLog( "TxHistoryHelper: No self.vc defined, cannot proceed to tx detail screen" ) return tx = None try: entry = _GetTxs(self)[indexPath.row] if entry.tx: tx = entry.tx else: tx = parent.wallet.transactions.get(entry.tx_hash, None) if tx and tx.raw: tx = Transaction(tx.raw) except: return if tx is None: # I'm not sure why this would happen but we did get issue #810 where it happened to 1 user. # Perhaps a chain split led to an "old" history view on-screen. That's my theory, at least. -Calin parent.show_error(_( "The requested transaction has dropped out of the wallet history.\n\nIf this problem persists, please contact us at electroncash.org." ), title=_("Transaction Not Found"), onOk=lambda: parent.refresh_components('history') ) return txd = txdetail.CreateTxDetailWithEntry(entry, tx=tx) self.vc.navigationController.pushViewController_animated_(txd, True)
def got_network_response_chunk_slot(self, response, chunk_index): if response.get('error'): return self.fail_metadata_info("Download chunk data error!\n%r"%(response['error'].get('message'))) raw = response.get('result') tx = Transaction(raw) self.handle_chunk_tx(tx, chunk_index)
def CreateTxDetailWithTx(tx : Transaction, on_label = None, on_appear = None, asModalNav = False) -> ObjCInstance: parent = gui.ElectrumGui.gui wallet = parent.wallet import time tx_hash, status_, label_, can_broadcast, amount, fee, height, conf, timestamp, exp_n = wallet.get_tx_info(tx) size = tx.estimated_size() status_str = "" status = status_ img = None if conf is not None: if tx_hash is not None and height is not None and timestamp is not None: status, status_str = wallet.get_tx_status(tx_hash, height, conf, timestamp) if status is not None and status >= 0 and status < len(StatusImages): img = StatusImages[status] else: conf = 0 timestamp = time.time() if timestamp is None else timestamp doFX = False #fx() and fx().is_enabled() ccy = None #fx().get_currency() if doFX else None fiat_amount_str = None #str(self.fiat.text) if doFX else None #HistoryEntry = namedtuple("HistoryEntry", "extra_data tx_hash status_str label v_str balance_str date ts conf status value fiat_amount fiat_balance fiat_amount_str fiat_balance_str ccy status_image") entry = HistoryEntry(tx,tx_hash,status_str,label_,parent.format_amount(amount) if amount is not None else _("Transaction unrelated to your wallet"), "",timestamp_to_datetime(time.time() if conf <= 0 else timestamp), timestamp,conf,status,amount,None,None,fiat_amount_str,None,ccy,img) return CreateTxDetailWithEntry(entry, on_label = on_label, on_appear = on_appear, asModalNav = asModalNav)
def create_last_will(self, ): outputs = [(TYPE_SCRIPT, ScriptOutput(make_opreturn(self.contract.address.to_ui_string().encode('utf8'))),0), (TYPE_ADDRESS, self.refresh_address, self.value+190), (TYPE_ADDRESS, self.cold_address, 546), (TYPE_ADDRESS, self.inheritor_address, 546)] try: tx = self.wallet.mktx(outputs, self.password, self.config, domain=self.fund_domain, change_addr=self.fund_change_address) id = tx.txid() except NotEnoughFunds: return self.show_critical(_("Not enough balance to fund smart contract.")) except Exception as e: return self.show_critical(repr(e)) # preparing transaction, contract can't give a change self.main_window.network.broadcast_transaction2(tx) self.create_button.setText("Creating Last Will...") self.create_button.setDisabled(True) coin = self.wait_for_coin(id,10) self.wallet.add_input_info(coin) inputs = [coin] outputs = [(TYPE_ADDRESS, self.contract.address, self.value)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version=2 show_transaction(tx, self.main_window, "Make Last Will contract", prompt_if_unsaved=True) if self.notification.do_anything() : outputs = self.notification.notification_outputs(self.contract.address) tx = self.wallet.mktx(outputs, self.password, self.config, domain=self.fund_domain, change_addr=self.fund_change_address) show_transaction(tx, self.main_window, "Notification service payment", prompt_if_unsaved=True) self.plugin.switch_to(Intro, self.wallet_name, None, None)
def make_Bucket(desc, coins): size = sum( Transaction.estimated_input_size(coin, sign_schnorr=sign_schnorr) for coin in coins) value = sum(coin['value'] for coin in coins) min_height = min(coin['height'] for coin in coins) return Bucket(desc, size, value, coins, min_height)
def build_slp_txn(coins, slp_output, receiver_output, postoffice_output, change_output): slp_msg = SlpMessage.parseSlpOutputScript(slp_output[1]) outputs = [slp_output, receiver_output] if len(slp_msg.op_return_fields["token_output"]) - 1 == 2: outputs.extend([postoffice_output]) elif len(slp_msg.op_return_fields["token_output"]) - 1 == 3: outputs.extend([postoffice_output, change_output]) tx = Transaction.from_io(coins, outputs) return tx
def got_network_response_slot(self): self.download_finished = True resp = self.json_response if resp.get('error'): return self.fail_genesis_info("Download error!\n%r"%(resp['error'].get('message'))) raw = resp.get('result') tx = Transaction(raw) self.handle_genesis_tx(tx)
def end(self): inputs = [self.manager.txin] outputs = [(TYPE_ADDRESS, self.manager.contract.addresses[self.manager.mode], self.manager.value - self.fee)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version=2 if not self.wallet.is_watching_only(): self.manager.signtx(tx) self.manager.completetx(tx) show_transaction(tx, self.main_window, "End Last Will contract", prompt_if_unsaved=True) self.plugin.switch_to(Intro, self.wallet_name, None, None)
def _synch_full(self, wallet): c = self._get_contacts(wallet) if not c: # short-circuit abort function early if no contacts exist. return dict() h = self._get_history(wallet) seen = dict() # Address -> dict of tx_hash_str -> hitem tuple for hitem in h: if self.stopFlag.is_set(): # early return, another thread requested a stop return None # loop through ALL the history and see if relevant tx's exist for contacts we care about tx_hash = hitem[0] tx = wallet.transactions.get(tx_hash) if tx and tx.raw: tx = Transaction(tx.raw) # take a copy ins = tx.inputs() # implicit deserialize for x in ins: xa = x['address'] if isinstance(xa, PublicKey): xa = xa.toAddress() if isinstance(xa, Address) and xa in c: dct = seen.get(xa, dict()) wasEmpty = not dct if tx_hash not in dct: dct[tx_hash] = hitem if wasEmpty: seen[xa] = dct outs = tx.outputs() for x in outs: typ, xa, dummy = x if isinstance(xa, Address) and xa in c: dct = seen.get(xa, dict()) wasEmpty = not dct if tx_hash not in dct: dct[tx_hash] = hitem if wasEmpty: seen[xa] = dct storable = dict() for addr, d in seen.items(): addrstr = addr.to_storage_string() storable[addrstr] = d return storable
def on_qr(self, data): from electroncash.bitcoin import base_decode, is_address data = data.strip() if is_address(data): self.set_URI(data) return if data.startswith('bitcoincash:'): self.set_URI(data) return # try to decode transaction from electroncash.transaction import Transaction try: text = base_decode(data, None, base=43).encode('hex') tx = Transaction(text) tx.deserialize() if self.wallet: my_coins = self.wallet.get_spendable_coins( None, self.electrum_config) my_outpoints = [ vin['prevout_hash'] + ':' + str(vin['prevout_n']) for vin in my_coins ] for i, txin in enumerate(tx.inputs()): outpoint = txin['prevout_hash'] + ':' + str( txin['prevout_n']) if outpoint in my_outpoints: my_index = my_outpoints.index(outpoint) tx._inputs[i]['value'] = my_coins[my_index]['value'] except: tx = None if tx: self.tx_dialog(tx) return # show error self.show_error("Unable to decode QR data")
def tx_from_text(self, txt): from electroncash.transaction import tx_from_str try: txt_tx = tx_from_str(txt) tx = Transaction(txt_tx, sign_schnorr=self.wallet.is_schnorr_enabled()) tx.deserialize() if self.wallet: my_coins = self.wallet.get_spendable_coins( None, self.main_window.config) my_outpoints = [ vin['prevout_hash'] + ':' + str(vin['prevout_n']) for vin in my_coins ] for i, txin in enumerate(tx.inputs()): outpoint = txin['prevout_hash'] + ':' + str( txin['prevout_n']) if outpoint in my_outpoints: my_index = my_outpoints.index(outpoint) tx._inputs[i]['value'] = my_coins[my_index]['value'] return tx except: traceback.print_exc(file=sys.stderr) self.show_critical( _("Electron Cash was unable to parse your transaction")) return
def ref_tx(self, contract, utxo_index, m): self.manager.choice(contract, utxo_index, m) inputs = self.manager.txin if self.manager.value - self.fee < 0: self.show_error("Not enough funds to make the transaction!") return outputs = [(TYPE_ADDRESS, self.manager.contract.address, self.manager.value - self.fee)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 self.manager.signtx(tx) self.wallet.sign_transaction(tx, self.password) self.manager.completetx_ref(tx) return tx
def make_tx(self, coins, outputs, change_addrs, fee_estimator, dust_threshold, sign_schnorr=False): '''Select unspent coins to spend to pay outputs. If the change is greater than dust_threshold (after adding the change output to the transaction) it is kept, otherwise none is sent and it is added to the transaction fee.''' # Deterministic randomness from coins utxos = [c['prevout_hash'] + str(c['prevout_n']) for c in coins] self.p = PRNG(''.join(sorted(utxos))) # Copy the outputs so when adding change we don't modify "outputs" tx = Transaction.from_io([], outputs, sign_schnorr=sign_schnorr) # Size of the transaction with no inputs and no change base_size = tx.estimated_size() spent_amount = tx.output_value() def sufficient_funds(buckets): '''Given a list of buckets, return True if it has enough value to pay for the transaction''' total_input = sum(bucket.value for bucket in buckets) total_size = sum(bucket.size for bucket in buckets) + base_size return total_input >= spent_amount + fee_estimator(total_size) # Collect the coins into buckets, choose a subset of the buckets buckets = self.bucketize_coins(coins, sign_schnorr=sign_schnorr) buckets = self.choose_buckets(buckets, sufficient_funds, self.penalty_func(tx)) tx.add_inputs([coin for b in buckets for coin in b.coins]) tx_size = base_size + sum(bucket.size for bucket in buckets) # This takes a count of change outputs and returns a tx fee; # each pay-to-bitcoin-address output serializes as 34 bytes fee = lambda count: fee_estimator(tx_size + count * 34) change, dust = self.change_outputs(tx, change_addrs, fee, dust_threshold) tx.add_outputs(change) tx.ephemeral['dust_to_fee'] = dust self.print_error("using %d inputs" % len(tx.inputs())) self.print_error("using buckets:", [bucket.desc for bucket in buckets]) return tx
def pledge_tx(self): inputs = self.txin print("creating pledge tx") if self.value - self.fee - self.rpayment>0: outputs = [ (TYPE_ADDRESS, self.contract.address, self.value - self.fee - self.rpayment), (TYPE_ADDRESS, self.contract.addresses[PROTEGE], self.rpayment)] else: print("single output") outputs = [ (TYPE_ADDRESS, self.contract.addresses[PROTEGE], self.value - self.fee)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 #print(tx.outputs()) return tx
def make_unsigned_transaction(self, amount, fee, all_inputs, outputs, changes): ''' make unsigned transaction ''' dust = self.dust_threshold( ) # always 546 for now, but this call is here in case something more sophisticated happens in the future coins = {} tx_inputs = [] amounts = {} try: for player in all_inputs: inputs_coins = self.get_coins(all_inputs[player]) # if there are no coins on input it terminates the process if inputs_coins: coins[player] = inputs_coins else: return None except BaseException as e: self.print_error('make_unsigned_transaction:', repr(e)) return None for player, pubkey_utxos in coins.items(): amounts[player] = 0 for pubkey, utxos in pubkey_utxos.items(): for utxo in utxos: utxo['type'] = 'p2pkh' utxo['address'] = Address.from_pubkey(pubkey) utxo['pubkeys'] = [pubkey] utxo['x_pubkeys'] = [pubkey] utxo['prevout_hash'] = utxo['tx_hash'] utxo['prevout_n'] = utxo['tx_pos'] utxo['signatures'] = [None] utxo['num_sig'] = 1 tx_inputs.append(utxo) amounts[player] += utxo['value'] tx_inputs.sort(key=lambda x: x['prevout_hash'] + str(x["tx_pos"])) tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount)) for output in outputs] transaction = Transaction.from_io(tx_inputs, tx_outputs, sign_schnorr=False) tx_changes = [ (TYPE_ADDRESS, Address.from_string(changes[player]), int(amounts[player] - amount - fee)) for player in sorted(changes) if Address.is_valid(changes[player]) and int(amounts[player] - amount - fee) >= dust ] transaction.add_outputs(tx_changes) return transaction
def make_unsigned_transaction(self, amount, fee, inputs, outputs, changes): coins = {vk : self.get_first_sufficient_utxo(inputs[vk], amount) for vk in inputs} for vk in coins: coins[vk]['type'] = 'p2pkh' coins[vk]['address'] = Address.from_string(self.address(vk)) coins[vk]['pubkeys'] = [vk] coins[vk]['x_pubkeys'] = [vk] coins[vk]['prevout_hash'] = coins[vk]['tx_hash'] coins[vk]['prevout_n'] = coins[vk]['tx_pos'] coins[vk]['signatures'] = [None] coins[vk]['num_sig'] = 1 tx_inputs = [coins[vk] for vk in sorted(coins)] tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount)) for output in outputs ] tx = Transaction.from_io(tx_inputs, tx_outputs) tx_changes = [(TYPE_ADDRESS, Address.from_string(changes[vk]), int(coins[vk]['value'] - amount - fee)) for vk in changes if Address.is_valid(changes[vk])] tx.add_outputs(tx_changes) return tx
def tx_from_components(all_components, session_hash): """ Returns the tx and a list of indices matching inputs with components""" input_indices = [] assert len(session_hash) == 32 if Protocol.FUSE_ID is None: prefix = [] else: assert len(Protocol.FUSE_ID) == 4 prefix = [4, *Protocol.FUSE_ID] inputs = [] outputs = [ (TYPE_SCRIPT, ScriptOutput(bytes([OpCodes.OP_RETURN, *prefix, 32]) + session_hash), 0) ] for i, compser in enumerate(all_components): comp = pb.Component() comp.ParseFromString(compser) ctype = comp.WhichOneof('component') if ctype == 'input': inp = comp.input if len(inp.prev_txid) != 32: raise FusionError("bad component prevout") inputs.append( dict(address=Address.from_P2PKH_hash(hash160(inp.pubkey)), prevout_hash=inp.prev_txid[::-1].hex(), prevout_n=inp.prev_index, num_sig=1, signatures=[None], type='p2pkh', x_pubkeys=[inp.pubkey.hex()], pubkeys=[inp.pubkey.hex()], sequence=0xffffffff, value=inp.amount)) input_indices.append(i) elif ctype == 'output': out = comp.output atype, addr = get_address_from_output_script(out.scriptpubkey) if atype != TYPE_ADDRESS: raise FusionError("bad component address") outputs.append((TYPE_ADDRESS, addr, out.amount)) elif ctype != 'blank': raise FusionError("bad component") tx = Transaction.from_io(inputs, outputs, locktime=0, sign_schnorr=True) tx.version = 1 return tx, input_indices
def build_slp_txn(coins, slp_output, pre_postage_outputs, postoffice_output, change_output, send_amount, old_slp_msg): slp_msg = SlpMessage.parseSlpOutputScript(slp_output[1]) pre_postage_outputs = list(pre_postage_outputs[1:]) if sum(old_slp_msg.op_return_fields["token_output"] ) > send_amount: # has change output pre_postage_outputs = pre_postage_outputs[:-1] outputs = [slp_output] + pre_postage_outputs if len(slp_msg.op_return_fields["token_output"]) - len( pre_postage_outputs) == 2: outputs.extend([postoffice_output]) elif len(slp_msg.op_return_fields["token_output"]) - len( pre_postage_outputs) == 3: outputs.extend([postoffice_output, change_output]) tx = Transaction.from_io(coins, outputs) return tx
def make_unsigned_transaction(self, amount, fee, all_inputs, outputs, changes): "make unsigned transaction" dust = dust_threshold(self.network) coins = {} tx_inputs = [] amounts = {} try: for player in all_inputs: inputs_coins = self.get_coins(all_inputs[player]) # if there is no coins on input it terminates the process if inputs_coins: coins[player] = inputs_coins else: return None except: return None for player, pubkey_utxos in coins.items(): amounts[player] = 0 for pubkey, utxos in pubkey_utxos.items(): for utxo in utxos: utxo['type'] = 'p2pkh' utxo['address'] = Address.from_pubkey(pubkey) utxo['pubkeys'] = [pubkey] utxo['x_pubkeys'] = [pubkey] utxo['prevout_hash'] = utxo['tx_hash'] utxo['prevout_n'] = utxo['tx_pos'] utxo['signatures'] = [None] utxo['num_sig'] = 1 tx_inputs.append(utxo) amounts[player] += utxo['value'] tx_inputs.sort(key=lambda x: x['prevout_hash'] + str(x["tx_pos"])) tx_outputs = [(TYPE_ADDRESS, Address.from_string(output), int(amount)) for output in outputs] transaction = Transaction.from_io(tx_inputs, tx_outputs) tx_changes = [ (TYPE_ADDRESS, Address.from_string(changes[player]), int(amounts[player] - amount - fee)) for player in sorted(changes) if Address.is_valid(changes[player]) and int(amounts[player] - amount - fee) >= dust ] transaction.add_outputs(tx_changes) return transaction
def refresh(self): if self.manager.mode!=0: print("This wallet can't refresh a contract!") return print("Notification Service: ") print(self.notification.do_anything()) if self.notification.do_anything() : outputs = self.notification.notification_outputs(self.manager.contract.address) tx = self.wallet.mktx(outputs, self.password, self.config, None, None) show_transaction(tx, self.main_window, "Notification service payment", prompt_if_unsaved=True) inputs = [self.manager.txin] outputs = [(TYPE_ADDRESS, self.manager.contract.address, self.manager.value-self.fee)] tx = Transaction.from_io(inputs, outputs, locktime=0) tx.version = 2 self.manager.signtx(tx) self.wallet.sign_transaction(tx, self.password) self.manager.completetx_ref(tx) show_transaction(tx, self.main_window, "Refresh Last Will contract", prompt_if_unsaved=True) self.plugin.switch_to(Intro, self.wallet_name,None,None)