diff --git a/src/js/ripple/amount.js b/src/js/ripple/amount.js index f3b9f697..1e959c9d 100644 --- a/src/js/ripple/amount.js +++ b/src/js/ripple/amount.js @@ -598,30 +598,48 @@ Amount.prototype.invert = function() { * The regular expression below matches above cases, broken down for better understanding: * * ^\s* // start with any amount of whitespace - * ([a-zA-Z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 + * ([A-z]{3}|[0-9]{3}) // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 * \s* // any amount of whitespace * (-)? // optional dash * (\d+) // 1 or more digits * (?:\.(\d*))? // optional . character with any amount of digits * \s* // any amount of whitespace - * ([a-f0-9]{40}|[a-z0-9]{3})? // optional 40 character hex string OR 3 letters + * ([A-z]{3}|[0-9]{3})? // either 3 letter alphabetic currency-code or 3 digit numeric currency-code. See ISO 4217 * \s* // any amount of whitespace * $ // end of string * */ -Amount.human_RE = /^\s*([a-z]{3}|[0-9]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([a-f0-9]{40}|[a-z0-9]{3})?\s*$/i; +Amount.human_RE_hex = /^\s*(-)?(\d+)(?:\.(\d*))?\s*([a-fA-F0-9]{40})\s*$/; +Amount.human_RE = /^\s*([A-z]{3}|[0-9]{3})?\s*(-)?(\d+)(?:\.(\d*))?\s*([A-z]{3}|[0-9]{3})?\s*$/; Amount.prototype.parse_human = function(j, opts) { opts = opts || {}; - var m = String(j).match(Amount.human_RE); + var integer; + var fraction; + var currency; + var precision = null; - if (m) { - var currency = m[5] || m[1] || 'XRP'; - var integer = m[5] && m[1] ? m[1] + '' + m[3] : (m[3] || '0'); - var fraction = m[4] || ''; - var precision = null; + // first check if it's a hex formatted currency + var matches = String(j).match(Amount.human_RE_hex); + if (matches && matches.length === 5 && matches[4]) { + integer = matches[2]; + fraction = matches[3] || ''; + currency = matches[4]; + this._is_negative = Boolean(matches[1]); + } + if (integer === void(0) && currency === void(0)) { + var m = String(j).match(Amount.human_RE); + if (m) { + currency = m[5] || m[1] || 'XRP'; + integer = m[5] && m[1] ? m[1] + '' + m[3] : (m[3] || '0'); + fraction = m[4] || ''; + this._is_negative = Boolean(m[2]); + } + } + + if (integer) { currency = currency.toUpperCase(); this._value = new BigInteger(integer); @@ -648,8 +666,6 @@ Amount.prototype.parse_human = function(j, opts) { this.canonicalize(); } - this._is_negative = !!m[2]; - // Apply interest/demurrage if (opts.reference_date && this._currency.has_interest()) { var interest = this._currency.get_interest_at(opts.reference_date); @@ -1155,7 +1171,7 @@ Amount.prototype.to_json = function() { } else { var amount_json = { value : this.to_text(), - currency : this._currency.to_json() + currency : this._currency.has_interest() ? this._currency.to_hex() : this._currency.to_json() }; if (this._issuer.is_valid()) { amount_json.issuer = this._issuer.to_json(); diff --git a/test/amount-test.js b/test/amount-test.js index 9d5c040a..94f9db19 100644 --- a/test/amount-test.js +++ b/test/amount-test.js @@ -35,6 +35,30 @@ describe('Amount', function() { it('12345.6789 XAU', function() { assert.strictEqual(Amount.from_human("12345.6789 XAU").to_text_full(), '12345.6789/XAU/NaN'); }); + it('12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() { + assert.strictEqual(Amount.from_human("12345.6789 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_text_full(), '12345.6789/XAU (-0.5%pa)/NaN'); + }); + it('12345.6789 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("12345.6789 0000000000000000000000005553440000000000").to_text_full(), '12345.6789/USD/NaN'); + }); + it('10 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("10 0000000000000000000000005553440000000000").to_text_full(), '10/USD/NaN'); + }); + it('100 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("100 0000000000000000000000005553440000000000").to_text_full(), '100/USD/NaN'); + }); + it('1000 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("1000 0000000000000000000000005553440000000000").to_text_full(), '1000/USD/NaN'); + }); + it('-100 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-100 0000000000000000000000005553440000000000").to_text_full(), '-100/USD/NaN'); + }); + it('-1000 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-1000 0000000000000000000000005553440000000000").to_text_full(), '-1000/USD/NaN'); + }); + it('-1000.001 0000000000000000000000005553440000000000', function() { + assert.strictEqual(Amount.from_human("-1000.001 0000000000000000000000005553440000000000").to_text_full(), '-1000.001/USD/NaN'); + }); it('XAU 12345.6789', function() { assert.strictEqual(Amount.from_human("XAU 12345.6789").to_text_full(), '12345.6789/XAU/NaN'); }); @@ -190,6 +214,23 @@ describe('Amount', function() { assert.strictEqual('0/XRP/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full()); }); }); + describe('Amount to_json', function() { + it('10 USD', function() { + var amount = Amount.from_human("10 USD").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("USD", amount.currency); + }); + it('10 0000000000000000000000005553440000000000', function() { + var amount = Amount.from_human("10 0000000000000000000000005553440000000000").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("USD", amount.currency); + }); + it('10 015841551A748AD2C1F76FF6ECB0CCCD00000000', function() { + var amount = Amount.from_human("10 015841551A748AD2C1F76FF6ECB0CCCD00000000").to_json(); + assert.strictEqual("10", amount.value); + assert.strictEqual("015841551A748AD2C1F76FF6ECB0CCCD00000000", amount.currency); + }); + }); describe('Amount operations', function() { it('Negate native 123', function () { assert.strictEqual('-0.000123/XRP', Amount.from_json('123').negate().to_text_full());