Victor forwarded me your request of giving your user a wallet by which they can manage their asset with their keys. There are many non-custodian wallets, but BTrade the exchange requires one which can serve the functionalities expected from an exchange, and serve it with a better user experience than what current non-custodian wallet can do.
I think what you wanted can be solved with a Trading Account smart contract. Here is the concept. Trading Account is administrated by users, which allows BTrade to execute some operations with a piece of signed permission from the user. We used such “signed permission” in some of our projects with good results.
I explain the “Trading Account” concept by the steps users use it:
For buying Ether:
1. BTrade produces a plugin for αWallet, signed. 2. User clicks "Buy Ether". A message shows that the user should
transfer fiat currency into a certain bank account, with an identifier as the transaction reference. For now, think the identifier the user’s Ethereum address; in reality, it needs to be transformed for privacy. 3. When BTrade accounted the fiat, the wallet would pop up a notification message to the user that BTrade has received the money. On the blockchain, this can be done by BTrade creating daily Ethereum events each containing a bloom filter that has all the identifier of the day in it. On the user’s mobile, the balance is displayed as a fiat custodian account (created if not already). 5. The user then chooses to buy the Ether at the market price or with a limit order. As the blockchain transaction gets settled, the user has their Ether balance on the mobile in a “trading account”.
Selling Ether, limit order (market order is a special type of limit order):
1. The user chooses the price they wish to sell Ether for, and how
long the order would stand for, with a reasonable default of 2 weeks. 2. When the user hit “issue order”, the order is cryptographically signed by the user and sent to BTrade’s endpoint. BTrade can technically withdraw the amount of Ether specified by this order any time before the order expires, from the user’s “Trading Account”, but it chooses to do so only if the order has a match. 3. When the order is matched and executed, BTrade withdraws Ether from the user’s “Trading account” and updates the balance of the user’s fiat account. 4. The user receives a notification and can observe the order execution result and balance on their mobile wallet.
This method is better than the traditional way which requires the user to send Ether to the exchange, because it is instant, and it does not cost ether if the order didn’t get executed.
On the other hand, the user might spend money from their Trading Account, since the user is the sole administrator of it. If the Trading Account’s balance drops below the amount in the user’s sell order, the sell order will have to be cancelled. However, this can’t be done in a reliable way, since there is a very small chance (not small if the user is a miner) that both user’s spending transaction and Ethereum sell-order is executed, forcing the exchange to reverse the order. This is called a racing condition, and solutions are either expensive or inconvenient.
Solution 1: Cheque account.
This is the usual approach, and we are doing the effort to standardise it by naming it “cheque account”. A Cheque Account is created instead of a Trading Account. When the user sells Ether, she “pre-authorise” BTrade to withdraw funds from the cheque account as if issuing BTrade a bound cheque. This costs her a bit of gas.
When an order is matched, BTrade withdraw Ethers from the Cheque Account since it has the pre-authorisation.
Pre-authorised Ethers are locked up. The user can spend the remaining portion, but not the portion locked up by the pre-authorisation. This prevents the racing condition, however, it doubles the gas expenditure, since the user needs to pay gas to pre-authorise, and BTrade has to pay gas again to withdraw from the user’s Cheque Account.
Solution 2: Slow-withdraw behaviour for Trade Account.
The user can spend directly from their Trading account similar to how they can spend from their Ethereum address balance, with one of the two methods.
The user sends a signed message to BTrade. BTrade would close open orders if it sees the need, then, withdraws the said amount by using the signed message and send it as the user instructed. BTrade, in this case, does not need to be trusted since the only harm it can do is to not to execute such a transaction.
If BTrade became unavailable (e.g. the company is closed, the server is down), the user can always send a transaction to their Trading Account themselves. However, he needs to first issue an authorisation to himself, wait for it bedded in the blockchain, wait for a 1-minute timeout, then dispatch the money with a second command to the Trade Account. If the user tries to use the method when BTrade is not unavailable (e.g. the user is travelling in China and BTrade is behind the Great Firewall of China), BTrade will monitor the blockchain for such authorisations and delete open orders invalidated by it. The one-minute wait-gap is intended for BTrade to do so.
In all of this email, I assumed that the user has the money for gas to send the transactions in the first place. This assumption, if not valid, can be amended by some gas station protocol, which we were already using a lot this year. Serenity would provide a final cure for it in the years to come.