import './eager_offset'
import { Bytes, ByteArray } from './collections'
import { typeConversion } from './conversion'
/** Host interface for BigInt arithmetic */
export declare namespace bigInt {
function plus(x: BigInt, y: BigInt): BigInt
function minus(x: BigInt, y: BigInt): BigInt
function times(x: BigInt, y: BigInt): BigInt
function dividedBy(x: BigInt, y: BigInt): BigInt
function dividedByDecimal(x: BigInt, y: BigDecimal): BigDecimal
function mod(x: BigInt, y: BigInt): BigInt
function pow(x: BigInt, exp: u8): BigInt
function fromString(s: string): BigInt
function bitOr(x: BigInt, y: BigInt): BigInt
function bitAnd(x: BigInt, y: BigInt): BigInt
function leftShift(x: BigInt, bits: u8): BigInt
function rightShift(x: BigInt, bits: u8): BigInt
}
/** Host interface for BigDecimal */
export declare namespace bigDecimal {
function plus(x: BigDecimal, y: BigDecimal): BigDecimal
function minus(x: BigDecimal, y: BigDecimal): BigDecimal
function times(x: BigDecimal, y: BigDecimal): BigDecimal
function dividedBy(x: BigDecimal, y: BigDecimal): BigDecimal
function equals(x: BigDecimal, y: BigDecimal): boolean
function toString(bigDecimal: BigDecimal): string
function fromString(s: string): BigDecimal
}
/** An Ethereum address (20 bytes). */
export class Address extends Bytes {
static fromString(s: string): Address {
return changetype
(typeConversion.stringToH160(s))
}
/** Convert `Bytes` that must be exactly 20 bytes long to an address.
* Passing in a value with fewer or more bytes will result in an error */
static fromBytes(b: Bytes): Address {
if (b.length != 20) {
throw new Error(
`Bytes of length ${b.length} can not be converted to 20 byte addresses`,
)
}
return changetype(b)
}
static zero(): Address {
let self = new ByteArray(20)
for (let i = 0; i < 20; i++) {
self[i] = 0
}
return changetype(self)
}
}
/** An arbitrary size integer represented as an array of bytes. */
export class BigInt extends Uint8Array {
static fromI32(x: i32): BigInt {
let byteArray = ByteArray.fromI32(x)
return BigInt.fromByteArray(byteArray)
}
static fromU32(x: u32): BigInt {
let byteArray = ByteArray.fromU32(x)
return BigInt.fromUnsignedBytes(byteArray)
}
static fromI64(x: i64): BigInt {
let byteArray = ByteArray.fromI64(x)
return BigInt.fromByteArray(byteArray)
}
static fromU64(x: u64): BigInt {
let byteArray = ByteArray.fromU64(x)
return BigInt.fromUnsignedBytes(byteArray)
}
static zero(): BigInt {
return BigInt.fromI32(0)
}
/**
* `bytes` assumed to be little-endian. If your input is big-endian, call `.reverse()` first.
*/
static fromSignedBytes(bytes: Bytes): BigInt {
let byteArray = bytes
return BigInt.fromByteArray(byteArray)
}
static fromByteArray(byteArray: ByteArray): BigInt {
return changetype(byteArray)
}
/**
* `bytes` assumed to be little-endian. If your input is big-endian, call `.reverse()` first.
*/
static fromUnsignedBytes(bytes: ByteArray): BigInt {
let signedBytes = new BigInt(bytes.length + 1)
for (let i = 0; i < bytes.length; i++) {
signedBytes[i] = bytes[i]
}
signedBytes[bytes.length] = 0
return signedBytes
}
toHex(): string {
return typeConversion.bigIntToHex(this)
}
toHexString(): string {
return typeConversion.bigIntToHex(this)
}
toString(): string {
return typeConversion.bigIntToString(this)
}
static fromString(s: string): BigInt {
return bigInt.fromString(s)
}
toI32(): i32 {
let uint8Array = changetype(this)
let byteArray = changetype(uint8Array)
return byteArray.toI32()
}
toU32(): u32 {
let uint8Array = changetype(this)
let byteArray = changetype(uint8Array)
return byteArray.toU32()
}
toI64(): i64 {
let uint8Array = changetype(this)
let byteArray = changetype(uint8Array)
return byteArray.toI64()
}
toU64(): u64 {
let uint8Array = changetype(this)
let byteArray = changetype(uint8Array)
return byteArray.toU64()
}
toBigDecimal(): BigDecimal {
return new BigDecimal(this)
}
isZero(): boolean {
return this == BigInt.fromI32(0)
}
isI32(): boolean {
return BigInt.fromI32(i32.MIN_VALUE) <= this && this <= BigInt.fromI32(i32.MAX_VALUE)
}
abs(): BigInt {
return this < BigInt.fromI32(0) ? this.neg() : this
}
sqrt(): BigInt {
let x: BigInt = this
let z = x.plus(BigInt.fromI32(1)).div(BigInt.fromI32(2))
let y = x
while (z < y) {
y = z
z = x.div(z).plus(z).div(BigInt.fromI32(2))
}
return y
}
// Operators
@operator('+')
plus(other: BigInt): BigInt {
assert(this !== null, "Failed to sum BigInts because left hand side is 'null'")
return bigInt.plus(this, other)
}
@operator('-')
minus(other: BigInt): BigInt {
assert(this !== null, "Failed to subtract BigInts because left hand side is 'null'")
return bigInt.minus(this, other)
}
@operator('*')
times(other: BigInt): BigInt {
assert(this !== null, "Failed to multiply BigInts because left hand side is 'null'")
return bigInt.times(this, other)
}
@operator('/')
div(other: BigInt): BigInt {
assert(this !== null, "Failed to divide BigInts because left hand side is 'null'")
return bigInt.dividedBy(this, other)
}
divDecimal(other: BigDecimal): BigDecimal {
return bigInt.dividedByDecimal(this, other)
}
@operator('%')
mod(other: BigInt): BigInt {
assert(
this !== null,
"Failed to apply module to BigInt because left hand side is 'null'",
)
return bigInt.mod(this, other)
}
@operator('==')
equals(other: BigInt): boolean {
return BigInt.compare(this, other) == 0
}
@operator('!=')
notEqual(other: BigInt): boolean {
return !(this == other)
}
@operator('<')
lt(other: BigInt): boolean {
return BigInt.compare(this, other) == -1
}
@operator('>')
gt(other: BigInt): boolean {
return BigInt.compare(this, other) == 1
}
@operator('<=')
le(other: BigInt): boolean {
return !(this > other)
}
@operator('>=')
ge(other: BigInt): boolean {
return !(this < other)
}
@operator.prefix('-')
neg(): BigInt {
return BigInt.fromI32(0).minus(this)
}
@operator('|')
bitOr(other: BigInt): BigInt {
return bigInt.bitOr(this, other)
}
@operator('&')
bitAnd(other: BigInt): BigInt {
return bigInt.bitAnd(this, other)
}
@operator('<<')
leftShift(bits: u8): BigInt {
return bigInt.leftShift(this, bits)
}
@operator('>>')
rightShift(bits: u8): BigInt {
return bigInt.rightShift(this, bits)
}
/// Limited to a low exponent to discourage creating a huge BigInt.
pow(exp: u8): BigInt {
return bigInt.pow(this, exp)
}
/**
* Returns −1 if a < b, 1 if a > b, and 0 if A == B
*/
static compare(a: BigInt, b: BigInt): i32 {
// Check if a and b have the same sign.
let aIsNeg = a.length > 0 && a[a.length - 1] >> 7 == 1
let bIsNeg = b.length > 0 && b[b.length - 1] >> 7 == 1
if (!aIsNeg && bIsNeg) {
return 1
} else if (aIsNeg && !bIsNeg) {
return -1
}
// Check how many bytes of a and b are relevant to the magnitude.
let aRelevantBytes = a.length
while (
aRelevantBytes > 0 &&
((!aIsNeg && a[aRelevantBytes - 1] == 0) ||
(aIsNeg && a[aRelevantBytes - 1] == 255))
) {
aRelevantBytes -= 1
}
let bRelevantBytes = b.length
while (
bRelevantBytes > 0 &&
((!bIsNeg && b[bRelevantBytes - 1] == 0) ||
(bIsNeg && b[bRelevantBytes - 1] == 255))
) {
bRelevantBytes -= 1
}
// If a and b are positive then the one with more relevant bytes is larger.
// Otherwise the one with less relevant bytes is larger.
if (aRelevantBytes > bRelevantBytes) {
return aIsNeg ? -1 : 1
} else if (bRelevantBytes > aRelevantBytes) {
return aIsNeg ? 1 : -1
}
// We now know that a and b have the same sign and number of relevant bytes.
// If a and b are both negative then the one of lesser magnitude is the
// largest, however since in two's complement the magnitude is flipped, we
// may use the same logic as if a and b are positive.
let relevantBytes = aRelevantBytes
for (let i = 1; i <= relevantBytes; i++) {
if (a[relevantBytes - i] < b[relevantBytes - i]) {
return -1
} else if (a[relevantBytes - i] > b[relevantBytes - i]) {
return 1
}
}
return 0
}
}
export class BigDecimal {
digits: BigInt
exp: BigInt
constructor(bigInt: BigInt) {
this.digits = bigInt
this.exp = BigInt.fromI32(0)
}
static fromString(s: string): BigDecimal {
return bigDecimal.fromString(s)
}
static zero(): BigDecimal {
return new BigDecimal(BigInt.zero())
}
toString(): string {
return bigDecimal.toString(this)
}
truncate(decimals: i32): BigDecimal {
let digitsRightOfZero = this.digits.toString().length + this.exp.toI32()
let newDigitLength = decimals + digitsRightOfZero
let truncateLength = this.digits.toString().length - newDigitLength
if (truncateLength < 0) {
return this
} else {
for (let i = 0; i < truncateLength; i++) {
this.digits = this.digits.div(BigInt.fromI32(10))
}
this.exp = BigInt.fromI32(decimals * -1)
return this
}
}
@operator('+')
plus(other: BigDecimal): BigDecimal {
assert(this !== null, "Failed to sum BigDecimals because left hand side is 'null'")
return bigDecimal.plus(this, other)
}
@operator('-')
minus(other: BigDecimal): BigDecimal {
assert(
this !== null,
"Failed to subtract BigDecimals because left hand side is 'null'",
)
return bigDecimal.minus(this, other)
}
@operator('*')
times(other: BigDecimal): BigDecimal {
assert(
this !== null,
"Failed to multiply BigDecimals because left hand side is 'null'",
)
return bigDecimal.times(this, other)
}
@operator('/')
div(other: BigDecimal): BigDecimal {
assert(this !== null, "Failed to divide BigDecimals because left hand side is 'null'")
return bigDecimal.dividedBy(this, other)
}
@operator('==')
equals(other: BigDecimal): boolean {
return BigDecimal.compare(this, other) == 0
}
@operator('!=')
notEqual(other: BigDecimal): boolean {
return !(this == other)
}
@operator('<')
lt(other: BigDecimal): boolean {
return BigDecimal.compare(this, other) == -1
}
@operator('>')
gt(other: BigDecimal): boolean {
return BigDecimal.compare(this, other) == 1
}
@operator('<=')
le(other: BigDecimal): boolean {
return !(this > other)
}
@operator('>=')
ge(other: BigDecimal): boolean {
return !(this < other)
}
@operator.prefix('-')
neg(): BigDecimal {
assert(this !== null, "Failed to negate BigDecimal because the value of it is 'null'")
return new BigDecimal(new BigInt(0)).minus(this)
}
/**
* Returns −1 if a < b, 1 if a > b, and 0 if A == B
*/
static compare(a: BigDecimal, b: BigDecimal): i32 {
let diff = a.minus(b)
if (diff.digits.isZero()) {
return 0
}
return diff.digits > BigInt.fromI32(0) ? 1 : -1
}
}