mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-11-19 19:25:51 +00:00
[DOC] demurrage (not an actual doc page yet
This commit is contained in:
241
content/demurrage.md
Normal file
241
content/demurrage.md
Normal file
@@ -0,0 +1,241 @@
|
||||
Demurrage in Ripple Currencies
|
||||
==============================
|
||||
|
||||
[Demurrage](http://en.wikipedia.org/wiki/Demurrage_%28currency%29) is a
|
||||
negative interest rate on assets held that represents the cost of
|
||||
holding those assets. Ripple supports currencies that have interest or
|
||||
demurrage rates built into the currency definition, such as
|
||||
"XAU (-0.5%pa)". Each currency-rate combination is treated as a completely
|
||||
distinct currency for purposes of pathfinding and order books.
|
||||
|
||||
A gateway that wants to charge demurrage for holding assets (such as
|
||||
gold) can issue a custom currency representing that asset with the
|
||||
demurrage rate built-in. This is reflected in a different hex
|
||||
representation for the demurraging currency. Client applications should
|
||||
represent a demurraging currency by displaying the negative annual
|
||||
percentage rate along with the currency code.
|
||||
|
||||
XRP cannot have demurrage or interest.
|
||||
|
||||
Dealing with Demurraging Currencies
|
||||
-----------------------------------
|
||||
|
||||
The rippled server, and consequently the official global ledger, do not
|
||||
track changes in value due to demurrage in the balance of funds. This
|
||||
allows demurrage costs to be applied continuously, instead of operating
|
||||
on fixed intervals. It also prevents demurrage from inflicting
|
||||
significant additional computational and storage load for servers that
|
||||
are part of the network. Instead, the fact that particular holdings are
|
||||
subject to demurrage is tracked in the ledger by virtue of the custom
|
||||
currency codes. Demurrage is calculated on the entire currency as if it
|
||||
were interest, according to the following formula:
|
||||
|
||||
D = A \* ( e \^ (t/ τ) )
|
||||
|
||||
where:
|
||||
|
||||
- D is the amount after demurrage
|
||||
- A is the pre-demurrage amount as recorded in the global ledger
|
||||
- e is Euler's number
|
||||
- t is the number of seconds since the [Ripple
|
||||
Epoch](rippled-apis.html#specifying-time) (0:00 on January 1, 2000
|
||||
UTC)
|
||||
- τ is the [e-folding time](http://en.wikipedia.org/wiki/E-folding) in
|
||||
seconds. This value is calculated from the desired interest rate.
|
||||
|
||||
You can think of demurrage in the Ripple Network as similar to
|
||||
inflation, where the value of all assets affected by it decreases over
|
||||
time, but the ledger always holds amounts in year-2000 values. (This
|
||||
representation was chosen as a simplification of the more complicated
|
||||
representation where individual holdings could track when the demurrage
|
||||
on them started accruing, because this way it becomes easier to
|
||||
recognize, exchange, and represent assets with demurrage applied.) Keep
|
||||
in mind, this does not reflect actual, real-world inflation: instead,
|
||||
it's hypothetical inflation at a constant rate.
|
||||
|
||||
### Calculating e-folding time
|
||||
|
||||
It is simple to calculate from a targeted demurrage rate in annual
|
||||
percent to get a τ value to use in calculating demurrage:
|
||||
|
||||
1. First, subtract the demurrage percentage rate from 100% to get the
|
||||
percentage of initial amount that remains after annual demurrage.
|
||||
Represent it as a decimal. For example, for 0.5% annual interest,
|
||||
you would get 0.995
|
||||
2. Now, take the natural log of that number. For example, ln(0.995).
|
||||
For traditional demurrage (decrease in value over time), this value
|
||||
will be negative.
|
||||
3. Finally, take the number of seconds in one year (31536000) and
|
||||
divide by the result of the natural log operation. The result is
|
||||
your e-folding time in seconds, for example -6291418827.045599
|
||||
|
||||
If you're curious: Since an e-folding amount represents how long until
|
||||
an investment increases e times, a negative interest rate means that the
|
||||
investment would have been worth e times its value that amount of time
|
||||
in the past. Alternatively, it means that after that amount of seconds,
|
||||
the investment will be worth 1/e of what it used to be.
|
||||
|
||||
### Canonical Calculations
|
||||
|
||||
For purposes of calculating demurrage consistently across applications,
|
||||
the precision used is important. Our canonical source of demurrage
|
||||
calculations is ripple-lib. By following these specifications, you
|
||||
should be able to reproduce the demurrage results from ripple-lib
|
||||
exactly:
|
||||
|
||||
First, recall the canonical formula for demurrage:
|
||||
|
||||
D = A \* ( e \^ (t/ τ) )
|
||||
|
||||
where D is the post-demurrage amount, and A is the pre-demurrage amount.
|
||||
For the remainder of the formula, e \^ (t/ τ), we call this the
|
||||
"demurrage coefficient". The demurrage coefficient is always relative to
|
||||
a specific time, such that demurrage is calculated for the period
|
||||
starting at the beginning of the Ripple Epoch (00:00:00 January 1, 2000)
|
||||
|
||||
The two directional calculations can therefore be simplified to:
|
||||
|
||||
1. Find the demurrage coefficient for the reference time
|
||||
2. Apply it to the amount to convert
|
||||
1. To convert ledger values to display values, multiply by the
|
||||
demurrage coefficient
|
||||
2. To convert display values to ledger values, divide by the
|
||||
demurrage coefficient
|
||||
|
||||
3. Make sure that the converted value can be represented to the desired
|
||||
accuracy. For example, ledger values submitted to Ripple must fit in
|
||||
Ripple's [internal format](https://wiki.ripple.com/Currency_format).
|
||||
|
||||
For more information on the necessary precision:
|
||||
|
||||
The demurrage coefficient should be calculated entirely in [64-bit
|
||||
IEEE754
|
||||
doubles](http://en.wikipedia.org/wiki/Double-precision_floating-point_format),
|
||||
such as the number types native to Javascript, or the float type
|
||||
available in Python. However, there are some additional notes:
|
||||
|
||||
- For purposes of demurrage, one year is defined as exactly 31536000
|
||||
seconds. This is exactly 365 days, with no adjustments for leap days
|
||||
or leap seconds.
|
||||
- The reference time should be specified in seconds, as an integer. If
|
||||
your clock provides a higher resolution, you should truncate the
|
||||
reference time to seconds before using it.
|
||||
|
||||
Client Applications
|
||||
-------------------
|
||||
|
||||
In order to accurately convey amounts in present-day terms, client
|
||||
applications must adjust for demurrage. This means a few things:
|
||||
|
||||
- When representing the value of a demurraging currency, the display
|
||||
value should be adjusted to the "post-demurrage" values. (This
|
||||
generally means that display values will be lower than the ledger
|
||||
values.)
|
||||
- When making offers or transactions in a demurraging currency,
|
||||
amounts entered by the user should be adjusted upward, to interpret
|
||||
user input as post-demurrage numbers. (This generally means that
|
||||
amounts written into offers are higher than the user input value)
|
||||
|
||||
Client applications must also make sure to distinguish between
|
||||
currencies with differing amounts of demurrage, and to display the
|
||||
correct demurrage rates for all currencies with such rates. Currently,
|
||||
the only Ripple Labs-created client that supports demurrage is Ripple
|
||||
Trade.
|
||||
|
||||
### ripple-lib support
|
||||
|
||||
Clients that are built from
|
||||
[ripple-lib](https://github.com/ripple/ripple-lib) can pass a
|
||||
`reference_date` as an option to the Amount.from\_human function to
|
||||
account for demurrage. This function can automatically convert a
|
||||
human-input number to the necessary amount to hold on the ledger to
|
||||
represent that value in at a given time. (The amount that is sent to the
|
||||
rippled server is the hypothetical amount one would have needed in order
|
||||
to have the desired amount after enduring constant demurrage since the
|
||||
Ripple Epoch.)
|
||||
|
||||
For example, if you're using javascript, you can use ripple-lib utility
|
||||
to calculate this manually:
|
||||
|
||||
```
|
||||
// create an Amount object for an amount of the demurring currency, in this case 10
|
||||
// pass in a reference_date that represents today,
|
||||
// which will calculate how much you will need to represent the requested amount for today
|
||||
var demAmount = Amount.from_human('10 0158415500000000C1F76FF6ECB0BAC600000000', {reference_date:459990264});
|
||||
|
||||
// set the issuer -- optional
|
||||
demAmount.set_issuer("rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
|
||||
|
||||
// get the json format that can be used as TakerPays or TakerGets in the order creation
|
||||
console.log(demAmount.to_json());
|
||||
|
||||
// this will output an Amount with ~10.75 as the value for XAU, which is what is needed to create an
|
||||
// effective order today for 10 XAU
|
||||
```
|
||||
|
||||
|
||||
To calculate how much a given amount has demurred up to today:
|
||||
|
||||
```
|
||||
// create a new Amount object
|
||||
var demAmount = Amount.from_json('10/015841551A748AD2C1F76FF6ECB0CCCD00000000/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
|
||||
|
||||
// apply interest
|
||||
demAmount = demAmount.applyInterest(new Date());
|
||||
|
||||
// get the current amount:
|
||||
console.log(demAmount.to_json());
|
||||
|
||||
Where Does Demurrage Go?
|
||||
------------------------
|
||||
|
||||
To put it simply, the value that depreciates due to demurrage becomes
|
||||
the property of the gateway issuing the currency. This means that, when
|
||||
someone holding a balance of currency goes to redeem that currency from
|
||||
the Gateway, the amount they get is the post-demurrage amount (the
|
||||
"display amount") relative to the current moment in time.
|
||||
|
||||
Note that, when the Gateway issues currency with demurrage, it must also
|
||||
adjust the values it issues, so that the amount sent to the rippled
|
||||
server and written in the ledger is already adjusted for demurrage up to
|
||||
the point in time it was issued.
|
||||
|
||||
Demurrage and Money-Making Offers
|
||||
---------------------------------
|
||||
|
||||
Demurrage ensures that particular currencies "drift" in value slowly
|
||||
over time, so that the same amount on the ledger is worth increasingly
|
||||
less over time when redeemed. (A balance will never go negative, but it
|
||||
will get closer and closer to zero value.) However, offers are not
|
||||
automatically updated to compensate for demurrage that accumulated in
|
||||
the time since the offer was made. This means that, if you are making an
|
||||
offer to buy a demurraging currency, you must occasionally adjust your
|
||||
offer to ask for higher ledger amounts to get the same post-demurrage
|
||||
actual value. However, we expect this to be a complete non-issue because
|
||||
the relative value of currencies (especially pseudo-currency commodities
|
||||
such as precious metals) fluctuates much faster than typical rates of
|
||||
demurrage.
|
||||
|
||||
Since Ripple client applications already adjust for demurrage when
|
||||
taking human inputs to make an offer, most users will not have to do
|
||||
anything different when making offers.
|
||||
|
||||
Currency Format Details
|
||||
-----------------------
|
||||
|
||||
Currency with demurrage or interest is represented as a 160-bit value
|
||||
that begins with the value `0x01`. This sets it apart from hashes (which
|
||||
are always `0x80` or higher) as well as standard currency (`0x00`) and
|
||||
other currency types we may define in the future (`0x02-0x7F`).
|
||||
Demurraging currency has the following format:
|
||||
|
||||
01 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
|
||||
CURCODE- DATE------- RATE------------------- RESERVED---
|
||||
|
||||
- CURCODE is the 3-byte currency code, such as "USD"
|
||||
- DATE is no longer used, and should always be 0.
|
||||
- RATE is the e-folding time, formatted as an IEEE Double, represented
|
||||
in hex. For example, -6291418827.045599 becomes "C1F76FF6ECB0BAC6".
|
||||
- RESERVED is reserved for future use. It should always be given as 0,
|
||||
but other values should be accepted for forward-compatibility.
|
||||
|
||||
Reference in New Issue
Block a user