skycoin / teller

Skycoin exchange service
15 stars 30 forks source link

OTC Passthrough #222

Open gz-c opened 6 years ago

gz-c commented 6 years ago

"OTC Passthrough" refers to passing through purchases directly to an exchange, as opposed to directly from a wallet at a flat rate.

Implementation requirements:

Our implementation will use C2CX as the partner exchange. A library for interfacing with C2CX is available at https://github.com/skycoin/exchange-api.

Exchanges do not have an API for withdrawals (for good reason), so we will maintain a BTC balance in C2CX to make purchases with. Users' deposits will go to a separate cold wallet that we control, outside of the exchange. Our BTC held on C2CX will need to be periodically replenished manually. Note that this means the implementation must check that we have a sufficient balance in C2CX before we can make the purchase.

Similarly, payouts will be made from a local Skycoin wallet held on the teller server. This wallet will need its balance replenished. The sending of skycoin is handled outside of the passthrough component, so does not concern the passthrough implementation. The passthrough implementation must send the number of SKY bought from C2CX, to the Sender component.

C2CX's API does not let one specify how much BTC they want to spend; instead, the number of SKY to buy must be specified. Since our incoming deposits are in BTC, we will need to do some extra work to be able to spend a specific amount of BTC.

To spend the BTC on C2CX, first obtain the list of open sell orders. Sell orders are specified in terms of number of SKY at a given BTC price. Convert this value to the number of BTC it costs to purchase this entire sell order. Create an order at this price, with a maximum amount of SKY equal to the amount of SKY in this sell order (i.e. buy, the entire sell order). If the number of BTC is higher than the amount of BTC we have to spend, cap the amount, and adjust the amount of SKY appropriately (i.e., buy part of the sell order). Repeat this process until all BTC is spent.

Sell orders that we try to match may disappear before we can execute the buy order against them. To handle this, give all orders we place a 1 second timeout. If one of our orders is not executed within 1 second, cancel it. Then, wait for the order to be cancelled before trying again.

Sell orders may be partially filled before our buy order executes. In this case we can end up with a partially filled buy order. Ideally we cancel the rest of the order, but we must keep a record of how much we bought.

Simplest description of the purchase process in context of the whole system:

  1. User sends X BTC to their deposit address, is detected by the scanner system and sent to the passthrough system
  2. Passthrough system attempts to purchase X BTC worth of SKY from C2CX
  3. Passthrough system sends the number of SKY bought to the sender system

An initial implementation skeleton is sketched out in exchange/passthrough.go. The business logic needs to be implemented, and the flow of (place order, wait, complete or cancel) must be reasoned through and implemented. It must also handle unexpected order statuses from C2CX. Retryable and fatal statuses must be determined. The system should attempt to retry as much as possible. Only one deposit and exchange order should be processed at a time.

Some gists with background information and details on C2CX's API [these are drafts, do not follow them precisely]: https://gist.github.com/gz-c/0574138235c17c224901b5996395fd2d https://gist.github.com/gz-c/87cbc2a534ca58e8b89d4926216a2cb4 https://gist.github.com/gz-c/93c8757539ee1ff502342de04f7e634c

gz-c commented 6 years ago

We are using C2CX's "Market" API instead, which allows us to specify how much BTC we went to spend with a single order.