Skip to content

Commit f05941f

Browse files
committedNov 6, 2014
[FIX] cap IOU Amounts to their max and min value
respect rippled's limits
1 parent 76cfb69 commit f05941f

File tree

2 files changed

+118
-6
lines changed

2 files changed

+118
-6
lines changed
 

‎src/js/ripple/amount.js

+42-6
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ var consts = {
5454

5555
// Maximum possible amount for non-XRP currencies using the maximum mantissa
5656
// with maximum exponent. Corresponds to hex 0xEC6386F26FC0FFFF.
57-
max_value: '9999999999999999e80'
57+
max_value: '9999999999999999e80',
58+
// Minimum possible amount for non-XRP currencies.
59+
min_value: '-1000000000000000e-96'
5860
};
5961

6062
// Add constants to Amount class
@@ -424,6 +426,33 @@ Amount.prototype.invert = function() {
424426
return this.copy()._invert();
425427
};
426428

429+
/**
430+
* Canonicalize amount value
431+
*
432+
* Mirrors rippled's internal Amount representation
433+
* From https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol/STAmount.h#L31-L40
434+
*
435+
* Internal form:
436+
* 1: If amount is zero, then value is zero and offset is -100
437+
* 2: Otherwise:
438+
* legal offset range is -96 to +80 inclusive
439+
* value range is 10^15 to (10^16 - 1) inclusive
440+
* amount = value * [10 ^ offset]
441+
*
442+
* -------------------
443+
*
444+
* The amount can be epxresses as A x 10^B
445+
* Where:
446+
* - A must be an integer between 10^15 and (10^16)-1 inclusive
447+
* - B must be between -96 and 80 inclusive
448+
*
449+
* This results
450+
* - minumum: 10^15 x 10^-96 -> 10^-81 -> -1e-81
451+
* - maximum: (10^16)-1 x 10^80 -> 9999999999999999e80
452+
*
453+
* @returns {Amount}
454+
* @throws {Error} if offset exceeds legal ranges, meaning the amount value is bigger than supported
455+
*/
427456
Amount.prototype.canonicalize = function() {
428457
if (!(this._value instanceof BigInteger)) {
429458
// NaN.
@@ -447,9 +476,8 @@ Amount.prototype.canonicalize = function() {
447476
}
448477
}
449478

450-
// XXX Make sure not bigger than supported. Throw if so.
451479
} else if (this.is_zero()) {
452-
this._offset = -100;
480+
this._offset = Amount.cMinOffset;
453481
this._is_negative = false;
454482
} else {
455483
// Normalize mantissa to valid range.
@@ -465,6 +493,16 @@ Amount.prototype.canonicalize = function() {
465493
}
466494
}
467495

496+
// Make sure not bigger than supported. Throw if so.
497+
if (this.is_negative() && this._offset < Amount.cMinOffset) {
498+
throw new Error('Exceeding min value of ' + Amount.min_value);
499+
}
500+
501+
// Make sure not smaller than supported. Throw if so.
502+
if (!this.is_negative() && this._offset > Amount.cMaxOffset) {
503+
throw new Error('Exceeding max value of ' + Amount.max_value);
504+
}
505+
468506
return this;
469507
};
470508

@@ -539,9 +577,7 @@ Amount.prototype.equals = function(d, ignore_issuer) {
539577
return this.equals(Amount.from_json(d));
540578
}
541579

542-
var result = true;
543-
544-
result = !((!this.is_valid() || !d.is_valid())
580+
var result = !((!this.is_valid() || !d.is_valid())
545581
|| (this._is_native !== d._is_native)
546582
|| (!this._value.equals(d._value) || this._offset !== d._offset)
547583
|| (this._is_negative !== d._is_negative)

‎test/amount-test.js

+76
Original file line numberDiff line numberDiff line change
@@ -1162,4 +1162,80 @@ describe('Amount', function() {
11621162
assert.strictEqual(demAmount.to_human_full(), '10.75853086191915/XAU (-0.5%pa)/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
11631163
});
11641164
});
1165+
1166+
describe('amount limits', function() {
1167+
it ('max JSON wire limite', function() {
1168+
assert.strictEqual(Amount.bi_xns_max.toString(), '9000000000000000000');
1169+
});
1170+
1171+
it ('max JSON wire limite', function() {
1172+
assert.strictEqual(Amount.bi_xns_min.toString(), '-9000000000000000000');
1173+
});
1174+
1175+
it('max mantissa value', function() {
1176+
assert.strictEqual(Amount.bi_man_max_value.toString(), '9999999999999999');
1177+
});
1178+
1179+
it('min mantissa value', function() {
1180+
assert.strictEqual(Amount.bi_man_min_value.toString(), '1000000000000000');
1181+
});
1182+
1183+
it ('from_json minimum XRP', function() {
1184+
console.log('max', Amount.bi_xns_max.toString());
1185+
var amt = Amount.from_json('-9000000000000000000');
1186+
assert.strictEqual(amt.to_json(), '-9000000000000000000');
1187+
});
1188+
1189+
it ('from_json maximum XRP', function() {
1190+
var amt = Amount.from_json('-9000000000000000000');
1191+
assert.strictEqual(amt.to_json(), '-9000000000000000000');
1192+
});
1193+
1194+
it ('from_json less than minimum XRP', function() {
1195+
var amt = Amount.from_json('-9000000000000000001');
1196+
assert.strictEqual(amt.to_json(), '0');
1197+
});
1198+
1199+
it ('from_json more than maximum XRP', function() {
1200+
var amt = Amount.from_json('9000000000000000001');
1201+
assert.strictEqual(amt.to_json(), '0');
1202+
});
1203+
1204+
it ('from_json minimum IOU', function() {
1205+
var amt = Amount.from_json('-1e-81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
1206+
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
1207+
assert.strictEqual(amt.to_text(), '-1000000000000000e-96');
1208+
assert.strictEqual(amt.to_text(), Amount.min_value);
1209+
});
1210+
1211+
it('from_json exceed minimum IOU', function() {
1212+
assert.throws(function() {
1213+
Amount.from_json('-1e-82/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
1214+
}, 'Exceeding min value of ' + Amount.min_value);
1215+
});
1216+
1217+
it ('from_json maximum IOU', function() {
1218+
var amt = Amount.from_json('9999999999999999e80/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
1219+
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
1220+
assert.strictEqual(amt.to_text(), '9999999999999999e80');
1221+
});
1222+
1223+
it ('from_json exceed maximum IOU', function() {
1224+
assert.throws(function() {
1225+
Amount.from_json('9999999999999999e81/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh')
1226+
}, 'Exceeding max value of ' + Amount.max_value);
1227+
});
1228+
1229+
it ('from_json normalize mantissa to valid max range, lost significant digits', function() {
1230+
var amt = Amount.from_json('99999999999999999999999999999999/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
1231+
assert.strictEqual(amt._value.toString(), Amount.bi_man_max_value.toString());
1232+
assert.strictEqual(amt.to_text(), '9999999999999999e16');
1233+
});
1234+
1235+
it ('from_json normalize mantissa to min valid range, lost significant digits', function() {
1236+
var amt = Amount.from_json('-0.0000000000000000000000001/USD/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh');
1237+
assert.strictEqual(amt._value.toString(), Amount.bi_man_min_value.toString());
1238+
assert.strictEqual(amt.to_text(), '-1000000000000000e-40');
1239+
});
1240+
});
11651241
});

0 commit comments

Comments
 (0)
Please sign in to comment.