Skip to content

Instantly share code, notes, and snippets.

@justmoon
Last active January 4, 2016 08:49
Show Gist options
  • Save justmoon/8597643 to your computer and use it in GitHub Desktop.
Save justmoon/8597643 to your computer and use it in GitHub Desktop.
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
Copy link

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
Copy link
Author

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
Copy link

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
Copy link

You can do

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

to save a little computing time.

@sublimator
Copy link

Cheers :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment