Coder Social home page Coder Social logo

get10101 / itchysats Goto Github PK

View Code? Open in Web Editor NEW
62.0 9.0 17.0 15.78 MB

CFDs on Bitcoin.

Home Page: https://itchysats.network

License: MIT License

Rust 85.22% HTML 0.04% JavaScript 0.21% CSS 0.11% TypeScript 14.29% Shell 0.08% Dockerfile 0.02% EJS 0.02%
bitcoin blockchain cfd cryptocurrency decentralized non-custodial peer-to-peer rust trading

itchysats's People

Contributors

1010tom avatar bonomat avatar bors[bot] avatar da-kami avatar delicioushair avatar dependabot[bot] avatar holzeis avatar klochowicz avatar luckysori avatar lukechilds avatar restioson avatar rishflab avatar romanz avatar scratchscratchscratchy avatar thomaseizinger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

itchysats's Issues

Taker to initiate CFD rollover

The taker should be able to say that he wants to roll over the contract for another iterations.

The maker should only accept this if the taker should not have gotten liquidated already.

Proposal:
Initially we can make this a manual step, e.g. the user has to click a button to say: roll over. Eventually I'd see this as an automated action. Whenever the user comes online, he rolls over to the next iteration.

Use margin to make `build_party_params` pass

Currently the taker panics because we pass a ZERO Bitcoin amount when building params.

Make construction of party params work.

  • Load the margin from DB
  • Update the CFD state after successful contract setup
  • Make building the params pass on both sides

Refund timelock should be in seconds not in blocks

Currently the refund timeout is depicted in blocks

https://github.com/comit-network/hermes/blob/d8b5b6498bcd4fc5fdb5df6d9b183e4edc09b268/cfd_protocol/src/lib.rs#L665

This is risky as the contract term expires at a fixed point of time, i.e. when the oracle publishes the attestation. Refund should be possible shortly afterwards.
(Note: We cannot use an absolute timelock here because it would allow a malicious user to publish an old state and immediately publish the refund transaction.)

On average Bitcoin has a block every 10 minutes. There are times when blocks are showing up faster or slower. I can happen that a relative timelock in blocks could be faster than a relative timelock in seconds.
Hence, it could happen that the refund timelock expires faster than expected allowing an user to refund before the oracle would publish its signature.

Our API would support witching from blocks to time easily but care should be taken when doing so:
see https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki

If bit (1 << 31) of the sequence number is set, then no consensus meaning is applied to the sequence number and can be included in any block under all currently possible circumstances.

If bit (1 << 31) of the sequence number is not set, then the sequence number is interpreted as an encoded relative lock-time.

The sequence number encoding is interpreted as follows:

Bit (1 << 22) determines if the relative lock-time is time-based or block based: If the bit is set, the relative lock-time specifies a timespan in units of 512 seconds granularity. The timespan starts from the median-time-past of the output’s previous block, and ends at the MTP of the previous block. If the bit is not set, the relative lock-time specifies a number of blocks.

The flag (1<<22) is the highest order bit in a 3-byte signed integer for use in bitcoin scripts as a 3-byte PUSHDATA with OP_CHECKSEQUENCEVERIFY (BIP 112).

Embed frontend in binaries

Automate embedding of frontend artifacts in the respective binaries and serve them on the same port as the HTTP API.

Outcome should be a self-contained binary that serves its own frontend once started.

Price recommendation for the maker's sell offer creation

What we currently have:

image

The maker currently has to enter a price manually when pricing the CFD.
This is quite cumbersome and can be optimized.

In an initial iteration I propose that we change the fields to:

  1. Instead of an editable field OrderPrice have an editable field Spread (in percent) that is defaulted to 3%
  2. Maker the OrderPrice field non-editable
  3. Calculate the OrderPrice from current price and spread.

(3.) can easily be achieved with a calculation endpoint (similar to the taker's /calculate/margin) that is triggered on either a price change or a spread change.

Note: This ticket is depending on having a price feed as described in #96

Note: This could eventually be extended with automated offer re-publication, but that is out of scope for this ticket.

Create oracle actor that monitors for attestations to price events

We need an actor that interacts with the olivia instance at https://h00.ooo/ and informs other actors about attestations to price events.

  1. The CfdActor needs to be told about price attestations so it can expose a choice to the user on settling via the now unlocked CET.
  2. The monitoring actor needs to know about the price attestation to start monitoring the correct CET.

The above two can easily be added later because they are just about sending a message to the correct address.

A minimal useful step is to log each price attestation.

Cfd handling upon daemon restart

Upon restarting a deamon the application has to be able to handle already existing Cfds.

This means, when starting the Cfd actor and the monitoring actor we have to reason about the Cfd state and might want to trigger certain interaction so the Cfd is properly loaded and displayed, as well as monitoring is picked up to trigger state changes.

When implementing the monitor actor we had planned to just load all Cfds from the db and pass them to the monitor actor so it could trigger monitoring as needed based on the Cfd state.
i.e.: match statement in the constructor of monitor actor that triggers the remaining part of the transaction monitoring based on the state.

For the Cfd actor we did not invest too much time in what a restart would require. The assumption is that it does no have to do anything, because it always gets messages from another actor to transition the Cfd into a new state.
One thing we will have to think about is how to deal with Cfds that upon restart are in a state that is prior to PendingOpen. I think such Cfds should be transitioned to a state SavelyAborted by the Cfd actor upon a message from whom?
i.e. we don't go on with any Cfd that was not completely set up.

Note: I would still not delete SafelyAborted Cfds for now, including all states (since we always append the state it will keep it unless that logic is changed). We can filter them out upon initial load (...). Once we have more confidence in the implementation we could add removing them.

Persistent storage for taker & maker

recommentation: sqlx + sqlite similar to oracle impl

recommentation: Append stuff as you learn things. i.e. keep appending state so you see all the states you went through. (we should not lose data that is important when updating storage)

Epic: Ready to play

We should sort out everything that is between us and sending a download link to someone for trying out the software. This does not include features but only infrastructure, shipping etc. We can "play" with the software in an unfinished state. The point of prioritizing this is to avoid surprises after we are "done" that prevent us from trying out the software.

Calculate profit in daemon and display in UI

The CFD profit is dependent on the current price (calculated). We should take the current price into account for the CFD feed.

  • upon CFD feed update re-calculate the profit every time
  • upon price update trigger a CFD feed update

This requires some kind of price feed (from the Oracle or a component that publishes a reliable price related to the Oracle's price).

How to deal with limbo offer state

With the current model, offers will "disappear" if a taker took it.

With this model we have an in-between state on the maker side: the state in between of a taker requesting to take an offer and the maker accepting/rejecting it.

Differently said: multiple takers might want to take the same offer from the same maker.

This has some further implications:
Atm an incoming TakeOrder request will overwrite an existing one. This can lead to a problem where the user (the maker) wants to accept an order for one user but it gets overwritten by an incoming request from a different taker.

The question is how do we want to deal with this?

One click release

When the time comes, one click / action should be all we need to do create a "release" that provides us with download-able production binaries.

Integrate wallet with frontend

  • Get an address to transfer BTC to the tool
  • See balance
  • See blockheight (?)
  • See transactions (?)

Note: We might not need a full blown wallet view, might be good enough to integrate balance display and only have the CFDs to represent the "transaction view".

Define Oracle (HTTP?) API

The oracle will need to expose an API that both the broker and trader daemon can consume. We need to define this API.

Maker with a CFD they can't accept/reject

After rejecting first offer and creating a new one which was meant to be accepted (to test the happy path), I discovered that I could not accept or reject the offer.

Maker log:


2021-09-24 10:27:38  INFO POST /api/order/sell application/json:
2021-09-24 10:28:02 DEBUG Taker wants to take an order taker_id=e53977ec-fb86-4e81-bd23-d1a45320153f quantity=101 order_id=15762b72-9644-4da7-80d4-ad62d56cc74b
2021-09-24 10:28:08  INFO POST /api/order/reject text/plain:
2021-09-24 10:28:08 DEBUG Maker rejects an order msg.order_id=15762b72-9644-4da7-80d4-ad62d56cc74b
2021-09-24 10:28:15  INFO BitMex quote updated bid=44638 ask=44638.5
2021-09-24 10:28:23  INFO POST /api/order/sell application/json:
2021-09-24 10:28:30 DEBUG Taker wants to take an order taker_id=e53977ec-fb86-4e81-bd23-d1a45320153f quantity=101 order_id=2438638b-8897-4f1c-ab25-50ae1443852d
2021-09-24 10:28:35  INFO POST /api/order/accept text/plain:
2021-09-24 10:28:35 DEBUG Maker accepts an order msg.order_id=2438638b-8897-4f1c-ab25-50ae1443852d
thread 'rocket-worker-thread' panicked at 'called `Result::unwrap()` on an `Err` value: no rows returned by a query that expected to return at least one row', daemon/src/maker_cfd_actor.rs:276:10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'thread 'rocket-worker-threadrocket-worker-thread' panicked at '' panicked at 'all branches are disabled and there is no else branchall branches are disabled and there is no else branch', ', daemon/src/routes_maker.rsdaemon/src/routes_maker.rs::3232::55

After restarting the maker the faulty CFD is still stuck in the database and still crashes the maker when one of the buttons is clicked.

Taker can't take twice

I realized that a taker can only take once and not again:
How to reproduce:

  1. maker creates offer
  2. taker takes
  3. maker accepts or rejects
  4. taker sees cfd in correct state
  5. maker creates new offer
  6. Taker cannot take again

I'm not sure if this was introduced after #119 or was already present before.

It looks like the connection between maker and taker is lost:

Maker log

2021-09-24 07:45:04 DEBUG Taker wants to take an order taker_id=c7cbc045-96d2-436c-92a8-d56028545249 quantity=200 order_id=ddc8b504-2485-46cf-884d-a081b3017b34
2021-09-24 07:45:07  INFO POST /api/order/reject text/plain:
2021-09-24 07:45:07 DEBUG Maker rejects an order msg.order_id=ddc8b504-2485-46cf-884d-a081b3017b34
2021-09-24 07:45:07 ERROR e=channel closed

Taker log:

2021-09-24 07:45:04  INFO Taking current order: Order { id: OrderId(ddc8b504-2485-46cf-884d-a081b3017b34), trading_pair: BtcUsd, position: Sell, price: Usd(10000), min_quantity: Usd(100), max_quantity: Usd(1000), leverage: Leverage(5), liquidation_price: Usd(8368.200836820083682008368201), creation_timestamp: SystemTime { tv_sec: 1632433368, tv_nsec: 569400000 }, term: 28800s, origin: Theirs }
2021-09-24 07:45:07 DEBUG Order rejected order_id=ddc8b504-2485-46cf-884d-a081b3017b34

Price feed for taker and maker

In order to be able to price the CFD as the maker we will need the current price feed. Given, that the maker might want to open counterpositions on Bitmex we should potentially use the Bitmex price feed.

This will enable: #33

Use Bitmex for price feed

I recommend using Bitmex API feed. Our "usual" source (kraken) does not offer CFDs.


I played around with this library which works nicely: https://github.com/dovahcrow/bitmex-rs/
unfortunately it hasn't been released for a while but the latest master works great.

It comes with ws subscription. This gives you the latest rates

let mut client = BitMEXWebsocket::new().await?;

client
    .send(Command::Subscribe(vec![
        Topic::QuoteBin1m(Some("XBTUSD".to_string())),
    ]))
    .await?;

while let Some(msg) = client.next().await {
println!("{:?}", msg);
    }

CFD position margin (collateral in Bitcoin)

The collateral is still missing in the UI. Without the collateral to be locked up in BTC there is no DLC, so we should get that in.
We will have to find a way to let the taker daemon handle the calc upon the taker changing the quantity.

Since this value is independent of the offer I think we will have to handle it separately.

Something like:

  • POST /collateral
    • Body: { quantity, price, leverage }
  • Add collateral event to the feed and update collateral UI element upon feed updates

Epic: Happy path click-through

As a first target, we want to be able to do a full run-through of the happy path:

  1. Broker goes online
  2. Broker configures their quote in the daemon
  3. Trader connects and receives quote
  4. Trader accepts quote and they set up a CFD
  5. Trader proposes roll-over of contract for another period
  6. Trader proposes settlement according to current price
  7. Broker accepts settlement and the contract pays out accordingly (on-chain)

Ability to start the taker without the maker daemon

The taker daemon should be more resilient upon startup. If the maker is not available it should print a message like maker currently not available, retrying connection setup in x seconds... and then retry setting up the connection.

Retrieve next price attestation event from oracle

We should do something similar as with the BitMex's rate:

  1. A loop that keeps refreshing it.
  2. Store the result in a watch channel.
  3. When making an offer, get the next event ID and put it in the offer.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.