Repository: spesmilo/electrum

Issue:
Change address setting is ignored if sending from imported addresses
If you're sending from an imported address, the "use change address" setting is ignored, as per this line in wallet.py:

```
if not self.use_change or account == -1:
```

This situation can occur unexpectedly on a regular non-custom "Send" transaction if you have any imported addresses with a non-zero balance. This can result in the change going back to one of your regular addresses, instead of a change address.

The original intention may have been to prevent accidentally sweeping the entire balance of an imported paper wallet when you spend only some of it, but if a transaction has multiple source addresses, this can happen anyway, as per this thread on bitcointalk:

https://bitcointalk.org/index.php?topic=699082.0

It would be better to always use change addresses, even with imported addresses, if the user has turned the "Use change addresses" option on. This would also reduce the chance of lost coins, since change addresses are regenerated from the seed.

The proposed solution of changing the above line to:

```
if not self.use_change:
```

would seem to do the trick.

(Sorry I don't know how to create pull requests.)



Discussion:
The line in question is https://github.com/spesmilo/electrum/blob/master/lib/wallet.py#L605 on current HEAD.

``` Python
def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None):
    "add change to a transaction"
    change_amount = total - ( amount + fee )
    if change_amount > DUST_THRESHOLD:
        if not change_addr:

            # send change to one of the accounts involved in the tx
            for i in range(len(inputs)): # For #769, if one input is not imported, then assume there will be no problem with paper wallet importing.
                address = inputs[i].get('address')
                account, _ = self.get_address_index(address)
                if account != IMPORTED_ACCOUNT: break

            if not self.use_change or account == IMPORTED_ACCOUNT:
                change_addr = inputs[-1]['address']
            else:
                change_addr = self.accounts[account].get_addresses(1)[-self.gap_limit_for_change]

        # Insert the change output at a random position in the outputs
        posn = random.randint(0, len(outputs))
        outputs[posn:posn] = [( 'address', change_addr,  change_amount)]
    return outputs
```

This would seem like a better solution:

Check all inputs, and if any one input is a non-imported address, THEN follow the use_change.

I guess whether you choose to change
`if not self.use_change or account == IMPORTED_ACCOUNT:` to `if not self.use_change:`
or to do the looping method I wrote above comes down to what Thomas decides is best for the project.

Or maybe he will say it is best as is... who knows.

I think looping and checking for a non-imported input would be the path of least danger.

> Check all inputs, and if any one input is a non-imported address, THEN follow the use_change.

Possibly, but I still think that's potentially misleading. There's certainly no warning anywhere in the UI that turning on "Use change addresses" applies only to generated addresses. I would fully expect the change from an imported address to go into a change address.

This is wanted. we already had a situation where a user lost coins because they expected change to go back to their imported address.

Even if this is wanted, it's currently broken either way. I sent coins from an imported address (along with a couple of generated addresses) and the change want to a regular generated address, not a change address or the imported address. This behavior seems unquestionably wrong.

I sympathize with a user losing coins but the current behavior makes no sense - and would not prevent anyone from losing coins in a similar situation.

The transaction is https://blockchain.info/tx/7ba987f202323c302b7cc736436a1858579255b131e4f7332caced3a96d945ed

The imported address is: 1DavidGAHiCiiSZgBrbteAkby5AUf6QR3o
Yet the change went to: 1K2TZGCiP8F2sZHtZ73LtyMQJUygFxwUUH

Wouldn't `inputs[-1]['address']` be better as `inputs[0]['address']` seeing as the input you are checking is input[0]?

sorry I did not understand.. reopening


Resolving patch:
diff --git a/lib/wallet.py b/lib/wallet.py
--- a/lib/wallet.py
+++ b/lib/wallet.py
@@ -603,7 +603,7 @@ def add_tx_change( self, inputs, outputs, amount, fee, total, change_addr=None):
                 account, _ = self.get_address_index(address)
 
                 if not self.use_change or account == IMPORTED_ACCOUNT:
-                    change_addr = inputs[-1]['address']
+                    change_addr = address
                 else:
                     change_addr = self.accounts[account].get_addresses(1)[-self.gap_limit_for_change]
 


Test patch: