1
- var extend = require ( 'extend' ) ;
1
+ 'use strict' ;
2
+
3
+ var extend = require ( 'extend' ) ;
2
4
var UInt160 = require ( './uint160' ) . UInt160 ;
3
5
var utils = require ( './utils' ) ;
4
6
var Float = require ( './ieee754' ) . Float ;
@@ -16,8 +18,7 @@ var Currency = extend(function() {
16
18
// 3-letter code: ...
17
19
// XXX Should support hex, C++ doesn't currently allow it.
18
20
19
- this . _value = NaN ;
20
-
21
+ this . _value = NaN ;
21
22
this . _update ( ) ;
22
23
} , UInt160 ) ;
23
24
@@ -32,65 +33,103 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
32
33
* Examples:
33
34
*
34
35
* USD => currency
35
- * USD - Dollar => currency with optional full currency name
36
- * XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate per year
36
+ * USD - Dollar => currency with optional full currency
37
+ * name
38
+ * XAU (-0.5%pa) => XAU with 0.5% effective demurrage rate
39
+ * per year
37
40
* XAU - Gold (-0.5%pa) => Optionally allowed full currency name
38
- * USD (1%pa) => US dollars with 1% effective interest per year
41
+ * USD (1%pa) => US dollars with 1% effective interest
42
+ * per year
39
43
* INR - Indian Rupees => Optional full currency name with spaces
40
- * TYX - 30-Year Treasuries => Optional full currency with numbers and a dash
41
- * TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers, dash and interest rate
44
+ * TYX - 30-Year Treasuries => Optional full currency with numbers
45
+ * and a dash
46
+ * TYX - 30-Year Treasuries (1.5%pa) => Optional full currency with numbers,
47
+ * dash and interest rate
42
48
*
43
- * The regular expression below matches above cases, broken down for better understanding:
49
+ * The regular expression below matches above cases, broken down for better
50
+ * understanding:
44
51
*
45
52
* ^\s* // start with any amount of whitespace
46
- * ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217
47
- * (\s*-\s*[- \w]+) // optional full currency name following the dash after currency code,
48
- * full currency code can contain letters, numbers and dashes
49
- * (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and . notation (-0.5%pa)
53
+ * ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3
54
+ * digit numeric currency-code. See ISO 4217
55
+ * (\s*-\s*[- \w]+) // optional full currency name following the dash
56
+ * after currency code, full currency code can
57
+ * contain letters, numbers and dashes
58
+ * (\s*\(-?\d+\.?\d*%pa\))? // optional demurrage rate, has optional - and
59
+ * . notation (-0.5%pa)
50
60
* \s*$ // end with any amount of whitespace
51
61
*
52
62
*/
53
- Currency . prototype . human_RE = / ^ \s * ( [ a - z A - Z 0 - 9 ] { 3 } ) ( \s * - \s * [ - \w ] + ) ? ( \s * \( - ? \d + \. ? \d * % p a \) ) ? \s * $ / ;
63
+
64
+ /*eslint-disable max-len*/
65
+ Currency . prototype . human_RE = / ^ \s * ( [ a - z A - Z 0 - 9 \< \> \( \) \{ \} \[ \] \| \? \! \@ \# \$ \% \^ \& ] { 3 } ) ( \s * - \s * [ - \w ] + ) ? ( \s * \( - ? \d + \. ? \d * % p a \) ) ? \s * $ / ;
66
+ /*eslint-enable max-len*/
54
67
55
68
Currency . from_json = function ( j , shouldInterpretXrpAsIou ) {
56
69
return ( new Currency ( ) ) . parse_json ( j , shouldInterpretXrpAsIou ) ;
57
70
} ;
58
71
59
72
Currency . from_human = function ( j , opts ) {
60
73
return ( new Currency ( ) . parse_human ( j , opts ) ) ;
61
- }
74
+ } ;
62
75
63
76
// this._value = NaN on error.
64
77
Currency . prototype . parse_json = function ( j , shouldInterpretXrpAsIou ) {
65
78
this . _value = NaN ;
66
79
80
+ if ( j instanceof Currency ) {
81
+ this . _value = j . copyTo ( { } ) . _value ;
82
+ this . _update ( ) ;
83
+ return this ;
84
+ }
85
+
67
86
switch ( typeof j ) {
87
+ case 'number' :
88
+ if ( ! isNaN ( j ) ) {
89
+ this . parse_number ( j ) ;
90
+ }
91
+ break ;
68
92
case 'string' :
69
-
70
- // if an empty string is given, fall back to XRP
71
93
if ( ! j || j === '0' ) {
72
- this . parse_hex ( shouldInterpretXrpAsIou ? Currency . HEX_CURRENCY_BAD : Currency . HEX_ZERO ) ;
94
+ // Empty string or XRP
95
+ this . parse_hex ( shouldInterpretXrpAsIou
96
+ ? Currency . HEX_CURRENCY_BAD
97
+ : Currency . HEX_ZERO ) ;
98
+ break ;
99
+ }
100
+
101
+ if ( j === '1' ) {
102
+ // 'no currency'
103
+ this . parse_hex ( Currency . HEX_ONE ) ;
104
+ break ;
105
+ }
106
+
107
+ if ( / ^ [ A - F 0 - 9 ] { 40 } $ / . test ( j ) ) {
108
+ // Hex format
109
+ this . parse_hex ( j ) ;
73
110
break ;
74
111
}
75
112
76
113
// match the given string to see if it's in an allowed format
77
- var matches = String ( j ) . match ( this . human_RE ) ;
114
+ var matches = j . match ( this . human_RE ) ;
78
115
79
116
if ( matches ) {
80
-
81
117
var currencyCode = matches [ 1 ] ;
82
118
83
119
// for the currency 'XRP' case
84
120
// we drop everything else that could have been provided
85
121
// e.g. 'XRP - Ripple'
86
122
if ( ! currencyCode || / ^ ( 0 | X R P ) $ / . test ( currencyCode ) ) {
87
- this . parse_hex ( shouldInterpretXrpAsIou ? Currency . HEX_CURRENCY_BAD : Currency . HEX_ZERO ) ;
123
+ this . parse_hex ( shouldInterpretXrpAsIou
124
+ ? Currency . HEX_CURRENCY_BAD
125
+ : Currency . HEX_ZERO ) ;
88
126
89
127
// early break, we can't have interest on XRP
90
128
break ;
91
129
}
92
130
93
- // the full currency is matched as it is part of the valid currency format, but not stored
131
+ // the full currency is matched as it is part of the valid currency
132
+ // format, but not stored
94
133
// var full_currency = matches[2] || '';
95
134
var interest = matches [ 3 ] || '' ;
96
135
@@ -117,25 +156,28 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
117
156
currencyData [ 2 ] = currencyCode . charCodeAt ( 1 ) & 0xff ;
118
157
currencyData [ 3 ] = currencyCode . charCodeAt ( 2 ) & 0xff ;
119
158
120
- // byte 5-8 are for reference date, but should always be 0 so we won't fill it
159
+ // byte 5-8 are for reference date, but should always be 0 so we
160
+ // won't fill it
121
161
122
162
// byte 9-16 are for the interest
123
163
percentage = parseFloat ( percentage [ 0 ] ) ;
124
164
125
- // the interest or demurrage is expressed as a yearly (per annum) value
165
+ // the interest or demurrage is expressed as a yearly (per annum)
166
+ // value
126
167
var secondsPerYear = 31536000 ; // 60 * 60 * 24 * 365
127
168
128
169
// Calculating the interest e-fold
129
170
// 0.5% demurrage is expressed 0.995, 0.005 less than 1
130
171
// 0.5% interest is expressed as 1.005, 0.005 more than 1
131
- var interestEfold = secondsPerYear / Math . log ( 1 + percentage / 100 ) ;
172
+ var interestEfold = secondsPerYear / Math . log ( 1 + percentage / 100 ) ;
132
173
var bytes = Float . toIEEE754Double ( interestEfold ) ;
133
174
134
- for ( var i = 0 ; i <= bytes . length ; i ++ ) {
175
+ for ( var i = 0 ; i <= bytes . length ; i ++ ) {
135
176
currencyData [ 8 + i ] = bytes [ i ] & 0xff ;
136
177
}
137
178
138
- // the last 4 bytes are reserved for future use, so we won't fill those
179
+ // the last 4 bytes are reserved for future use, so we won't fill
180
+ // those
139
181
140
182
} else {
141
183
currencyData [ 12 ] = currencyCode . charCodeAt ( 0 ) & 0xff ;
@@ -144,29 +186,13 @@ Currency.prototype.parse_json = function(j, shouldInterpretXrpAsIou) {
144
186
}
145
187
146
188
this . parse_bytes ( currencyData ) ;
147
- } else {
148
- this . parse_hex ( j ) ;
149
- }
150
- break ;
151
-
152
- case 'number' :
153
- if ( ! isNaN ( j ) ) {
154
- this . parse_number ( j ) ;
155
- }
156
- break ;
157
-
158
- case 'object' :
159
- if ( j instanceof Currency ) {
160
- this . _value = j . copyTo ( { } ) . _value ;
161
- this . _update ( ) ;
162
189
}
163
190
break ;
164
191
}
165
192
166
193
return this ;
167
194
} ;
168
195
169
-
170
196
Currency . prototype . parse_human = function ( j ) {
171
197
return this . parse_json ( j ) ;
172
198
} ;
@@ -176,14 +202,15 @@ Currency.prototype.parse_human = function(j) {
176
202
*
177
203
* You should never need to call this.
178
204
*/
205
+
179
206
Currency . prototype . _update = function ( ) {
180
207
var bytes = this . to_bytes ( ) ;
181
208
182
209
// is it 0 everywhere except 12, 13, 14?
183
210
var isZeroExceptInStandardPositions = true ;
184
211
185
212
if ( ! bytes ) {
186
- return 'XRP' ;
213
+ return ;
187
214
}
188
215
189
216
this . _native = false ;
@@ -192,16 +219,17 @@ Currency.prototype._update = function() {
192
219
this . _interest_period = NaN ;
193
220
this . _iso_code = '' ;
194
221
195
- for ( var i = 0 ; i < 20 ; i ++ ) {
196
- isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && ( i === 12 || i === 13 || i === 14 || bytes [ i ] === 0 ) ;
222
+ for ( var i = 0 ; i < 20 ; i ++ ) {
223
+ isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
224
+ && ( i === 12 || i === 13 || i === 14 || bytes [ i ] === 0 ) ;
197
225
}
198
226
199
227
if ( isZeroExceptInStandardPositions ) {
200
228
this . _iso_code = String . fromCharCode ( bytes [ 12 ] )
201
229
+ String . fromCharCode ( bytes [ 13 ] )
202
230
+ String . fromCharCode ( bytes [ 14 ] ) ;
203
231
204
- if ( this . _iso_code === '\0\0\0 ' ) {
232
+ if ( this . _iso_code === '\u0000\u0000\u0000 ' ) {
205
233
this . _native = true ;
206
234
this . _iso_code = 'XRP' ;
207
235
}
@@ -215,8 +243,8 @@ Currency.prototype._update = function() {
215
243
this . _type = 1 ;
216
244
this . _interest_start = ( bytes [ 4 ] << 24 ) +
217
245
( bytes [ 5 ] << 16 ) +
218
- ( bytes [ 6 ] << 8 ) +
219
- ( bytes [ 7 ] ) ;
246
+ ( bytes [ 6 ] << 8 ) +
247
+ ( bytes [ 7 ] ) ;
220
248
this . _interest_period = Float . fromIEEE754Double ( bytes . slice ( 8 , 16 ) ) ;
221
249
}
222
250
} ;
@@ -230,7 +258,8 @@ Currency.prototype.parse_bytes = function(byte_array) {
230
258
var isZeroExceptInStandardPositions = true;
231
259
232
260
for (var i=0; i<20; i++) {
233
- isZeroExceptInStandardPositions = isZeroExceptInStandardPositions && (i===12 || i===13 || i===14 || byte_array[0]===0)
261
+ isZeroExceptInStandardPositions = isZeroExceptInStandardPositions
262
+ && (i===12 || i===13 || i===14 || byte_array[0]===0)
234
263
}
235
264
236
265
if (isZeroExceptInStandardPositions) {
@@ -260,20 +289,25 @@ Currency.prototype.is_native = function() {
260
289
} ;
261
290
262
291
/**
263
- * Whether this currency is an interest-bearing/demurring currency.
292
+ * @return { Boolean } whether this currency is an interest-bearing currency
264
293
*/
294
+
265
295
Currency . prototype . has_interest = function ( ) {
266
- return this . _type === 1 && ! isNaN ( this . _interest_start ) && ! isNaN ( this . _interest_period ) ;
296
+ return this . _type === 1
297
+ && ! isNaN ( this . _interest_start )
298
+ && ! isNaN ( this . _interest_period ) ;
267
299
} ;
268
300
269
301
/**
270
302
*
271
- * @param referenceDate - number of seconds since the Ripple Epoch (0:00 on January 1, 2000 UTC)
272
- * used to calculate the interest over provided interval
273
- * pass in one years worth of seconds to ge the yearly interest
274
- * @returns {number } - interest for provided interval, can be negative for demurred currencies
303
+ * @param {number } referenceDate number of seconds since the Ripple Epoch
304
+ * (0:00 on January 1, 2000 UTC) used to calculate the
305
+ * interest over provided interval pass in one years
306
+ * worth of seconds to ge the yearly interest
307
+ * @returns {number } interest for provided interval, can be negative for
308
+ * demurred currencies
275
309
*/
276
- Currency . prototype . get_interest_at = function ( referenceDate , decimals ) {
310
+ Currency . prototype . get_interest_at = function ( referenceDate ) {
277
311
if ( ! this . has_interest ( ) ) {
278
312
return 0 ;
279
313
}
@@ -288,57 +322,66 @@ Currency.prototype.get_interest_at = function(referenceDate, decimals) {
288
322
}
289
323
290
324
// calculate interest by e-fold number
291
- return Math . exp ( ( referenceDate - this . _interest_start ) / this . _interest_period ) ;
325
+ return Math . exp ( ( referenceDate - this . _interest_start )
326
+ / this . _interest_period ) ;
292
327
} ;
293
328
294
- Currency . prototype . get_interest_percentage_at = function ( referenceDate , decimals ) {
329
+ Currency . prototype . get_interest_percentage_at
330
+ = function ( referenceDate , decimals ) {
295
331
var interest = this . get_interest_at ( referenceDate , decimals ) ;
296
332
297
333
// convert to percentage
298
- var interest = ( interest * 100 ) - 100 ;
299
- var decimalMultiplier = decimals ? Math . pow ( 10 , decimals ) : 100 ;
334
+ interest = ( interest * 100 ) - 100 ;
335
+ var decimalMultiplier = decimals ? Math . pow ( 10 , decimals ) : 100 ;
300
336
301
337
// round to two decimals behind the dot
302
- return Math . round ( interest * decimalMultiplier ) / decimalMultiplier ;
338
+ return Math . round ( interest * decimalMultiplier ) / decimalMultiplier ;
303
339
} ;
304
340
305
341
// XXX Currently we inherit UInt.prototype.is_valid, which is mostly fine.
306
342
//
307
343
// We could be doing further checks into the internal format of the
308
344
// currency data, since there are some values that are invalid.
309
345
//
310
- //Currency.prototype.is_valid = function() {
346
+ // Currency.prototype.is_valid = function() {
311
347
// return UInt.prototype.is_valid() && ...;
312
- //};
348
+ // };
313
349
314
350
Currency . prototype . to_json = function ( opts ) {
315
351
if ( ! this . is_valid ( ) ) {
316
352
// XXX This is backwards compatible behavior, but probably not very good.
317
353
return 'XRP' ;
318
354
}
319
355
320
- var opts = opts || { } ;
356
+ if ( ! opts ) {
357
+ opts = { } ;
358
+ }
321
359
322
360
var currency ;
323
361
var fullName = opts && opts . full_name ? ' - ' + opts . full_name : '' ;
324
- opts . show_interest = opts . show_interest !== void ( 0 ) ? opts . show_interest : this . has_interest ( ) ;
362
+ opts . show_interest = opts . show_interest !== undefined
363
+ ? opts . show_interest
364
+ : this . has_interest ( ) ;
325
365
326
366
if ( ! opts . force_hex && / ^ [ A - Z 0 - 9 ] { 3 } $ / . test ( this . _iso_code ) ) {
327
367
currency = this . _iso_code + fullName ;
328
368
if ( opts . show_interest ) {
329
- var decimals = ! isNaN ( opts . decimals ) ? opts . decimals : void ( 0 ) ;
330
- var interestPercentage = this . has_interest ( ) ? this . get_interest_percentage_at ( this . _interest_start + 3600 * 24 * 365 , decimals ) : 0 ;
369
+ var decimals = ! isNaN ( opts . decimals ) ? opts . decimals : undefined ;
370
+ var interestPercentage = this . has_interest ( )
371
+ ? this . get_interest_percentage_at (
372
+ this . _interest_start + 3600 * 24 * 365 , decimals
373
+ )
374
+ : 0 ;
331
375
currency += ' (' + interestPercentage + '%pa)' ;
332
376
}
333
377
334
378
} else {
335
-
336
379
// Fallback to returning the raw currency hex
337
380
currency = this . to_hex ( ) ;
338
381
339
- // XXX This is to maintain backwards compatibility, but it is very, very odd
340
- // behavior, so we should deprecate it and get rid of it as soon as
341
- // possible.
382
+ // XXX This is to maintain backwards compatibility, but it is very, very
383
+ // odd behavior, so we should deprecate it and get rid of it as soon as
384
+ // possible.
342
385
if ( currency === Currency . HEX_ONE ) {
343
386
currency = 1 ;
344
387
}
@@ -357,5 +400,3 @@ Currency.prototype.get_iso = function() {
357
400
} ;
358
401
359
402
exports . Currency = Currency ;
360
-
361
- // vim:sw=2:sts=2:ts=8:et
0 commit comments