Analysis of Bancor Equations Supporting REX

Introduction

In this document, we describe the Bancor equations supporting REX and the reasoning behind setting the REX initial state and any possible constraints on the system. We first present the relevant REX pool balances. These balances are represented both by their C++ smart contract variable names and by the mathematical variables used in the presented equations. If not shown explicitly, the unit of all balances, paid fees and staked resources is the blockchain core token SYS. The balances are

  • total_unlent represents the SYS balance that is available for renting. In
    the following we use u to represent this balance, i.e., u = total_unlent.
  • total_lent represents the total rented SYS balance. At any point in time, total_lent is the sum of tokens staked in all currently open loans. In the following we use l = total_lent.
  • total_rent is a virtual balance. The initial value of this balance must be strictly positive as discussed below. The balances total_rent and total_unlent are the two connectors of the Bancor algorithm which determines CPU and Network renting prices. In the following we use f = total_rent.

For a detailed description of the REX smart contract, see Ref [1].

REX Loan Calculations

Upon renting CPU or Network resources, the amount staked to those resources for 30 days is calculated as a function of the loan fee, ∆f, and the REX pool balances u = total_unlent and f = total_rent, using Bancor equation. For a given loan with id i, the equation is

For example, if at a given point in time, u = 5×10⁷, and f = 3×10⁴, a loan fee ∆f⁽ⁱ⁾ = 1 results in renting ∆u⁽ⁱ⁾ = 1666.6111 SYS worth of resources. That is, the renting cost rate for this loan is ∆f⁽ⁱ⁾/∆u⁽ⁱ⁾ ≈ 0.06%. In general, the REX pool balances are large compared to the fee of a given loan, then the renting cost rate can be estimated as

When the loan described above is created, the REX pool balances are updated as follows: uu − ∆u⁽ⁱ⁾, l l + ∆u⁽ⁱ⁾, f f + ∆f⁽ⁱ⁾. In other words, the staked amount ∆u⁽ⁱ⁾ is moved from u to l, i.e., from total_unlent to total_lent. In addition, the paid fee is added to total_unlent. The overall set of updates is

Note that f is a virtual balance and there is no double spending by adding ∆f⁽ⁱ⁾ to both u and f.

Initializing REX Pool

Initially, the REX pool is empty (u = l = 0). As lenders buy REX (lend SYS tokens), u increases. On the other hand, the balance f is virtual and needs to be initialized to some value f₀. It is important to note that f₀ must not be zero; otherwise, the first loan will deplete the entire u balance no matter how small the paid fee is. This can be easily verified by setting f = 0 in Eq 1 which results in ∆u = u for any ∆f > 0. Seeing that we must have f₀ > 0, the next step is to decide a practical value of f₀. The REX pool balance u is expected to reach tens of millions of SYS tokens rather quickly . We will use the estimate u₀ = 2 × 10⁷ as a reference value. A small f₀ causes a problem similar to the one caused by f₀ = 0. For example, if f₀ = 100, a payment ∆f = 100 gives a rented stake of ∆u = 1 × 10⁷, which is half of the entire pool. The same can be repeated and most of the pool can be rented using only a small sum of fee payments. Following the first few loans, renting cost increases rapidly and becomes too high.

On the other hand, setting f₀ to a large value would lead to a prohibitively high renting cost. By setting a target initial renting cost rate r₀ ≈ 0.1%, and using the u₀ reference balance, Eq 2 gives f₀ = 2 × 10⁴, which is the initial value we choose for total_rent.

Loan Expiration

When loan i expires, the corresponding rented resources, ∆u⁽ⁱ⁾, are released,
i.e., moved from total_lent back to total_unlent. The balance f is updated
by subtracting the output of the inverse equation

where ∆u⁽ⁱ⁾ was calculated using Eq 1, and u′ and f′ are the values at loan expiration. Since these values are in general different from the values at loan creation, f′f and u′u, we have ∆f′⁽ⁱ⁾ ≠ ∆f⁽ⁱ⁾. That is, the output of Eq 3 is different from the fee paid at loan creation. To summarize, the updates are

Looking at Eq 3, we notice that if, at the time of expiration, total_unlent happens to be zero (u′ = 0), the equation gives ∆f′⁽ⁱ⁾ = f′. And following the update given by Eq 4, we get f′ = 0 after the loan expires. As described above, this leaves the market in an unstable state. One scenario that can lead to this state is as follows: while there is at least one outstanding loan, one or more REX owners may sell enough REX to cause total_unlent to drop to u′ = 0. Following that, one or more loans can expire resulting in f′ = 0. In order to prevent the system from reaching that state, we impose a dynamic lower bound on u which we describe in the following section.

Unlent Balance Lower Bound

Let ulb be the dynamic lower bound of u, which means that at any point in time we have uulb. We must define ulb such that ulb > 0 as long as there are outstanding loans, and ulb = 0 when all loans have expired. The second condition allows REX owners to sell all their REX. Setting ulb to be a fraction of l, i.e., ulb = α×l, where 0 <α< 1, satisfies both requirements. In addition, we want a reasonably low ulb so that it does not routinely cause selling orders to be queued and renting actions to fail. We set α = 0.2, i.e., ulb = 0.2 × l.

Note that we chose to calculate ulb as a function of l instead of f for two
reasons. First, u is expected to be of a different order of magnitude than f
which makes the comparison impractical, and second, the value of f cannot
be used to determine whether there are outstanding loans.

Adjusting REX Pool Virtual Balance

We provide a backup solution that can be invoked in case REX initial condition is out of balance. This can happen, for example, if after a period of time, total_unlent remains well below the reference value of u₀ = 2×10⁷ described above. It means that the initial renting cost rate is well above target value r₀ ≈ 0.1%, or the target rate determined by similar resource renting markets. The action setrex allows producers to set the balance f to a predetermined value calculated using Eq 2 as f₀r₀ × u, where u is the current value of total_unlent and r₀ is the target renting cost rate.

Derivation of the Equations

Bancor protocol [2] allows for instant liquidity by connecting a currency reserve to a smart token. It defines the fractional reserve ratio as

where R is the current value of the currency reserve, S is the smart token current supply, and P is the current token price relative to the reserve currency. The protocol posits that F is always constant and is set to a predetermined value which dictates the price behavior as a function of supply.

One of the results of the protocol is an equation that determines the amount to be paid in return for a given number of tokens:

where R₀ is the initial reserve value, S₀ is the initial smart token supply, and ∆S is the number of issued tokens.

The inverse equation,

determines the number of smart tokens issued in return for a given payment. After the tokens are issued, the supply is updated to S = S₀ + ∆S and the reserve to R = R₀ + ∆R.

Now consider a smart token that is connected to two reserves R⁽¹⁾and R⁽²⁾, and assume that the fractional reserve ratio of the smart token is the same for both reserves. A payment ∆R⁽¹⁾ results in ∆S issued tokens given by Eq 6 applied to R⁽¹⁾:

If these tokens are then sold (equivalent to adding −∆S to the smart token supply) in exchange for the second reserve currency, we obtain

Replacing Eq 7 in Eq 8 results in

Note that ∆R⁽²⁾ and ∆R⁽¹⁾ have opposite signs. In REX equations shown above, the two reserves are f R⁽¹⁾ and uR⁽²⁾.

References

[1] REX Implementation. https://github.com/EOSIO/eosio.contracts/issues/117

[2] Eyal Hertzog, Guy Benartzi, and Galia Benartzi. Bancor Protocol White Paper.

All product and company names are trademarks or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.


Disclaimer: Block.one makes its contribution on a voluntary basis as a member of the EOSIO community and is not responsible for ensuring the overall performance of the software or any related applications. We make no representation, warranty, guarantee or undertaking in respect of the releases described here, the related GitHub release, the EOSIO software or any related documentation, whether expressed or implied, including but not limited to the warranties or merchantability, fitness for a particular purpose and noninfringement. In no event shall we be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or documentation or the use or other dealings in the software or documentation. Any test results or performance figures are indicative and will not reflect performance under all conditions. Any reference to any third party or third-party product, resource or service is not an endorsement or recommendation by Block.one. We are not responsible, and disclaim any and all responsibility and liability, for your use of or reliance on any of these resources. Third-party resources may be updated, changed or terminated at any time, so the information here may be out of date or inaccurate.