def submit_proposal(self, proposal_name, save=True): """Submit the proposal for proposal_name.""" proposal = self.get_proposal(proposal_name) if not proposal.fee_txid: raise Exception('Proposal has no fee transaction') if proposal.submitted: raise Exception('Proposal has already been submitted') if not self.wallet.network: raise Exception('Not connected') confirmations, _ = self.wallet.get_confirmations(proposal.fee_txid) if confirmations < BUDGET_FEE_CONFIRMATIONS: raise Exception('Collateral requires at least %d confirmations' % BUDGET_FEE_CONFIRMATIONS) payments_count = proposal.get_payments_count() payment_amount = format_satoshis_plain(proposal.payment_amount) params = [ proposal.proposal_name, proposal.proposal_url, payments_count, proposal.start_block, proposal.address, payment_amount, proposal.fee_txid ] errmsg = [] callback = lambda r: self.submit_proposal_callback( proposal.proposal_name, errmsg, r, save) self.network_event.clear() self.wallet.network.send([('masternode.budget.submit', params)], callback) self.network_event.wait() if errmsg: errmsg = errmsg[0] return (errmsg, proposal.submitted)
def get_max_amount(self): inputs = self.wallet.get_spendable_coins(None) addr = str( self.send_screen.screen.address) or self.wallet.dummy_address() amount, fee = self.wallet.get_max_amount(self.electrum_config, inputs, addr, None) return format_satoshis_plain(amount, self.decimal_point())
def fiat_to_btc(self, fiat_amount): if not fiat_amount: return '' rate = run_hook('exchange_rate') if not rate: return '' satoshis = int(pow(10, 8) * Decimal(fiat_amount) / Decimal(rate)) return format_satoshis_plain(satoshis, self.decimal_point())
def data(self, index, role=Qt.DisplayRole): if not index.isValid(): return None if role not in [ Qt.EditRole, Qt.DisplayRole, Qt.ToolTipRole, Qt.FontRole ]: return None data = None p = self.proposals[index.row()] c = index.column() if c == self.NAME: data = p.proposal_name elif c == self.URL: data = p.proposal_url elif c == self.YES_COUNT: data = p.yes_count elif c == self.NO_COUNT: data = p.no_count elif c == self.START_BLOCK: data = p.start_block if role == Qt.FontRole: data = util.MONOSPACE_FONT elif c == self.END_BLOCK: data = p.end_block if role == Qt.FontRole: data = util.MONOSPACE_FONT elif c == self.AMOUNT: data = p.payment_amount if role in [Qt.DisplayRole, Qt.EditRole]: data = format_satoshis_plain(data) elif c == self.ADDRESS: data = p.address if role == Qt.FontRole: data = util.MONOSPACE_FONT elif c == self.TXID: data = p.fee_txid if role == Qt.FontRole: data = util.MONOSPACE_FONT return QVariant(data)
def setAmount(self, amount): if amount is None: self.setText(" ") # Space forces repaint in case units changed else: self.setText(format_satoshis_plain(amount, self.decimal_point()))
def sign_transaction(self, tx, password): if tx.is_complete(): return client = self.get_client() self.signing = True inputs = [] inputsPaths = [] pubKeys = [] trustedInputs = [] redeemScripts = [] signatures = [] preparedTrustedInputs = [] changePath = "" changeAmount = None output = None outputAmount = None use2FA = False pin = "" rawTx = tx.serialize() # Fetch inputs of the transaction to sign for txinput in tx.inputs(): if ('is_coinbase' in txinput and txinput['is_coinbase']): self.give_error("Coinbase not supported") # should never happen inputs.append([ self.transactions[txinput['prevout_hash']].raw, txinput['prevout_n'] ]) address = txinput['address'] inputsPaths.append(self.address_id(address)) pubKeys.append(self.get_public_keys(address)) # Recognize outputs - only one output and one change is authorized if len(tx.outputs()) > 2: # should never happen self.give_error("Transaction with more than 2 outputs not supported") for type, address, amount in tx.outputs(): assert type == TYPE_ADDRESS if self.is_change(address): changePath = self.address_id(address) changeAmount = amount else: if output <> None: # should never happen self.give_error("Multiple outputs with no change not supported") output = address if not self.canAlternateCoinVersions: v, h = bc_address_to_hash_160(address) if v == PUBKEY_ADDR: output = hash_160_to_bc_address(h, 0) outputAmount = amount self.get_client() # prompt for the PIN before displaying the dialog if necessary if not self.check_proper_device(): self.give_error('Wrong device or password') self.handler.show_message("Signing Transaction ...") try: # Get trusted inputs from the original transactions for utxo in inputs: txtmp = bitcoinTransaction(bytearray(utxo[0].decode('hex'))) trustedInputs.append(self.get_client().getTrustedInput(txtmp, utxo[1])) # TODO : Support P2SH later redeemScripts.append(txtmp.outputs[utxo[1]].script) # Sign all inputs firstTransaction = True inputIndex = 0 while inputIndex < len(inputs): self.get_client().startUntrustedTransaction(firstTransaction, inputIndex, trustedInputs, redeemScripts[inputIndex]) outputData = self.get_client().finalizeInput(output, format_satoshis_plain(outputAmount), format_satoshis_plain(self.get_tx_fee(tx)), changePath, bytearray(rawTx.decode('hex'))) if firstTransaction: transactionOutput = outputData['outputData'] if outputData['confirmationNeeded']: # TODO : handle different confirmation types. For the time being only supports keyboard 2FA self.handler.clear_dialog() if 'keycardData' in outputData: pin2 = "" for keycardIndex in range(len(outputData['keycardData'])): msg = "Do not enter your device PIN here !\r\n\r\n" + \ "Your Ledger Wallet wants to talk to you and tell you a unique second factor code.\r\n" + \ "For this to work, please match the character between stars of the output address using your security card\r\n\r\n" + \ "Output address : " for index in range(len(output)): if index == outputData['keycardData'][keycardIndex]: msg = msg + "*" + output[index] + "*" else: msg = msg + output[index] msg = msg + "\r\n" confirmed, p, pin = self.password_dialog(msg) if not confirmed: raise Exception('Aborted by user') try: pin2 = pin2 + chr(int(pin[0], 16)) except: raise Exception('Invalid PIN character') pin = pin2 else: use2FA = True confirmed, p, pin = self.password_dialog() if not confirmed: raise Exception('Aborted by user') pin = pin.encode() client.bad = True self.device_checked = False self.plugin.get_client(self, True, True) self.handler.show_message("Signing ...") else: # Sign input with the provided PIN inputSignature = self.get_client().untrustedHashSign(inputsPaths[inputIndex], pin) inputSignature[0] = 0x30 # force for 1.4.9+ signatures.append(inputSignature) inputIndex = inputIndex + 1 firstTransaction = False except Exception, e: self.give_error(e, True)
def format_amount_and_units(self, x): return format_satoshis_plain( x, self.decimal_point()) + ' ' + self.base_unit