예제 #1
0
    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))
예제 #3
0
    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
예제 #6
0
 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
예제 #7
0
    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)
예제 #8
0
 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
예제 #9
0
 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
예제 #10
0
파일: keepkey.py 프로젝트: asfin/electrum
 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
예제 #12
0
 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)
예제 #13
0
    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))
예제 #14
0
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)
예제 #15
0
    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()