Skip to content

Instantly share code, notes, and snippets.

@justmoon justmoon/gist:8597643
Last active Jan 4, 2016

Embed
What would you like to do?
Demurrage currency code
Currently, we're using this currency code format (from ripple.com/wiki/Currency_format):
00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __
ZERO------------------------------- CURCODE- VER-- RESERVED
Let's define the first byte as the type byte.
Type 0x00 means the normal format:
00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ __ __ __ __
ZERO---------------------------- CURCODE- VER-- RESERVED
Types 0x80 - 0xFF are reserved for hashes - i.e. if the first bit is one, the remaining 159 bits are a hash.
Type 0x01 means demurraging currency:
01 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __
CURCODE- DATE------- RATE------------------- RESERVED---
CURCODE - Three character uppercase ASCII
DATE - DEPRECATED Demurrage start date (Ripple epoch; seconds since 2000)
`-> There is no reason to choose one reference date over another so this feature will be removed.
For now just make sure you ALWAYS set the date to 00 00 00 00
RATE - Demurrage rate, defined as e-folding time in seconds (IEEE 754 double-precision floating-point)
RESERVED - Reserved for future use, duh
Note: Date and rate are four-byte aligned, rate is eight-byte aligned, for easy parsing on 32/64 bit CPUs.
Demurrage example:
01 58 41 55 00 00 00 00 C1 F7 6F F6 EC B0 BA C6 00 00 00 00
// Calculating the demurrage rate
//
// We want 0.5% per year. There are 31536000 in a year, so the e-folding time in seconds is:
31536000 / ln(0.995) = -6291418827.045599
// In plain English: The nominal amount of this asset will decrease (hence the minus sign) e times (≈2.71828) every 6291418827.045599 seconds
// As hex (IEEE double):
http://gregstoll.dyndns.org/~gregstoll/floattohex/
0xc1f76ff6ecb0bac6
// Final currency code
0158415500000000C1F76FF6ECB0BAC600000000
// Example TrustSet
{"Flags":131072,"TransactionType":"TrustSet","Account":"rNb721TdNHN37yoURrMYDiQFmvXmENCZW6","LimitAmount":{"value":"1000","currency":"0158415500000000C1F76FF6ECB0BAC600000000","issuer":"rUyPiNcSFFj6uMR2gEaD8jUerQ59G1qvwN"}}
@jatchili

This comment has been minimized.

Copy link

jatchili commented Jan 24, 2014

Maybe it'd make sense to express the rate as something like "e-folding time in seconds"? That would concentrate the precision more where it's needed, in the range very close to 1. Also, it's easy for a computer to calculate the demurrage factor as e^( time / T ), where T is the e-folding time. See also: https://en.wikipedia.org/wiki/Compound_interest#Continuous_compounding

@justmoon

This comment has been minimized.

Copy link
Owner Author

justmoon commented Jan 24, 2014

Great idea, the e-folding time for an annual rate of 0.5% is -6291418827.05, so if we plug that in:

e ^ (31536000 / -6291418827.05) = 0.995

Much better precision compared the previous approach (per-second interest/demurrage):

0.99999999984 ^ 31536000 = 0.99496694802

I'll update the doc.

@sublimator

This comment has been minimized.

Copy link

sublimator commented Jan 25, 2014

static public BigDecimal applyRate(BigDecimal amount, BigDecimal rate, TimeUnit time, long units) {
    BigDecimal appliedRate = getSeconds(time, units).divide(rate, MathContext.DECIMAL64);
    BigDecimal factor = BigDecimal.valueOf(Math.pow(Math.E, appliedRate.doubleValue()));
    return amount.multiply(factor, MathContext.DECIMAL64);
}

Overuse of BigDecimal aside, is that how you can apply a rate, to calculate the reduction?

eg. https://gist.github.com/sublimator/0e97703c8d8ae78d6079

@jatchili

This comment has been minimized.

Copy link

jatchili commented Jan 28, 2014

You can do

BigDecimal factor = BigDecimal.valueOf(Math.exp(appliedRate.doubleValue()));

to save a little computing time.

@sublimator

This comment has been minimized.

Copy link

sublimator commented Jan 30, 2014

Cheers :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.