Include a generic Wallet actor constructor in the actor systems and allow
passing in a generic Wallet actor implementing xtra::Handlers into the cfd
actors.
Rename 'Maker' and 'Taker' to 'MakerActorSystem' and 'TakerActorSystem' for
readability.
Co-authored-by: Mariusz Klochowicz <mariusz@klochowicz.com>
This allows us to avoid the use of the constant in two places which
removes the dependency on the constant from the taker entirely.
The logic here is generally not great - in particular having the taker
anticipate, which announcement it is going to be - but this is the
least invasive way of making the term dynamic.
We have a 1:1 relationship (and the fact that we don't remove cfds) between cfd and order at the moment, so once the cfd was inserted we cannot creat another cfd for the same order.
Thus, we should remove the order from the feel by sending `None`.
If the maker tells the taker that the take request was for an invalid
order ID, we should do something other than panic. For example,
logging and treating the situation as if the maker had rejected the
take request.
We almost always have the entire `Cfd` available when we call this
function. It is therefore much easier to simply pass the entire
`Cfd` in instead of selective data.
Inserting cfd or updating its state requires a follow-up update on the Cfd feed
sent to the UI. Encapsulate the behaviour in functions that are shared
across Cfd actors.
Once we have collaborative close present in the state(s) we lock in the profit based on the price of the collaborative close.
Note: Currently no automated validation on the maker side if the given amounts and price of collaborative settlement are sane.
The `oracle::Actor` only needs to be able to send the
`oracle::Attestation` to an actor who can handle it. We were already
able to express this using trait bounds, but it was blocking us from
being able to make the `{maker_taker}_cfd::Actor` generic over
different actors due to infinite, cyclic types.
The `monitor::Actor` only needs to be able to send the
`monitor::Event` to an actor who can handle it. We were already able
to express this using trait bounds, but it was blocking us from being
able to make the `{maker_taker}_cfd::Actor` generic over different
actors due to infinite, cyclic types.
Distinguish between collaborative close and cet closing.
Moved the payout on the `Cfd` which decides what the payout of the `Cfd` is, where
- `None` means the payout is not decided yet (we can optimize that and potentially combine this with `profit` in another iteration)
- `Some(payout)` can be a refund, collaborative or cet payout
Refund is handled in an early exit guard based on the state.
Collaborative settlement has priority over cet payout (attestation). In case there is a collaborative settlement present we always return payout based on that.
The function signature didn't need to take the whole state, as it was only
borrowed internally.
Removes the need for many `.clone()` calls sprinkled in the codebase.
The way I see it, an oracle "event" consists of both an "announcement"
and an "attestation". In the case of this message, we want to keep
track of the state of the "attestation", so the rename should make it
unambiguous.
Instead of always keeping track of the next 24 hours of announcements,
we instruct the `oracle::Actor` to fetch (if necessary) announcements
based on new orders.
At the moment this results in removing code which allowed us to fetch
several announcements in parallel, but we will need to reintroduce it
once we let the `daemon`s create CFDs with multiple attestation
events.
We are looping over multiple CFDs when trying to publish the CET.
If we fail inside the loop then the next CFD(s) are not processed and CETs might not get published properly.
This should make the code more resilient.
Reasoning:
The state transition can fail, hence the result.
It can, however, happen that there is no failure, but we still did not transition to a new state.
In such cases we don't want to save the state in the database because it would be an unwanted duplicated entry.
The `Attestation` in the `oracle` module has `Desiarialization` rules that conflict with loading it from the db.
We should not reuse domain structs between modules anyway, so this was cleaned up by introducing a dedicated `model::Attestation` and mapping to `oracle::Attestation`.
Instead of the oracle actor sending out the `Announcements` we only store them internally and let the cfd actors chose what `Announcement` is relevant given the term of the offer.
The specific `Announcement` is then fetched from the oracle actor.
The monitoring logic for pending attestations remains the same.
- store TakerId for proposals to be able to respond to specific taker about
settlement proposal when the user takes action
- send the collab settlement response (accept or reject) from the maker
- handle rejection (remove from the map), CFD state in the UI returns to "Open"
- Handles the Oracle's attestation in the cfd actor, transition according to the knowledge we have about the timelock expiry already.
- Tries to publish the CET if we are in `CetStatus::Ready`, i.e. both the attestation and timelock expiry happened. We try publishing if either event happened, and just print a log in case it's not ready yet.
- Tries to re-publish CET if we are in `PendingCet` upon restart.
- Re-triggers CET monitoring upon startup.
- Extends any state after `ContractSetup` to be able to store the attestation. (see below for ideas to change that)
Things that could be done different:
Currently we are carrying on the attestation through a lot of states - because we cannot just transition the user to `OpenCommitted` because it is a user decision to go for commit, but we have to keep the attestation around once it happened.
To reduce the state complexity, we could store the attestation independent of the state, but associated with the cfd.
This would make things a lot simpler, but we would then always have to go to the database to check if the attestation is already around (which might make other parts more complex).
Add support for multiple update proposals.
A taker might request to update/change a CFD in different ways, e.g.: propose to settle it or roll over.
In order to support different scenarios we introduce another layer of abstraction.
The rest of the changes creates a boilerplate for the actual rollover protocol.
New HashMap can store both incoming and outgoing settlement proposals at the
same time and resulted in some code simplification, as there are less types
needed to convey the intention.
Provide a type alias for convenience (this also ensures that both binaries store
settlement proposals in the same way)
Opted not to implement an additional message to fetch a specific announcement from the Oracle actor because it would have made the oracle actor unnecessarily complex (We would have to split it into different functionality by trait).
The taker cfd actor holds a sliding window of all the announcements received from the oracle actor.
Keep track of outgoing/incoming settlement proposals in a hashmap inside the CFD
rocket that is available as a Rocket state in order to derive correct CfdState
for the UI.
Add placeholders for actions for accepting/rejecting settlement offers in the maker.
Also:
- rename Accept/Reject in few places to reduce ambiguity between interacting
with an order and a settlement proposal.
- allow only one in-flight settlement proposal from the taker