def tx_outputs(self, derivation, tx, segwit=False): outputs = [] has_change = False for _type, address, amount in tx.outputs(): info = tx.output_info.get(address) if info is not None and not has_change: has_change = True # no more than one change address addrtype, hash_160 = b58_address_to_hash160(address) index, xpubs, m = info if len(xpubs) == 1: script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS address_n = self.client_class.expand_path(derivation + "/%d/%d" % index) txoutputtype = self.types.TxOutputType( amount=amount, script_type=script_type, address_n=address_n, ) else: script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG address_n = self.client_class.expand_path("/%d/%d" % index) nodes = map(self.ckd_public.deserialize, xpubs) pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes ] multisig = self.types.MultisigRedeemScriptType( pubkeys=pubkeys, signatures=[b''] * len(pubkeys), m=m) txoutputtype = self.types.TxOutputType( multisig=multisig, amount=amount, address_n=self.client_class.expand_path(derivation + "/%d/%d" % index), script_type=script_type) else: txoutputtype = self.types.TxOutputType() txoutputtype.amount = amount if _type == TYPE_SCRIPT: txoutputtype.script_type = self.types.PAYTOOPRETURN txoutputtype.op_return_data = address[2:] elif _type == TYPE_ADDRESS: if is_segwit_address(address): txoutputtype.script_type = self.types.PAYTOWITNESS else: addrtype, hash_160 = b58_address_to_hash160(address) if addrtype == NetworkConstants.ADDRTYPE_P2PKH: txoutputtype.script_type = self.types.PAYTOADDRESS elif addrtype == NetworkConstants.ADDRTYPE_P2SH: txoutputtype.script_type = self.types.PAYTOSCRIPTHASH else: raise BaseException('addrtype: ' + str(addrtype)) txoutputtype.address = address outputs.append(txoutputtype) return outputs
def do(self): try: staker = self.staker_e.text().strip() if not is_hash160(staker): try: addr_type, staker = b58_address_to_hash160(staker) except BaseException: raise Exception('invalid staker address') if addr_type != constants.net.ADDRTYPE_P2PKH: raise Exception('invalid staker address') staker = staker.hex() fee = int(self.fee_e.text().strip()) if fee < 0 or fee > 100: raise Exception('fee should between 0 and 100') addr = self.address_combo.currentText().strip() try: addr_type, self_h160 = b58_address_to_hash160(addr) except BaseException: raise Exception('invalid address') if len( addr ) == 0 or addr not in self.addresses or addr_type != constants.net.ADDRTYPE_P2PKH: raise Exception('invalid address') if staker == self_h160.hex(): raise Exception('cannot delegate to self') gas_limit, gas_price = self.parse_values() if gas_limit < 2250000: raise Exception('a minimum of 2,250,000 gas_limit is required') dele_exist = self.dele and self.dele.staker and self.dele.fee if self.mode == 'add' and dele_exist: self.dialog.parent().set_delegation(self.dele) elif self.mode in ['edit', 'add']: if dele_exist and self.staker_e.text().strip( ) == self.dele.staker and fee == self.dele.fee: return if self.is_watching_only: pod_str = self.pod_e.text().strip() if not pod_str: raise Exception('missing POD') pod = base64.b64decode(pod_str) else: pod = None self.dialog.parent().call_add_delegation( addr, staker, fee, gas_limit, gas_price, self.dialog, pod) elif self.mode == 'undelegate': self.dialog.parent().call_remove_delegation( addr, gas_limit, gas_price, self.dialog) self.dialog.reject() except (BaseException, ) as e: traceback.print_exc(file=sys.stderr) self.dialog.show_message(str(e))
def tx_outputs(self, derivation, tx, segwit=False): outputs = [] has_change = False for _type, address, amount in tx.outputs(): info = tx.output_info.get(address) if info is not None and not has_change: has_change = True # no more than one change address addrtype, hash_160 = b58_address_to_hash160(address) index, xpubs, m = info if len(xpubs) == 1: script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOADDRESS address_n = self.client_class.expand_path(derivation + "/%d/%d"%index) txoutputtype = self.types.TxOutputType( amount = amount, script_type = script_type, address_n = address_n, ) else: script_type = self.types.PAYTOP2SHWITNESS if segwit else self.types.PAYTOMULTISIG address_n = self.client_class.expand_path("/%d/%d"%index) nodes = map(self.ckd_public.deserialize, xpubs) pubkeys = [ self.types.HDNodePathType(node=node, address_n=address_n) for node in nodes] multisig = self.types.MultisigRedeemScriptType( pubkeys = pubkeys, signatures = [b''] * len(pubkeys), m = m) txoutputtype = self.types.TxOutputType( multisig = multisig, amount = amount, address_n = self.client_class.expand_path(derivation + "/%d/%d"%index), script_type = script_type) else: txoutputtype = self.types.TxOutputType() txoutputtype.amount = amount if _type == TYPE_SCRIPT: txoutputtype.script_type = self.types.PAYTOOPRETURN txoutputtype.op_return_data = address[2:] elif _type == TYPE_ADDRESS: if is_segwit_address(address): txoutputtype.script_type = self.types.PAYTOWITNESS else: addrtype, hash_160 = b58_address_to_hash160(address) if addrtype == constants.net.ADDRTYPE_P2PKH: txoutputtype.script_type = self.types.PAYTOADDRESS elif addrtype == constants.net.ADDRTYPE_P2SH: txoutputtype.script_type = self.types.PAYTOSCRIPTHASH else: raise BaseException('addrtype: ' + str(addrtype)) txoutputtype.address = address outputs.append(txoutputtype) return outputs
def parse_args(self): sender = None if len(self.senders) > 0: sender = self.senders[self.sender_combo.currentIndex()] if not sender: raise ParseArgsException('no sender selected') args = json.loads('[{}]'.format(self.args_e.text())) constructor = self.constructor inputs = constructor.get('inputs', []) if not len(args) == len(inputs): raise ParseArgsException( 'invalid input count,expect {} got {}'.format( len(inputs), len(args))) for index, _input in enumerate(inputs): _type = _input.get('type', '') if _type == 'address': addr = args[index] if is_address(addr): __, hash160 = b58_address_to_hash160(addr) addr = bh2u(hash160) if not is_hash160(addr): raise ParseArgsException('invalid input:{}'.format( args[index])) args[index] = addr.lower() elif 'int' in _type: if not isinstance(args[index], int): raise ParseArgsException('invalid input:{}'.format( args[index])) elif _type == 'bytes': args[index] = args[index].encode() return constructor, args, sender
def parse_args(self): if len(self.senders) > 0: sender = self.senders[self.sender_combo.currentIndex()] else: sender = '' args = json.loads('[{}]'.format(self.args_e.text())) abi_index = self.abi_signatures[self.abi_combo.currentIndex()][0] if abi_index == -1: return None, [], sender abi = self.contract['interface'][abi_index] inputs = abi.get('inputs', []) if not len(args) == len(inputs): raise ParseArgsException( 'invalid input count,expect {} got {}'.format( len(inputs), len(args))) for index, _input in enumerate(inputs): _type = _input.get('type', '') if _type == 'address': addr = args[index] if is_address(addr): __, hash160 = b58_address_to_hash160(addr) addr = bh2u(hash160) if not is_hash160(addr): raise ParseArgsException('invalid input:{}'.format( args[index])) args[index] = addr.lower() elif 'int' in _type: if not isinstance(args[index], int): raise ParseArgsException('inavlid input:{}'.format( args[index])) elif _type == 'bytes': args[index] = bytes.fromhex(args[index]) return abi, args, sender
def token_enabled(self): from electrum import bitcoin, constants addresses = self.app.wallet.get_addresses_sort_by_balance() try: addr_type, __ = bitcoin.b58_address_to_hash160(addresses[0]) except: addr_type = constants.net.SEGWIT_HRP return addr_type == constants.net.ADDRTYPE_P2PKH
def __init__(self, dialog, callback): """ :type dialog: QDialog :type callback: func """ QGridLayout.__init__(self) self.setSpacing(8) self.setColumnStretch(3, 1) self.callback = callback self.dialog = dialog if isinstance(self.dialog.parent().wallet.keystore, TrezorKeyStore): self.dialog.show_message( 'Trezor does not support QRC20 Token for now') self.dialog.reject() return self.addresses = self.dialog.parent( ).wallet.get_addresses_sort_by_balance() addr_type, __ = b58_address_to_hash160(self.addresses[0]) if not addr_type == constants.net.ADDRTYPE_P2PKH: self.dialog.show_message('only P2PKH address supports QRC20 Token') self.dialog.reject() return address_lb = QLabel(_("Contract Address:")) self.contract_addr_e = ButtonsLineEdit() self.addWidget(address_lb, 1, 0) self.addWidget(self.contract_addr_e, 1, 1, 1, -1) address_lb = QLabel(_("My Address:")) self.address_combo = QComboBox() self.address_combo.setMinimumWidth(300) self.address_combo.addItems(self.addresses) self.addWidget(address_lb, 2, 0) self.addWidget(self.address_combo, 2, 1, 1, -1) self.cancel_btn = CancelButton(dialog) self.save_btn = QPushButton(_('Save')) self.save_btn.setDefault(True) self.save_btn.clicked.connect(self.save_input) buttons = Buttons(*[self.cancel_btn, self.save_btn]) buttons.addStretch() self.addLayout(buttons, 3, 2, 2, -1)
def create_output_by_address(): txoutputtype = self.types.TxOutputType() txoutputtype.amount = amount if _type == TYPE_SCRIPT: txoutputtype.script_type = self.types.PAYTOOPRETURN txoutputtype.op_return_data = address[2:] elif _type == TYPE_ADDRESS: if is_segwit_address(address): txoutputtype.script_type = self.types.PAYTOWITNESS else: addrtype, hash_160 = b58_address_to_hash160(address) if addrtype == constants.net.ADDRTYPE_P2PKH: txoutputtype.script_type = self.types.PAYTOADDRESS elif addrtype == constants.net.ADDRTYPE_P2SH: txoutputtype.script_type = self.types.PAYTOSCRIPTHASH else: raise Exception('addrtype: ' + str(addrtype)) txoutputtype.address = address return txoutputtype
def get_inputs(self): try: gas_limit, gas_price, amount = self.parse_values() except (BaseException, ) as e: raise e if self.token.balance < amount: raise Exception(_('token not enough')) address_to = self.address_to_e.text().rstrip().lstrip() if is_b58_address(address_to): addr_type, hash160 = b58_address_to_hash160(address_to) if addr_type == constants.net.ADDRTYPE_P2PKH: hash160 = bh2u(hash160) else: raise Exception(_('invalid address to send to')) elif is_hash160(address_to): hash160 = address_to.lower() else: raise Exception(_('invalid address to send to')) return hash160, amount, gas_limit, gas_price
def create_output_by_address(): txoutputtype = self.types.TxOutputType() txoutputtype.amount = amount if _type == TYPE_SCRIPT: txoutputtype.script_type = self.types.PAYTOOPRETURN txoutputtype.op_return_data = trezor_validate_op_return_output_and_get_data(o) elif _type == TYPE_ADDRESS: if is_segwit_address(address): txoutputtype.script_type = self.types.PAYTOWITNESS else: addrtype, hash_160 = b58_address_to_hash160(address) if addrtype == constants.net.ADDRTYPE_P2PKH: txoutputtype.script_type = self.types.PAYTOADDRESS elif addrtype == constants.net.ADDRTYPE_P2SH: txoutputtype.script_type = self.types.PAYTOSCRIPTHASH else: raise Exception('addrtype: ' + str(addrtype)) txoutputtype.address = address return txoutputtype
def parse_args(self): if len(self.senders) > 0: sender = self.sender_combo.currentText().strip() if sender not in self.senders: raise ParseArgsException('invalid sender address') else: sender = '' args_str = f'[{self.args_e.text()}]'.replace("\n", "") try: args = json.loads(args_str) except BaseException as e: raise ParseArgsException(f"json decode error {e} for {args_str}") abi_index = self.abi_signatures[self.abi_combo.currentIndex()][0] if abi_index == -1: return None, [], sender abi = self.contract['interface'][abi_index] inputs = abi.get('inputs', []) if not len(args) == len(inputs): raise ParseArgsException( 'invalid input count,expect {} got {}'.format( len(inputs), len(args))) for index, _input in enumerate(inputs): _type = _input.get('type', '') if _type == 'address': addr = args[index] if is_address(addr): __, hash160 = b58_address_to_hash160(addr) addr = hash160.hex() if addr.startswith("0x"): addr = addr[2:] if not is_hash160(addr): raise ParseArgsException('invalid input:{}'.format( args[index])) args[index] = addr.lower() elif 'int' in _type: if not isinstance(args[index], int): raise ParseArgsException('inavlid input:{}'.format( args[index])) elif _type == 'bytes': args[index] = bytes.fromhex(args[index]) return abi, args, sender
def do_send(self): from electrum.bitcoin import is_p2pkh, is_hash160, b58_address_to_hash160, bh2u, TYPE_SCRIPT from electrum.transaction import opcodes, contract_script, PartialTxOutput address = str(self.to_addr) if not address: self.app.show_error( _('Recipient not specified.') + ' ' + _('Please scan a Bitcoin address or a payment request')) return if is_p2pkh(address): addr_type, hash160 = b58_address_to_hash160(address) hash160 = bh2u(hash160) elif is_hash160(address): hash160 = address.lower() else: self.app.show_error(_('Invalid Bitcoin Address') + ':\n' + address) return if address == self.bind_addr: self.app.show_error(_('You can not send to bind address!')) return try: amount = self.app.get_token_amount(self.amount, self.symbol, self.decimals) except: self.app.show_error( _('Invalid amount') + ':\n' + self.screen.amount) return if self.balance < amount: self.app.show_error(_('token not enough')) return datahex = 'a9059cbb{}{:064x}'.format(hash160.zfill(64), amount) tx_desc = _('Pay out {} {}').format(amount / (10**self.decimals), self.symbol) gas_limit = int(self.gas_limit) gas_price = int(float(self.gas_price) * (10**8)) script = contract_script(gas_limit, gas_price, datahex, self.contract_addr, opcodes.OP_CALL) outputs = [PartialTxOutput(scriptpubkey=script, value=0)] amount = sum(map(lambda x: x[2], outputs)) self._do_send(amount, tx_desc, outputs, gas_limit * gas_price)
def do(self): try: staker = self.staker_e.text() if not is_hash160(staker): addr_type, staker = b58_address_to_hash160(staker) if addr_type != constants.net.ADDRTYPE_P2PKH: raise Exception('wrong staker address') staker = bh2u(staker) fee = int(self.fee_e.text()) if fee < 0 or fee > 100: raise Exception('fee should between 0 and 100') addr = self.addresses[self.address_combo.currentIndex()] if not addr: raise Exception('please select a address') gas_limit, gas_price = self.parse_values() if gas_limit < 2250000: raise Exception('a minimum of 2,250,000 gas_limit is required') dele_exist = self.dele and self.dele.staker and self.dele.fee if self.mode == 'add' and dele_exist: self.dialog.parent().set_delegation(self.dele) elif self.mode in ['edit', 'add']: if dele_exist and self.staker_e.text( ) == self.dele.staker and fee == self.dele.fee: return self.dialog.parent().call_add_delegation( addr, staker, fee, gas_limit, gas_price, self.dialog) elif self.mode == 'undelegate': self.dialog.parent().call_remove_delegation( addr, gas_limit, gas_price, self.dialog) self.dialog.reject() except (BaseException, ) as e: traceback.print_exc(file=sys.stderr) self.dialog.show_message(str(e))
def _ShowAddressContextMenu(entry, parentvc, ipadAnchor, toggleFreezeCallback=None): parent = gui.ElectrumGui.gui if not parent.wallet: utils.NSLog( "_ShowAddressContextMenu: wallet is None -- possibly backgrounded/closed wallet. Returning early." ) return def on_block_explorer() -> None: parent.view_on_block_explorer(entry.address, 'addr') def on_request_payment() -> None: parent.jump_to_receive_with_address(entry.address) def on_private_key() -> None: def onPw(password: str) -> None: # present the private key view controller here. pk = None try: pk = parent.wallet.export_private_key( entry.address, password) if parent.wallet else None except: parent.show_error(str(sys.exc_info()[1])) return if pk: vc = private_key_dialog.PrivateKeyDialog.alloc().init( ).autorelease() pkentry = private_key_dialog.PrivateKeyEntry( entry.address, pk, entry.is_frozen, entry.is_change) utils.nspy_put_byname(vc, pkentry, 'entry') parentvc.navigationController.pushViewController_animated_( vc, True) parent.prompt_password_if_needed_asynch(onPw) def on_sign_verify() -> None: vc = sign_decrypt_dialog.Create_SignVerify_VC(entry.address) parentvc.navigationController.pushViewController_animated_(vc, True) def on_encrypt_decrypt() -> None: if not parent.wallet: return try: pubkey = parent.wallet.get_public_key(entry.address) except: print("exception extracting public key:", str(sys.exc_info()[1])) return if pubkey is not None and not isinstance(pubkey, str): pubkey = pubkey if not pubkey: return vc = sign_decrypt_dialog.Create_EncryptDecrypt_VC( entry.address, pubkey) parentvc.navigationController.pushViewController_animated_(vc, True) def on_copy() -> None: parent.copy_to_clipboard(entry.addr_str, 'Address') actions = [ [_('Cancel')], [_('Copy Address'), on_copy], [_("Request payment"), on_request_payment], ] watch_only = entry.is_watch_only if entry.num_utxos and parentvc.navigationController: from .coins import PushCoinsVC actions.insert(2, [ _('Show Coins (UTXOs)'), PushCoinsVC, [entry.address], parentvc.navigationController ]) if isinstance(parentvc, AddressDetail): actions.insert(2, [_('Share/Save QR...'), lambda: parentvc.onQRImgTap()]) if not watch_only: def onToggleFreeze() -> None: _ToggleFreeze(entry) if callable(toggleFreezeCallback): toggleFreezeCallback() actions.append([ _('Freeze') if not entry.is_frozen else _('Unfreeze'), onToggleFreeze ]) if not watch_only and not entry.is_frozen and entry.balance > 0: actions.append([ _('Spend from this Address'), lambda: _SpendFrom(entry, vc=parentvc) ]) actions.append([_("View on block explorer"), on_block_explorer]) if not watch_only: actions.append([_('Private key'), on_private_key]) try: typ = b58_address_to_hash160(entry.address)[0] can_sign = typ == constants.net.ADDRTYPE_P2PKH except: can_sign = is_segwit_address(entry.address) if can_sign: if not watch_only: actions.append([_('Sign/verify Message'), on_sign_verify]) actions.append([_('Encrypt/decrypt Message'), on_encrypt_decrypt]) else: actions.append([_('Verify Message'), on_sign_verify]) utils.show_alert( vc=parentvc, title=_("Options"), message=entry.addr_str, # [0:12] + "..." + entry.addr_str[-12:], actions=actions, cancel=_('Cancel'), style=UIAlertControllerStyleActionSheet, ipadAnchor=ipadAnchor)
def __init__(self, dialog, dele: 'Delegation', mode: str): """ :type dialog: QDialog :type callback: func """ QGridLayout.__init__(self) self.setSpacing(8) self.setColumnStretch(3, 1) self.dialog = dialog self.dele = dele self.mode = mode if dele and dele.addr: self.addresses = [dele.addr] else: self.addresses = [''] delegations = self.dialog.parent().wallet.db.list_delegations() for addr in self.dialog.parent().wallet.get_addresses_sort_by_balance(): if addr in delegations: continue addr_type, __ = b58_address_to_hash160(addr) if addr_type == constants.net.ADDRTYPE_P2PKH: self.addresses.append(addr) address_lb = QLabel(_("Address:")) self.address_combo = QComboBox() self.address_combo.setMinimumWidth(300) self.address_combo.addItems(self.addresses) self.addWidget(address_lb, 1, 0) self.addWidget(self.address_combo, 1, 1, 1, -1) self.address_combo.currentIndexChanged.connect(self.on_address) staker_lb = QLabel(_("Staker:")) self.staker_e = ButtonsLineEdit() self.addWidget(staker_lb, 2, 0) self.addWidget(self.staker_e, 2, 1, 1, -1) fee_lb = QLabel(_('Fee Percent:')) self.fee_e = QLineEdit() self.addWidget(fee_lb, 3, 0) self.addWidget(self.fee_e, 3, 1, 1, -1) self.optional_lb = QLabel(_('Optional:')) self.addWidget(self.optional_lb, 4, 0) self.optional_widget = QWidget() optional_layout = QHBoxLayout() optional_layout.setContentsMargins(0, 0, 0, 0) optional_layout.setSpacing(0) gas_limit_lb = QLabel(_('gas limit: ')) self.gas_limit_e = AmountEdit(lambda: '', True, None, 0, 0) self.gas_limit_e.setText('2250000') gas_price_lb = QLabel(_('gas price: ')) self.gas_price_e = AmountEdit(lambda: '', False, None, 8, 0) self.gas_price_e.setText('0.00000040') optional_layout.addWidget(gas_limit_lb) optional_layout.addWidget(self.gas_limit_e) optional_layout.addStretch(1) optional_layout.addWidget(gas_price_lb) optional_layout.addWidget(self.gas_price_e) optional_layout.addStretch(0) self.optional_widget.setLayout(optional_layout) self.addWidget(self.optional_widget, 4, 1, 1, -1) self.cancel_btn = CancelButton(dialog) self.do_btn = QPushButton(self.mode[0].upper() + self.mode[1:]) self.do_btn.clicked.connect(self.do) buttons = Buttons(*[self.cancel_btn, self.do_btn]) buttons.addStretch() self.addLayout(buttons, 5, 2, 2, -1) self.update()