ripple-binary-codec 2.6.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/enums/definitions.json +1 -1
- package/dist/enums/src/enums/definitions.json +6 -1
- package/dist/src/enums/definitions.json +1 -1
- package/dist/src/types/hash-128.js +1 -1
- package/dist/src/types/hash-128.js.map +1 -1
- package/dist/src/types/hash-160.js +1 -1
- package/dist/src/types/hash-160.js.map +1 -1
- package/dist/src/types/hash-192.js +1 -1
- package/dist/src/types/hash-192.js.map +1 -1
- package/dist/src/types/index.d.ts +2 -1
- package/dist/src/types/index.js +4 -1
- package/dist/src/types/index.js.map +1 -1
- package/dist/src/types/int-32.d.ts +33 -0
- package/dist/src/types/int-32.js +64 -0
- package/dist/src/types/int-32.js.map +1 -0
- package/dist/src/types/int.d.ts +38 -0
- package/dist/src/types/int.js +57 -0
- package/dist/src/types/int.js.map +1 -0
- package/dist/src/types/st-number.js +88 -33
- package/dist/src/types/st-number.js.map +1 -1
- package/dist/src/types/uint-16.js +2 -2
- package/dist/src/types/uint-16.js.map +1 -1
- package/dist/src/types/uint-32.js +1 -1
- package/dist/src/types/uint-32.js.map +1 -1
- package/dist/src/types/uint-64.js +1 -1
- package/dist/src/types/uint-64.js.map +1 -1
- package/dist/src/types/uint-8.js +1 -1
- package/dist/src/types/uint-8.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types/hash-128.js +1 -1
- package/dist/types/hash-128.js.map +1 -1
- package/dist/types/hash-160.js +1 -1
- package/dist/types/hash-160.js.map +1 -1
- package/dist/types/hash-192.js +1 -1
- package/dist/types/hash-192.js.map +1 -1
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js +4 -1
- package/dist/types/index.js.map +1 -1
- package/dist/types/int-32.d.ts +33 -0
- package/dist/types/int-32.js +64 -0
- package/dist/types/int-32.js.map +1 -0
- package/dist/types/int.d.ts +38 -0
- package/dist/types/int.js +57 -0
- package/dist/types/int.js.map +1 -0
- package/dist/types/st-number.js +88 -33
- package/dist/types/st-number.js.map +1 -1
- package/dist/types/uint-16.js +2 -2
- package/dist/types/uint-16.js.map +1 -1
- package/dist/types/uint-32.js +1 -1
- package/dist/types/uint-32.js.map +1 -1
- package/dist/types/uint-64.js +1 -1
- package/dist/types/uint-64.js.map +1 -1
- package/dist/types/uint-8.js +1 -1
- package/dist/types/uint-8.js.map +1 -1
- package/package.json +1 -1
- package/src/enums/definitions.json +6 -1
- package/src/types/hash-128.ts +1 -1
- package/src/types/hash-160.ts +1 -1
- package/src/types/hash-192.ts +1 -1
- package/src/types/index.ts +3 -0
- package/src/types/int-32.ts +72 -0
- package/src/types/int.ts +75 -0
- package/src/types/st-number.ts +107 -31
- package/src/types/uint-16.ts +2 -2
- package/src/types/uint-32.ts +1 -1
- package/src/types/uint-64.ts +1 -1
- package/src/types/uint-8.ts +1 -1
package/src/types/st-number.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable complexity -- required for various checks */
|
|
1
2
|
import { BinaryParser } from '../serdes/binary-parser'
|
|
2
3
|
import { SerializedType } from './serialized-type'
|
|
3
4
|
import { writeInt32BE, writeInt64BE, readInt32BE, readInt64BE } from '../utils'
|
|
@@ -6,8 +7,9 @@ import { writeInt32BE, writeInt64BE, readInt32BE, readInt64BE } from '../utils'
|
|
|
6
7
|
* Constants for mantissa and exponent normalization per XRPL Number spec.
|
|
7
8
|
* These define allowed magnitude for mantissa and exponent after normalization.
|
|
8
9
|
*/
|
|
9
|
-
const MIN_MANTISSA = BigInt('
|
|
10
|
-
const MAX_MANTISSA = BigInt('
|
|
10
|
+
const MIN_MANTISSA = BigInt('1000000000000000000') // 10^18
|
|
11
|
+
const MAX_MANTISSA = BigInt('9999999999999999999') // 10^19 - 1
|
|
12
|
+
const MAX_INT64 = BigInt('9223372036854775807') // 2^63 - 1, max signed 64-bit integer
|
|
11
13
|
const MIN_EXPONENT = -32768
|
|
12
14
|
const MAX_EXPONENT = 32768
|
|
13
15
|
const DEFAULT_VALUE_EXPONENT = -2147483648
|
|
@@ -62,6 +64,12 @@ function extractNumberPartsFromString(val: string): {
|
|
|
62
64
|
}
|
|
63
65
|
if (expPart) exponent += parseInt(expPart, 10)
|
|
64
66
|
|
|
67
|
+
// Remove trailing zeros from mantissa and adjust exponent
|
|
68
|
+
while (mantissaStr.length > 1 && mantissaStr.endsWith('0')) {
|
|
69
|
+
mantissaStr = mantissaStr.slice(0, -1)
|
|
70
|
+
exponent += 1
|
|
71
|
+
}
|
|
72
|
+
|
|
65
73
|
let mantissa = BigInt(mantissaStr)
|
|
66
74
|
if (sign === '-') mantissa = -mantissa
|
|
67
75
|
const isNegative = mantissa < BigInt(0)
|
|
@@ -72,7 +80,7 @@ function extractNumberPartsFromString(val: string): {
|
|
|
72
80
|
/**
|
|
73
81
|
* Normalize the mantissa and exponent to XRPL constraints.
|
|
74
82
|
*
|
|
75
|
-
* Ensures that after normalization, the mantissa is between MIN_MANTISSA and
|
|
83
|
+
* Ensures that after normalization, the mantissa is between MIN_MANTISSA and MAX_INT64.
|
|
76
84
|
* Adjusts the exponent as needed by shifting the mantissa left/right (multiplying/dividing by 10).
|
|
77
85
|
*
|
|
78
86
|
* @param mantissa - The unnormalized mantissa (BigInt).
|
|
@@ -87,16 +95,65 @@ function normalize(
|
|
|
87
95
|
let m = mantissa < BigInt(0) ? -mantissa : mantissa
|
|
88
96
|
const isNegative = mantissa < BigInt(0)
|
|
89
97
|
|
|
90
|
-
|
|
98
|
+
// Handle zero
|
|
99
|
+
if (m === BigInt(0)) {
|
|
100
|
+
return { mantissa: BigInt(0), exponent: DEFAULT_VALUE_EXPONENT }
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Grow mantissa until it reaches MIN_MANTISSA
|
|
104
|
+
while (m < MIN_MANTISSA && exponent > MIN_EXPONENT) {
|
|
91
105
|
exponent -= 1
|
|
92
106
|
m *= BigInt(10)
|
|
93
107
|
}
|
|
108
|
+
|
|
109
|
+
let lastDigit: bigint | null = null
|
|
110
|
+
|
|
111
|
+
// Shrink mantissa until it fits within MAX_MANTISSA
|
|
94
112
|
while (m > MAX_MANTISSA) {
|
|
95
|
-
if (exponent >= MAX_EXPONENT)
|
|
113
|
+
if (exponent >= MAX_EXPONENT) {
|
|
96
114
|
throw new Error('Mantissa and exponent are too large')
|
|
115
|
+
}
|
|
97
116
|
exponent += 1
|
|
117
|
+
lastDigit = m % BigInt(10)
|
|
98
118
|
m /= BigInt(10)
|
|
99
119
|
}
|
|
120
|
+
|
|
121
|
+
// Handle underflow: if exponent too small or mantissa too small, throw error
|
|
122
|
+
if (exponent < MIN_EXPONENT || m < MIN_MANTISSA) {
|
|
123
|
+
throw new Error('Underflow: value too small to represent')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Handle overflow: if exponent exceeds MAX_EXPONENT after growing.
|
|
127
|
+
if (exponent > MAX_EXPONENT) {
|
|
128
|
+
throw new Error('Exponent overflow: value too large to represent')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Handle overflow: if mantissa exceeds MAX_INT64 (2^63-1) after growing.
|
|
132
|
+
if (m > MAX_INT64) {
|
|
133
|
+
if (exponent >= MAX_EXPONENT) {
|
|
134
|
+
throw new Error('Exponent overflow: value too large to represent')
|
|
135
|
+
}
|
|
136
|
+
exponent += 1
|
|
137
|
+
lastDigit = m % BigInt(10)
|
|
138
|
+
m /= BigInt(10)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (lastDigit != null && lastDigit >= BigInt(5)) {
|
|
142
|
+
m += BigInt(1)
|
|
143
|
+
// After rounding, mantissa may exceed MAX_INT64 again
|
|
144
|
+
if (m > MAX_INT64) {
|
|
145
|
+
if (exponent >= MAX_EXPONENT) {
|
|
146
|
+
throw new Error('Exponent overflow: value too large to represent')
|
|
147
|
+
}
|
|
148
|
+
lastDigit = m % BigInt(10)
|
|
149
|
+
exponent += 1
|
|
150
|
+
m /= BigInt(10)
|
|
151
|
+
if (lastDigit >= BigInt(5)) {
|
|
152
|
+
m += BigInt(1)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
100
157
|
if (isNegative) m = -m
|
|
101
158
|
return { mantissa: m, exponent }
|
|
102
159
|
}
|
|
@@ -159,17 +216,9 @@ export class STNumber extends SerializedType {
|
|
|
159
216
|
* @throws Error if val is not a valid number string.
|
|
160
217
|
*/
|
|
161
218
|
static fromValue(val: string): STNumber {
|
|
162
|
-
const { mantissa, exponent
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (mantissa === BigInt(0) && exponent === 0 && !isNegative) {
|
|
167
|
-
normalizedMantissa = BigInt(0)
|
|
168
|
-
normalizedExponent = DEFAULT_VALUE_EXPONENT
|
|
169
|
-
} else {
|
|
170
|
-
;({ mantissa: normalizedMantissa, exponent: normalizedExponent } =
|
|
171
|
-
normalize(mantissa, exponent))
|
|
172
|
-
}
|
|
219
|
+
const { mantissa, exponent } = extractNumberPartsFromString(val)
|
|
220
|
+
const { mantissa: normalizedMantissa, exponent: normalizedExponent } =
|
|
221
|
+
normalize(mantissa, exponent)
|
|
173
222
|
|
|
174
223
|
const bytes = new Uint8Array(12)
|
|
175
224
|
writeInt64BE(bytes, normalizedMantissa, 0)
|
|
@@ -193,39 +242,66 @@ export class STNumber extends SerializedType {
|
|
|
193
242
|
*
|
|
194
243
|
* @returns String representation of the value
|
|
195
244
|
*/
|
|
196
|
-
// eslint-disable-next-line complexity -- required
|
|
197
245
|
toJSON(): string {
|
|
198
246
|
const b = this.bytes
|
|
199
|
-
if (!b || b
|
|
247
|
+
if (!b || b?.length !== 12)
|
|
200
248
|
throw new Error('STNumber internal bytes not set or wrong length')
|
|
201
249
|
|
|
202
250
|
// Signed 64-bit mantissa
|
|
203
251
|
const mantissa = readInt64BE(b, 0)
|
|
204
252
|
// Signed 32-bit exponent
|
|
205
|
-
|
|
253
|
+
let exponent = readInt32BE(b, 8)
|
|
206
254
|
|
|
207
255
|
// Special zero: XRPL encodes canonical zero as mantissa=0, exponent=DEFAULT_VALUE_EXPONENT.
|
|
208
256
|
if (mantissa === BigInt(0) && exponent === DEFAULT_VALUE_EXPONENT) {
|
|
209
257
|
return '0'
|
|
210
258
|
}
|
|
211
|
-
if (exponent === 0) return mantissa.toString()
|
|
212
259
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
260
|
+
const isNegative = mantissa < BigInt(0)
|
|
261
|
+
let mantissaAbs = isNegative ? -mantissa : mantissa
|
|
262
|
+
|
|
263
|
+
// If mantissa < MIN_MANTISSA, it was shrunk for int64 serialization (mantissa > 2^63-1).
|
|
264
|
+
// Restore it for proper string rendering to match rippled's internal representation.
|
|
265
|
+
if (mantissaAbs !== BigInt(0) && mantissaAbs < MIN_MANTISSA) {
|
|
266
|
+
mantissaAbs *= BigInt(10)
|
|
267
|
+
exponent -= 1
|
|
216
268
|
}
|
|
217
269
|
|
|
218
|
-
//
|
|
219
|
-
const
|
|
220
|
-
|
|
270
|
+
// For large mantissa range (default), rangeLog = 18
|
|
271
|
+
const rangeLog = 18
|
|
272
|
+
|
|
273
|
+
// Use scientific notation for exponents that are too small or too large
|
|
274
|
+
// Condition from rippled: exponent != 0 AND (exponent < -(rangeLog + 10) OR exponent > -(rangeLog - 10))
|
|
275
|
+
// For rangeLog = 18: exponent != 0 AND (exponent < -28 OR exponent > -8)
|
|
276
|
+
if (
|
|
277
|
+
exponent !== 0 &&
|
|
278
|
+
(exponent < -(rangeLog + 10) || exponent > -(rangeLog - 10))
|
|
279
|
+
) {
|
|
280
|
+
// Strip trailing zeros from mantissa (matches rippled behavior)
|
|
281
|
+
let exp = exponent
|
|
282
|
+
while (
|
|
283
|
+
mantissaAbs !== BigInt(0) &&
|
|
284
|
+
mantissaAbs % BigInt(10) === BigInt(0) &&
|
|
285
|
+
exp < MAX_EXPONENT
|
|
286
|
+
) {
|
|
287
|
+
mantissaAbs /= BigInt(10)
|
|
288
|
+
exp += 1
|
|
289
|
+
}
|
|
290
|
+
const sign = isNegative ? '-' : ''
|
|
291
|
+
return `${sign}${mantissaAbs}e${exp}`
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Decimal rendering for -(rangeLog + 10) <= exponent <= -(rangeLog - 10)
|
|
295
|
+
// i.e., -28 <= exponent <= -8, or exponent == 0
|
|
296
|
+
const padPrefix = rangeLog + 12 // 30
|
|
297
|
+
const padSuffix = rangeLog + 8 // 26
|
|
221
298
|
|
|
222
|
-
const padPrefix = 27
|
|
223
|
-
const padSuffix = 23
|
|
224
299
|
const mantissaStr = mantissaAbs.toString()
|
|
225
300
|
const rawValue = '0'.repeat(padPrefix) + mantissaStr + '0'.repeat(padSuffix)
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
const
|
|
301
|
+
const offset = exponent + padPrefix + rangeLog + 1 // exponent + 49
|
|
302
|
+
|
|
303
|
+
const integerPart = rawValue.slice(0, offset).replace(/^0+/, '') || '0'
|
|
304
|
+
const fractionPart = rawValue.slice(offset).replace(/0+$/, '')
|
|
229
305
|
|
|
230
306
|
return `${isNegative ? '-' : ''}${integerPart}${
|
|
231
307
|
fractionPart ? '.' + fractionPart : ''
|
package/src/types/uint-16.ts
CHANGED
|
@@ -29,7 +29,7 @@ class UInt16 extends UInt {
|
|
|
29
29
|
return val
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
if (typeof val === 'number') {
|
|
32
|
+
if (typeof val === 'number' && Number.isInteger(val)) {
|
|
33
33
|
UInt16.checkUintRange(val, 0, 0xffff)
|
|
34
34
|
|
|
35
35
|
const buf = new Uint8Array(UInt16.width)
|
|
@@ -37,7 +37,7 @@ class UInt16 extends UInt {
|
|
|
37
37
|
return new UInt16(buf)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
throw new Error('
|
|
40
|
+
throw new Error('Cannot construct UInt16 from given value')
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
package/src/types/uint-32.ts
CHANGED
package/src/types/uint-64.ts
CHANGED
package/src/types/uint-8.ts
CHANGED