Liquidators
The Liquidator Service is divided in four main tasks, one foreach pair:
- FetchJob
- OraclePriceJob
- UpdateCoverJob
- ExecuteJob
Now we are going to discuss each on in detail.
FetchJob
This job is responsible for retrieve the swaps from the blockchain and save them inside the database for the liquidation/execution.
- Retrieve active epoch (epoch of last fetched swap)
- Fetch thanks to the blockchain events the swaps
- + CreatedSwap
- – ExecutedSwap
- – ClosedSwap
- – LiquidateSwap
- +,− means filtering (so we filter the CreatedSwap removing the ExecutedSwap, ClosedSwap, UpdateSwap). In order to achieve this task, we developed a function based on binary search. The main idea is from the active epoch to the latest block we execute on call to the node, if the answer is good this is the answer in the order case we split the interval into (active epoch, (active epoch + latest block)/2) and ((active epoch + latest block)/2 + 1, latest block) and we recursively explore until we have retrieved the full list.
- Removing the swaps already present in the database (by the blockchain id)
- Save the new swaps inside the database
- Update the active epoch with the latest fetched swap
OraclePriceJob
Due to the relatively slow update time of the oracles and in order to save calls to the node, this job will retrieve the update price every fixed time instead foreach open swap.
- We call the chainlink oracle and retrieve the current price of the asset
- We update into the database the price with the new one.
UpdateCoverJob
- Retrieve all the open swaps
- Retrieve the minimum epoch of the open swaps
- Call the AddedCoverToSwap event from (minimum epoch, latest block)
- Foreach swap
- We check if there is a cover
- No: Do nothing
- Yes: We retrieve the detail of the swap from the blockchain with a new call. Inside the detail we found the new threshold value. Therefore, we update the swap (saving also the epoch of the latest cover).
- We check if there is a cover
ExecuteJob
- Retrieve the lastest updated price from the database
- Retrieve the current machine timestamp
- Retrieve the liquidable/executable swaps
- SwapType ⚌ 0 (AssetDirection) threshold ❮⚌ price
- SwapType ⚌ 1 (CurrencyDirection) threshold ❯⚌ price
- ExpiredSwaps executionTime ❮⚌ current machine timestamp
- Lock all the liquidable/executable swaps
- For foreach liquidable/executable swap
- SwapType ⚌ 0 (AssetDirection) we call the marginCall method on the smartcontract
- SwapType ⚌ 1 (CurrencyDirection) we call the marginCall method on the smartcontract
- ExcpiredSwap we call the executeSwap method on the smartcontract
Pay attention foreach call to a method of the smartcontract you will pay fee. To save a bit of ETH we implement a static call before the real call. This give us the advantage of if the static call will be reverted we won’t propagate the real call saving fees. This mechanics could be a bottleneck in cases of high levels of competion
The official liquidator is distributed as a docker image. In order to run a liquidator, you should fill the .env file properly and run the docker−compose file published from our side.