Skip to content

Commit

Permalink
back to JSBI :(
Browse files Browse the repository at this point in the history
  • Loading branch information
moodysalem committed Mar 5, 2021
1 parent 6e4aee6 commit 15fe235
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 96 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"uniswap",
"ethereum"
],
"module": "dist/sdk.esm.js",
"module": "dist/sdk-core.esm.js",
"scripts": {
"build": "tsdx build",
"start": "tsdx watch",
Expand All @@ -24,6 +24,7 @@
"@ethersproject/address": "^5.0.2",
"big.js": "^5.2.2",
"decimal.js-light": "^2.5.0",
"jsbi": "^3.1.4",
"tiny-invariant": "^1.1.0",
"tiny-warning": "^1.0.3",
"toformat": "^2.0.0"
Expand Down
18 changes: 10 additions & 8 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import JSBI from 'jsbi'

// exports for external consumption
export type BigintIsh = bigint | string | number
export type BigintIsh = JSBI | string | number

export enum ChainId {
MAINNET = 1,
Expand All @@ -21,10 +23,10 @@ export enum Rounding {
}

// exports for internal consumption
export const ZERO = BigInt(0)
export const ONE = BigInt(1)
export const TWO = BigInt(2)
export const THREE = BigInt(3)
export const TEN = BigInt(10)
export const ONE_HUNDRED = BigInt(100)
export const MaxUint256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
export const ZERO = JSBI.BigInt(0)
export const ONE = JSBI.BigInt(1)
export const TWO = JSBI.BigInt(2)
export const THREE = JSBI.BigInt(3)
export const TEN = JSBI.BigInt(10)
export const ONE_HUNDRED = JSBI.BigInt(100)
export const MaxUint256 = JSBI.BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
5 changes: 3 additions & 2 deletions src/entities/fractions/currencyAmount.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import JSBI from 'jsbi'
import { ChainId } from '../../constants'
import { Token } from '../token'
import CurrencyAmount from './CurrencyAmount'
Expand All @@ -10,14 +11,14 @@ describe('CurrencyAmount', () => {
it('works', () => {
const token = new Token(ChainId.MAINNET, ADDRESS_ONE, 18)
const amount = new TokenAmount(token, 100)
expect(amount.raw).toEqual(BigInt(100))
expect(amount.raw).toEqual(JSBI.BigInt(100))
})
})

describe('#ether', () => {
it('produces ether amount', () => {
const amount = CurrencyAmount.ether(100)
expect(amount.raw).toEqual(BigInt(100))
expect(amount.raw).toEqual(JSBI.BigInt(100))
})
})
})
11 changes: 6 additions & 5 deletions src/entities/fractions/currencyAmount.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import JSBI from 'jsbi'
import { currencyEquals } from '../token'
import { Currency, ETHER } from '../currency'
import invariant from 'tiny-invariant'
Expand All @@ -22,25 +23,25 @@ export default class CurrencyAmount extends Fraction {

// amount _must_ be raw, i.e. in the native representation
protected constructor(currency: Currency, amount: BigintIsh) {
const parsedAmount = BigInt(amount)
const parsedAmount = JSBI.BigInt(amount)
invariant(parsedAmount < MaxUint256, 'AMOUNT')

super(parsedAmount, TEN ** BigInt(currency.decimals))
super(parsedAmount, JSBI.exponentiate(TEN, JSBI.BigInt(currency.decimals)))
this.currency = currency
}

public get raw(): bigint {
public get raw(): JSBI {
return this.numerator
}

public add(other: CurrencyAmount): CurrencyAmount {
invariant(currencyEquals(this.currency, other.currency), 'TOKEN')
return new CurrencyAmount(this.currency, this.raw + other.raw)
return new CurrencyAmount(this.currency, JSBI.add(this.raw, other.raw))
}

public subtract(other: CurrencyAmount): CurrencyAmount {
invariant(currencyEquals(this.currency, other.currency), 'TOKEN')
return new CurrencyAmount(this.currency, this.raw - other.raw)
return new CurrencyAmount(this.currency, JSBI.subtract(this.raw, other.raw))
}

public toSignificant(
Expand Down
115 changes: 70 additions & 45 deletions src/entities/fractions/fraction.test.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,121 @@
import JSBI from 'jsbi'
import Fraction from './fraction'

describe('Fraction', () => {
describe('#quotient', () => {
it('floor division', () => {
expect(new Fraction(BigInt(8), BigInt(3)).quotient).toEqual(BigInt(2)) // one below
expect(new Fraction(BigInt(12), BigInt(4)).quotient).toEqual(BigInt(3)) // exact
expect(new Fraction(BigInt(16), BigInt(5)).quotient).toEqual(BigInt(3)) // one above
expect(new Fraction(JSBI.BigInt(8), JSBI.BigInt(3)).quotient).toEqual(JSBI.BigInt(2)) // one below
expect(new Fraction(JSBI.BigInt(12), JSBI.BigInt(4)).quotient).toEqual(JSBI.BigInt(3)) // exact
expect(new Fraction(JSBI.BigInt(16), JSBI.BigInt(5)).quotient).toEqual(JSBI.BigInt(3)) // one above
})
})
describe('#remainder', () => {
it('returns fraction after divison', () => {
expect(new Fraction(BigInt(8), BigInt(3)).remainder).toEqual(new Fraction(BigInt(2), BigInt(3)))
expect(new Fraction(BigInt(12), BigInt(4)).remainder).toEqual(new Fraction(BigInt(0), BigInt(4)))
expect(new Fraction(BigInt(16), BigInt(5)).remainder).toEqual(new Fraction(BigInt(1), BigInt(5)))
expect(new Fraction(JSBI.BigInt(8), JSBI.BigInt(3)).remainder).toEqual(
new Fraction(JSBI.BigInt(2), JSBI.BigInt(3))
)
expect(new Fraction(JSBI.BigInt(12), JSBI.BigInt(4)).remainder).toEqual(
new Fraction(JSBI.BigInt(0), JSBI.BigInt(4))
)
expect(new Fraction(JSBI.BigInt(16), JSBI.BigInt(5)).remainder).toEqual(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(5))
)
})
})
describe('#invert', () => {
it('flips num and denom', () => {
expect(new Fraction(BigInt(5), BigInt(10)).invert().numerator).toEqual(BigInt(10))
expect(new Fraction(BigInt(5), BigInt(10)).invert().denominator).toEqual(BigInt(5))
expect(new Fraction(JSBI.BigInt(5), JSBI.BigInt(10)).invert().numerator).toEqual(JSBI.BigInt(10))
expect(new Fraction(JSBI.BigInt(5), JSBI.BigInt(10)).invert().denominator).toEqual(JSBI.BigInt(5))
})
})
describe('#add', () => {
it('multiples denoms and adds nums', () => {
expect(new Fraction(BigInt(1), BigInt(10)).add(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(52), BigInt(120))
expect(new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).add(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))).toEqual(
new Fraction(JSBI.BigInt(52), JSBI.BigInt(120))
)
})

it('same denom', () => {
expect(new Fraction(BigInt(1), BigInt(5)).add(new Fraction(BigInt(2), BigInt(5)))).toEqual(
new Fraction(BigInt(3), BigInt(5))
expect(new Fraction(JSBI.BigInt(1), JSBI.BigInt(5)).add(new Fraction(JSBI.BigInt(2), JSBI.BigInt(5)))).toEqual(
new Fraction(JSBI.BigInt(3), JSBI.BigInt(5))
)
})
})
describe('#subtract', () => {
it('multiples denoms and subtracts nums', () => {
expect(new Fraction(BigInt(1), BigInt(10)).subtract(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(-28), BigInt(120))
)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).subtract(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(-28), JSBI.BigInt(120)))
})
it('same denom', () => {
expect(new Fraction(BigInt(3), BigInt(5)).subtract(new Fraction(BigInt(2), BigInt(5)))).toEqual(
new Fraction(BigInt(1), BigInt(5))
)
expect(
new Fraction(JSBI.BigInt(3), JSBI.BigInt(5)).subtract(new Fraction(JSBI.BigInt(2), JSBI.BigInt(5)))
).toEqual(new Fraction(JSBI.BigInt(1), JSBI.BigInt(5)))
})
})
describe('#lessThan', () => {
it('correct', () => {
expect(new Fraction(BigInt(1), BigInt(10)).lessThan(new Fraction(BigInt(4), BigInt(12)))).toBe(true)
expect(new Fraction(BigInt(1), BigInt(3)).lessThan(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(new Fraction(BigInt(5), BigInt(12)).lessThan(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).lessThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toBe(true)
expect(new Fraction(JSBI.BigInt(1), JSBI.BigInt(3)).lessThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))).toBe(
false
)
expect(
new Fraction(JSBI.BigInt(5), JSBI.BigInt(12)).lessThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toBe(false)
})
})
describe('#equalTo', () => {
it('correct', () => {
expect(new Fraction(BigInt(1), BigInt(10)).equalTo(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(new Fraction(BigInt(1), BigInt(3)).equalTo(new Fraction(BigInt(4), BigInt(12)))).toBe(true)
expect(new Fraction(BigInt(5), BigInt(12)).equalTo(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).equalTo(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))).toBe(
false
)
expect(new Fraction(JSBI.BigInt(1), JSBI.BigInt(3)).equalTo(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))).toBe(
true
)
expect(new Fraction(JSBI.BigInt(5), JSBI.BigInt(12)).equalTo(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))).toBe(
false
)
})
})
describe('#greaterThan', () => {
it('correct', () => {
expect(new Fraction(BigInt(1), BigInt(10)).greaterThan(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(new Fraction(BigInt(1), BigInt(3)).greaterThan(new Fraction(BigInt(4), BigInt(12)))).toBe(false)
expect(new Fraction(BigInt(5), BigInt(12)).greaterThan(new Fraction(BigInt(4), BigInt(12)))).toBe(true)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).greaterThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toBe(false)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(3)).greaterThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toBe(false)
expect(
new Fraction(JSBI.BigInt(5), JSBI.BigInt(12)).greaterThan(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toBe(true)
})
})
describe('#multiplty', () => {
it('correct', () => {
expect(new Fraction(BigInt(1), BigInt(10)).multiply(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(4), BigInt(120))
)
expect(new Fraction(BigInt(1), BigInt(3)).multiply(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(4), BigInt(36))
)
expect(new Fraction(BigInt(5), BigInt(12)).multiply(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(20), BigInt(144))
)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).multiply(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(4), JSBI.BigInt(120)))
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(3)).multiply(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(4), JSBI.BigInt(36)))
expect(
new Fraction(JSBI.BigInt(5), JSBI.BigInt(12)).multiply(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(20), JSBI.BigInt(144)))
})
})
describe('#divide', () => {
it('correct', () => {
expect(new Fraction(BigInt(1), BigInt(10)).divide(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(12), BigInt(40))
)
expect(new Fraction(BigInt(1), BigInt(3)).divide(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(12), BigInt(12))
)
expect(new Fraction(BigInt(5), BigInt(12)).divide(new Fraction(BigInt(4), BigInt(12)))).toEqual(
new Fraction(BigInt(60), BigInt(48))
)
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(10)).divide(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(12), JSBI.BigInt(40)))
expect(
new Fraction(JSBI.BigInt(1), JSBI.BigInt(3)).divide(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(12), JSBI.BigInt(12)))
expect(
new Fraction(JSBI.BigInt(5), JSBI.BigInt(12)).divide(new Fraction(JSBI.BigInt(4), JSBI.BigInt(12)))
).toEqual(new Fraction(JSBI.BigInt(60), JSBI.BigInt(48)))
})
})
})
76 changes: 49 additions & 27 deletions src/entities/fractions/fraction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import JSBI from 'jsbi'
import invariant from 'tiny-invariant'
import _Decimal from 'decimal.js-light'
import _Big, { RoundingMode } from 'big.js'
Expand All @@ -22,73 +23,94 @@ const toFixedRounding = {
}

export default class Fraction {
public readonly numerator: bigint
public readonly denominator: bigint
public readonly numerator: JSBI
public readonly denominator: JSBI

public constructor(numerator: BigintIsh, denominator: BigintIsh = ONE) {
this.numerator = BigInt(numerator)
this.denominator = BigInt(denominator)
this.numerator = JSBI.BigInt(numerator)
this.denominator = JSBI.BigInt(denominator)
}

// performs floor division
public get quotient(): bigint {
return this.numerator / this.denominator
public get quotient(): JSBI {
return JSBI.divide(this.numerator, this.denominator)
}

// remainder after floor division
public get remainder(): Fraction {
return new Fraction(this.numerator % this.denominator, this.denominator)
return new Fraction(JSBI.remainder(this.numerator, this.denominator), this.denominator)
}

public invert(): Fraction {
return new Fraction(this.denominator, this.numerator)
}

public add(other: Fraction | BigintIsh): Fraction {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
if (this.denominator === otherParsed.denominator) {
return new Fraction(this.numerator + otherParsed.numerator, this.denominator)
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
if (JSBI.equal(this.denominator, otherParsed.denominator)) {
return new Fraction(JSBI.add(this.numerator, otherParsed.numerator), this.denominator)
}
return new Fraction(
this.numerator * otherParsed.denominator + otherParsed.numerator * this.denominator,
this.denominator * otherParsed.denominator
JSBI.add(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(otherParsed.numerator, this.denominator)
),
JSBI.multiply(this.denominator, otherParsed.denominator)
)
}

public subtract(other: Fraction | BigintIsh): Fraction {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
if (this.denominator === otherParsed.denominator) {
return new Fraction(this.numerator - otherParsed.numerator, this.denominator)
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
if (JSBI.equal(this.denominator, otherParsed.denominator)) {
return new Fraction(JSBI.subtract(this.numerator, otherParsed.numerator), this.denominator)
}
return new Fraction(
this.numerator * otherParsed.denominator - otherParsed.numerator * this.denominator,
this.denominator * otherParsed.denominator
JSBI.subtract(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(otherParsed.numerator, this.denominator)
),
JSBI.multiply(this.denominator, otherParsed.denominator)
)
}

public lessThan(other: Fraction | BigintIsh): boolean {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
return this.numerator * otherParsed.denominator < otherParsed.numerator * this.denominator
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
return JSBI.lessThan(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(otherParsed.numerator, this.denominator)
)
}

public equalTo(other: Fraction | BigintIsh): boolean {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
return this.numerator * otherParsed.denominator === otherParsed.numerator * this.denominator
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
return JSBI.equal(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(otherParsed.numerator, this.denominator)
)
}

public greaterThan(other: Fraction | BigintIsh): boolean {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
return this.numerator * otherParsed.denominator > otherParsed.numerator * this.denominator
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
return JSBI.greaterThan(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(otherParsed.numerator, this.denominator)
)
}

public multiply(other: Fraction | BigintIsh): Fraction {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
return new Fraction(this.numerator * otherParsed.numerator, this.denominator * otherParsed.denominator)
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
return new Fraction(
JSBI.multiply(this.numerator, otherParsed.numerator),
JSBI.multiply(this.denominator, otherParsed.denominator)
)
}

public divide(other: Fraction | BigintIsh): Fraction {
const otherParsed = other instanceof Fraction ? other : new Fraction(BigInt(other))
return new Fraction(this.numerator * otherParsed.denominator, this.denominator * otherParsed.numerator)
const otherParsed = other instanceof Fraction ? other : new Fraction(JSBI.BigInt(other))
return new Fraction(
JSBI.multiply(this.numerator, otherParsed.denominator),
JSBI.multiply(this.denominator, otherParsed.numerator)
)
}

public toSignificant(
Expand Down
Loading

0 comments on commit 15fe235

Please sign in to comment.