@exodus/bigint 1.0.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/README.md +16 -0
- package/package.json +35 -0
- package/src/bn.js +160 -0
- package/src/index.js +4 -0
- package/src/native-bigint.js +173 -0
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# @exodus/bigint
|
|
2
|
+
|
|
3
|
+
Immutable API wrapper for big integers, using BigInt if available in the JS environment and falling back to bn.js if it isn't
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import BigIntWrapper from '@exodus/bigint'
|
|
9
|
+
|
|
10
|
+
const three = BigIntWrapper.wrap(3)
|
|
11
|
+
const five = BigIntWrapper.wrap(5)
|
|
12
|
+
|
|
13
|
+
// perform arithmetic
|
|
14
|
+
// see full API: ./src/native-bigint.js and ./src/__tests__/index.test.js
|
|
15
|
+
three.add(five).mul(three).div(five).pow(three).sub(five)
|
|
16
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@exodus/bigint",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "bigint wrappers for native BigUnt, bn.js and others",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"author": "Exodus Movement, Inc.",
|
|
7
|
+
"license": "UNLICENSED",
|
|
8
|
+
"homepage": "https://github.com/ExodusMovement/exodus-core/tree/master/packages/bigint#readme",
|
|
9
|
+
"files": [
|
|
10
|
+
"src",
|
|
11
|
+
"!**/__tests__",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"bn.js": "^4.11.0",
|
|
16
|
+
"lodash": "^4.17.11",
|
|
17
|
+
"minimalistic-assert": "^1.0.1"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"eslint": "^8.43.0",
|
|
21
|
+
"jest": "^29.3.1"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"test": "jest",
|
|
25
|
+
"lint": "eslint . --ignore-path ../../.gitignore",
|
|
26
|
+
"lint:fix": "yarn lint --fix"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/ExodusMovement/exodus-core.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/ExodusMovement/exodus-core/issues?q=is%3Aissue+is%3Aopen+label%3Abigint"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/bn.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import assert from 'minimalistic-assert'
|
|
2
|
+
import BN from 'bn.js'
|
|
3
|
+
|
|
4
|
+
// TODO: calculator delegator should wrap/unwrap all BN instances
|
|
5
|
+
// so that callers never gett a raw BN instance back
|
|
6
|
+
|
|
7
|
+
const FACTORY_SYMBOL = Symbol('bn-wrapper')
|
|
8
|
+
|
|
9
|
+
const unwrap = (value) => (value instanceof Wrapper ? value.unwrap() : value)
|
|
10
|
+
|
|
11
|
+
export default class Wrapper {
|
|
12
|
+
static name = 'bn.js'
|
|
13
|
+
static isUnderlyingInstance(a) {
|
|
14
|
+
return BN.isBN(a)
|
|
15
|
+
}
|
|
16
|
+
static wrap(value, base) {
|
|
17
|
+
return new Wrapper(FACTORY_SYMBOL, value, base)
|
|
18
|
+
}
|
|
19
|
+
static get ZERO() {
|
|
20
|
+
return ZERO
|
|
21
|
+
}
|
|
22
|
+
static get TEN() {
|
|
23
|
+
return TEN
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
__value__
|
|
27
|
+
|
|
28
|
+
constructor(factorySymbol, value, base = 10) {
|
|
29
|
+
if (factorySymbol !== FACTORY_SYMBOL) throw new Error('use wrap() instead')
|
|
30
|
+
|
|
31
|
+
if (BN.isBN(value)) {
|
|
32
|
+
this.__value__ = value
|
|
33
|
+
} else {
|
|
34
|
+
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
35
|
+
throw new TypeError(`Unsupported type: ${typeof value}`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (base !== 10 && base !== 16) throw new TypeError(`Unsupported base: ${base}`)
|
|
39
|
+
|
|
40
|
+
this.__value__ = new BN(value, base)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
unwrap() {
|
|
45
|
+
return this.__value__
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
add(value) {
|
|
49
|
+
return Wrapper.wrap(this.__value__.add(unwrap(value)))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
mutateAdd(value) {
|
|
53
|
+
this.__value__.iadd(unwrap(value))
|
|
54
|
+
return this
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
sub(value) {
|
|
58
|
+
return Wrapper.wrap(this.__value__.sub(unwrap(value)))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
mutateSub(value) {
|
|
62
|
+
this.__value__.isub(unwrap(value))
|
|
63
|
+
return this
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
mul(value) {
|
|
67
|
+
return Wrapper.wrap(this.__value__.mul(unwrap(value)))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
mutateMul(value) {
|
|
71
|
+
this.__value__.imul(unwrap(value))
|
|
72
|
+
return this
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
div(value) {
|
|
76
|
+
return Wrapper.wrap(this.__value__.div(unwrap(value)))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
mutateDiv(value) {
|
|
80
|
+
this.__value__.idivn(unwrap(value))
|
|
81
|
+
return this
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
mod(value) {
|
|
85
|
+
return Wrapper.wrap(this.__value__.mod(unwrap(value)))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pow(value) {
|
|
89
|
+
return Wrapper.wrap(this.__value__.pow(unwrap(value)))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
negate() {
|
|
93
|
+
return Wrapper.wrap(this.__value__.neg())
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
mutateNegate() {
|
|
97
|
+
return Wrapper.wrap(this.__value__.ineg())
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
abs() {
|
|
101
|
+
return this.isNegative() ? Wrapper.wrap(this.__value__.abs()) : this
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
mutateAbs() {
|
|
105
|
+
this.__value__.iabs()
|
|
106
|
+
return this
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
gte(value) {
|
|
110
|
+
return this.__value__.gte(unwrap(value))
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
gt(value) {
|
|
114
|
+
return this.__value__.gt(unwrap(value))
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
lte(value) {
|
|
118
|
+
return this.__value__.lte(unwrap(value))
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
lt(value) {
|
|
122
|
+
return this.__value__.lt(unwrap(value))
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
eq(value) {
|
|
126
|
+
return this.__value__.eq(unwrap(value))
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
isZero() {
|
|
130
|
+
return this.__value__.isZero()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
isNegative() {
|
|
134
|
+
return this.__value__.isNeg()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
isPositive() {
|
|
138
|
+
return this.__value__.gt(ZERO.unwrap())
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
toNumber() {
|
|
142
|
+
return this.__value__.toNumber()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
toString(base) {
|
|
146
|
+
assert(typeof base === 'number', 'expected number "base"')
|
|
147
|
+
return this.__value__.toString(base)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
toBaseBufferLE(length) {
|
|
151
|
+
return this.__value__.toBuffer('le', length)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
toBaseBufferBE(length) {
|
|
155
|
+
return this.__value__.toBuffer('be', length)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const ZERO = new Wrapper(FACTORY_SYMBOL, 0)
|
|
160
|
+
const TEN = new Wrapper(FACTORY_SYMBOL, 10)
|
package/src/index.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// TODO: calculator delegator should wrap/unwrap all BigInt instances
|
|
2
|
+
// so that callers never gett a raw BigInt instance back
|
|
3
|
+
|
|
4
|
+
import { memoize } from 'lodash'
|
|
5
|
+
import assert from 'minimalistic-assert'
|
|
6
|
+
|
|
7
|
+
const FACTORY_SYMBOL = Symbol('bigint-wrapper')
|
|
8
|
+
|
|
9
|
+
const unwrap = (value) => (value instanceof Wrapper ? value.unwrap() : value)
|
|
10
|
+
|
|
11
|
+
const memoizedWrap = memoize((value) => Wrapper.wrap(value))
|
|
12
|
+
|
|
13
|
+
export default class Wrapper {
|
|
14
|
+
static name = 'native-bigint'
|
|
15
|
+
|
|
16
|
+
static wrap(numberLike, base = 10) {
|
|
17
|
+
if (typeof numberLike === 'bigint') return new Wrapper(FACTORY_SYMBOL, numberLike)
|
|
18
|
+
if (typeof numberLike === 'number') return new Wrapper(FACTORY_SYMBOL, BigInt(numberLike))
|
|
19
|
+
if (typeof numberLike !== 'string') throw new Error(`Unsupported type: ${typeof numberLike}`)
|
|
20
|
+
|
|
21
|
+
switch (base) {
|
|
22
|
+
case 10:
|
|
23
|
+
return new Wrapper(FACTORY_SYMBOL, BigInt(numberLike))
|
|
24
|
+
case 16:
|
|
25
|
+
return new Wrapper(FACTORY_SYMBOL, BigInt('0x' + numberLike))
|
|
26
|
+
default:
|
|
27
|
+
throw new Error(`Unsupported base: ${base}`)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static isUnderlyingInstance(value) {
|
|
32
|
+
return typeof value === 'bigint'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static get ZERO() {
|
|
36
|
+
return memoizedWrap(0n)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static get TEN() {
|
|
40
|
+
return memoizedWrap(10n)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
__value__
|
|
44
|
+
|
|
45
|
+
constructor(factorySymbol, value) {
|
|
46
|
+
if (factorySymbol !== FACTORY_SYMBOL) throw new Error('use wrap() instead')
|
|
47
|
+
this.__value__ = value
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
unwrap() {
|
|
51
|
+
return this.__value__
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
add(value) {
|
|
55
|
+
return Wrapper.wrap(this.__value__ + unwrap(value))
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
mutateAdd(value) {
|
|
59
|
+
this.__value__ += unwrap(value)
|
|
60
|
+
return this
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
sub(value) {
|
|
64
|
+
return Wrapper.wrap(this.__value__ - unwrap(value))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
mutateSub(value) {
|
|
68
|
+
this.__value__ -= unwrap(value)
|
|
69
|
+
return this
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
mul(value) {
|
|
73
|
+
return Wrapper.wrap(this.__value__ * unwrap(value))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
mutateMul(value) {
|
|
77
|
+
this.__value__ *= unwrap(value)
|
|
78
|
+
return this
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
div(value) {
|
|
82
|
+
return Wrapper.wrap(this.__value__ / unwrap(value))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
mutateDiv(value) {
|
|
86
|
+
this.__value__ /= unwrap(value)
|
|
87
|
+
return this
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
mod(value) {
|
|
91
|
+
return Wrapper.wrap(this.__value__ % unwrap(value))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
pow(value) {
|
|
95
|
+
return Wrapper.wrap(this.__value__ ** unwrap(value))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
negate() {
|
|
99
|
+
return Wrapper.wrap(-this.__value__)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
mutateNegate() {
|
|
103
|
+
this.__value__ = -this.__value__
|
|
104
|
+
return this
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
abs() {
|
|
108
|
+
return this.__value__ < 0n ? Wrapper.wrap(-this.__value__) : this
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
mutateAbs() {
|
|
112
|
+
if (this.__value__ < 0n) this.__value__ = -this.__value__
|
|
113
|
+
return this
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
gte(value) {
|
|
117
|
+
return this.__value__ >= unwrap(value)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
gt(value) {
|
|
121
|
+
return this.__value__ > unwrap(value)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
lte(value) {
|
|
125
|
+
return this.__value__ <= unwrap(value)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
lt(value) {
|
|
129
|
+
return this.__value__ < unwrap(value)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
eq(value) {
|
|
133
|
+
return this.__value__ === unwrap(value)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
isZero() {
|
|
137
|
+
return this.__value__ === 0n
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
isNegative() {
|
|
141
|
+
return this.__value__ < 0n
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
isPositive() {
|
|
145
|
+
return this.__value__ > 0n
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
toString(base) {
|
|
149
|
+
assert(typeof base === 'number', 'expected number "base"')
|
|
150
|
+
return this.__value__.toString(base)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
toNumber() {
|
|
154
|
+
return Number(this.__value__)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
#getWidth() {
|
|
158
|
+
const bitLength = this.__value__.toString(2).length
|
|
159
|
+
return Math.ceil(bitLength / 8)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
toBaseBufferLE(width = this.#getWidth()) {
|
|
163
|
+
const hex = this.__value__.toString(16)
|
|
164
|
+
const buffer = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex')
|
|
165
|
+
buffer.reverse()
|
|
166
|
+
return buffer
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
toBaseBufferBE(width = this.#getWidth()) {
|
|
170
|
+
const hex = this.__value__.toString(16)
|
|
171
|
+
return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex')
|
|
172
|
+
}
|
|
173
|
+
}
|