Posts

Inside HIVE to HBD conversions (slightly technical).

avatar of @andablackwidow
25
@andablackwidow
·
0 views
·
7 min read

When I read first article of @edicted about conversions, I was sure I have to write detailed description of how it works. However literally as I finished reading I've noticed price of Hive falling on internal market, checked UpBit to make sure it is related to pump on HBD and ended up using conversions myself for the first time on mainnet. The article turned out to be amazingly well timed. As a result I went to sleep after 5AM and next day I forgot about writing. However, since discussions on how collateralized conversion works continued in two more articles and in comments, here I am with my description :o)

(Actually there is one more article but I'm yet to read it).


The feed.

We have to start from learning how price is established inside hived.

Witnesses can send witness_set_properties_operation with hbd_exchange_rate among properties or just feed_publish_operation to declare price of HIVE. The price could be sent manually, but obviously is not. The scripts that read the price from external exchanges can stop working, there can be connection problems or, like recently, some exchanges stopped serving API calls from US based IP addresses. Witnesses can use different sources for their price readings, they might attach volume based weights to it, or even weight their sources based on some arbitrary trustworthiness factor. Finally in the end the price can actually be totally fabricated out of whole cloth. The point is, prices submitted by witnesses can be very different at any given time, although it is assumed that most will be roughly reflecting actual global market conditions and only some will be out of place. For that reason hived uses median of witness price feeds to produce an official feed entry. For example, latest price dump on internal market would only be somewhat reflected on feeds of witnesses that use it among their sources, but since it barely showed on most exchanges and only with delay as a result of arbitrage, it would not have much impact on official feed entry (at some point price on internal market was rushing down to 37 cents while price on Binance was still 44 cents - bots were super happy, I presume; notice how it only reached 41 cents on Binance while internal market dipped below 36 cents).

There are two more elements considered: when witness did not publish price for some time - HIVE_MAX_FEED_AGE_SECONDS (7 days) - it is considered stalled and discarded. Also when there are less than HIVE_MIN_FEEDS (7) witnesses as source of new feed entry, the whole entry is discarded.

Official internal price and feed history.

So, we know how a single feed entry is formed. It happens once every HIVE_FEED_INTERVAL_BLOCKS (effectively one hour). hived keeps a moving window of historical feed entries that since HF16 covers HIVE_FEED_HISTORY_WINDOW (effectively 3.5 days). When new entry is formed, the oldest one is removed. That window is a source of four internal prices: current_min_history - minimum value of feed entry in the window, current_max_history - maximum value, market_median_history - median value and finally the most important price used almost everywhere in hived, current_median_history. There is one more price that is considered, price that HIVE would have to have for HBD debt to reach hard limit. For most of the time current_median_history equals market_median_history, but if debt limit price is higher, the latter is used as official internal price of HIVE.

Notice how official internal price, due to being median from 3.5 days (median, not average!), is going to ignore all short lived pumps or dumps, even if they were broad enough to make it to feed entries. The price movement has to persist for more than half of history window to influence official internal price.


Conversions.

Conversion from HBD to HIVE (convert_operation) is simple. You state how much HBD you want to convert and after 3.5 days you get HIVE based on official internal price effective at that moment. Your HBD is burned and new HIVE is created in its place. The 3.5 days is not a coincidence. When you send a conversion request, all the feed entries that will eventually form price used for actual conversion are still in the future. If conversion from HIVE to HBD was the same, there would be no problem. However its purpose is significantly different. It is to allow reaction on situations like the recent pump of HBD price. Waiting 3.5 days to get the ammo for defending the peg would not be acceptable. That's why it gives you HBD immediately, but it comes with a price.

The collateralized_convert_operation has to take into account that future price of HIVE might be lower than current one. To prepare for that, it divides given amount of HIVE by HIVE_CONVERSION_COLLATERAL_RATIO, effectively considering only half of HIVE for calculating converted amount. Official internal price is a median of prices in feed history window - it can be significantly different from current market price. That's why not that but current_min_history is used. This way users can't abuse temporary swings in price. If we are in volatile environment when minimum and median prices are way different, it is safer for the system to use lower price (and if they are close it does not matter that we are going to use minimum). Finally there can still be situations when during next 3.5 days price changes to the downside for more than 50% and stays at that level. It can even happen as a flash crash between feed entries (so users can already see price decline but the system cannot). It only matters if the price stays low for prolonged period of time. In such case future official price, when actual conversion happens, will be at such level that HIVE given by the user won't be enough to cover for the HBD they were given. The Hive network foots the bill in that case. It should be a rare occurrence, but might still happen. That's why there is HIVE_COLLATERALIZED_CONVERSION_FEE (5 percent) fee on every conversion. It more than covers potential rare loses.

The procedure is prepared for even more rare case. Normally HIVE to HBD conversions are disabled when HBD debt reaches upper soft limit (which happens to be the same as hard limit (Edit: not at the moment, see discussion with @dalz in comments below), when peg is broken for safety reasons, but could actually be (is) a different, lower value). However it can happen that user starts conversion and only then price declines to the point when official internal price is artificially changed to the upside due to hard limit. User won't benefit from that move though. The conversion uses market_median_history, that reflects actual market value of HIVE as reported by witnesses.

Let's sum up all the steps taken during HIVE to HBD conversion and then see an example:

  • user posts conversion request with X HIVE
  • X is subtracted from user balance and placed in separate object as collateral
  • X is cut in half and multiplied by current_min_history corrected by 5% fee giving Y HBD
  • Y HBD is created out of thin air and immediately given to the user
  • 3.5 days pass and actual conversion is executed
  • Y HBD is multiplied by market_median_history corrected by by 5% fee giving Z HIVE
  • if Z is not more than X, the excess collateral (X - Z) HIVE is given back to the user; Z HIVE is burned
  • if Z is more than X, system_warning_operation vop is generated (it can be observed on account history of initminer); all the X HIVE collateral is burned and the shortfall of (Z - X) HIVE remains in the system as extra inflation

At the moment of writing this article the official internal prices (accessed with database_api.get_feed_history) are:

  • current_min_history - 424 HBD for 1000 HIVE
  • current_max_history - 458 HBD for 1000 HIVE
  • market_median_history/current_median_history - 445 HBD for 1000 HIVE

Let's start conversion with 4000 HIVE as collateral.

  • given amount is cut in half - 2000 HIVE
  • current_min_history is used; 5% fee means we have to pay 5% more HIVE for the same amount of HBD, that is, we multiply:
(2'000.000 HIVE <em> 424.000 HBD </em> 10'000 basis points) / (1'000.000 HIVE * 10'500 basis points) =  
8'480'000'000.000000 HBD / 10'500'000.000 = 
807.619 HBD 
  • we get 807.619 HBD

Scenario 1 - prices stayed the same after 3.5 days:

  • market_median_history is used, we multiply:
(807.619 HBD * 1'000.000 HIVE <em> 10'500 basis points) / (445.000 HBD </em> 10'000 basis points) = 
8'479'999'500.000000 HIVE / 4'450'000.000 = 
1'905.617 HIVE 
  • excess collateral is (4'000.000 - 1'905.617) HIVE = 2'094.383 HIVE - we get that back
  • we ended up effectively converting our HIVE for HBD at around 0.4238 exchange rate (includes fee)

Scenario 2 - price increased to 0.4835:

  • market_median_history with value of 483.500 HBD for 1000 HIVE is used, we multiply:
(807.619 HBD <em> 1'000.000 HIVE </em> 10'500 basis points) / (483.500 HBD * 10'000 basis points) = 
8'479'999'500.000000 HIVE / 4'835'000.000 = 
1'753.877 
  • excess collateral is (4'000.000 - 1'753.877) HIVE = 2'246.123 HIVE - we get that back
  • we ended up effectively converting our HIVE to HBD at around 0.4605 exchange rate (includes fee)

Scenario 3 - price declined to 0.3983:

  • market_median_history with value of 398.300 HBD for 1000 HIVE is used, we multiply:
(807.619 HBD * 1'000.000 HIVE <em> 10'500 basis points) / (398.300 HBD </em> 10'000 basis points) = 
8'479'999'500.000000 HIVE / 3'983'000.000 = 
2'129.048 
  • excess collateral is (4'000.000 - 2'129.048) HIVE = 1'870.952 HIVE - we get that back
  • we ended up effectively converting our HIVE to HBD at around 0.3793 exchange rate (includes fee)

Scenario 4 - price crashed to 0.2021:

  • market_median_history with value of 202.100 HBD for 1000 HIVE is used, we multiply:
(807.619 HBD <em> 1'000.000 HIVE </em> 10'500 basis points) / (202.100 HBD * 10'000 basis points) = 
8'479'999'500.000000 HIVE / 2'021'000.000 = 
4'195.942 
  • shortfall of collateral is (4'195.942 - 4'000.000) HIVE = 195.942 HIVE - we get nothing back, Hive keeps the shortfall amount as extra inflation
  • we ended up effectively converting our HIVE to HBD at around 0.2019 exchange rate (despite shortfall it is still below actual price, just not whole fee was included)

Hopefully now it should be clear how the conversion works. If anyone is interested in technical details it is always best to look into the code: