def dscancel(
            self, *, tx: Transaction, new_fee_rate: Union[int, float, Decimal]
    ) -> PartialTransaction:
        """Double-Spend-Cancel: cancel an unconfirmed tx by double-spending
        its inputs, paying ourselves.
        'new_fee_rate' is the target min rate in sat/vbyte

        note: it is the caller's responsibility to have already called tx.add_info_from_network().
              Without that, all txins must be ismine.
        """
        assert tx
        if not isinstance(tx, PartialTransaction):
            tx = PartialTransaction.from_tx(tx)
        assert isinstance(tx, PartialTransaction)
        tx.remove_signatures()

        if not self.can_rbf_tx(tx, is_dscancel=True):
            raise CannotDoubleSpendTx(_('Transaction is final'))
        new_fee_rate = quantize_feerate(new_fee_rate)  # strip excess precision
        tx.add_info_from_wallet(self)
        if tx.is_missing_info_from_network():
            raise Exception("tx missing info from network")
        old_tx_size = tx.estimated_size()
        old_fee = tx.get_fee()
        assert old_fee is not None
        old_fee_rate = old_fee / old_tx_size  # sat/vbyte
        if new_fee_rate <= old_fee_rate:
            raise CannotDoubleSpendTx(_("The new fee rate needs to be higher than the old fee rate."))
        # grab all ismine inputs
        inputs = [txin for txin in tx.inputs()
                  if self.is_mine(self.adb.get_txin_address(txin))]
        value = sum([txin.value_sats() for txin in inputs])
        # figure out output address
        old_change_addrs = [o.address for o in tx.outputs() if self.is_mine(o.address)]
        out_address = (self.get_single_change_address_for_new_transaction(old_change_addrs)
                       or self.get_receiving_address())
        locktime = get_locktime_for_new_transaction(self.network)
        outputs = [PartialTxOutput.from_address_and_value(out_address, value)]
        tx_new = PartialTransaction.from_io(inputs, outputs, locktime=locktime)
        new_tx_size = tx_new.estimated_size()
        new_fee = max(
            new_fee_rate * new_tx_size,
            old_fee + self.relayfee() * new_tx_size / Decimal(1000),  # BIP-125 rules 3 and 4
        )
        new_fee = int(math.ceil(new_fee))
        output_value = value - new_fee
        if output_value < self.dust_threshold():
            raise CannotDoubleSpendTx(_("The output value remaining after fee is too low."))
        outputs = [PartialTxOutput.from_address_and_value(out_address, value - new_fee)]
        tx_new = PartialTransaction.from_io(inputs, outputs, locktime=locktime)
        tx_new.set_rbf(True)
        tx_new.add_info_from_wallet(self)
        return tx_new
Double-Spend-Cancel: cancel an unconfirmed tx by double-spending
        its inputs, paying ourselves.
        'new_fee_rate' is the target min rate in sat/vbyte

        note: it is the caller's responsibility to have already called tx.add_info_from_network().
              Without that, all txins must be ismine.
        
electrum/wallet.py