diff --git a/__tests__/utils/CairoTypes/CairoInt8.test.ts b/__tests__/utils/CairoTypes/CairoInt8.test.ts new file mode 100644 index 000000000..64d006ce7 --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt8.test.ts @@ -0,0 +1,118 @@ +/* eslint-disable no-new */ +import { Cairoint8, P, INT_8_MAX, INT_8_MIN } from '../../../src/utils/cairoDataTypes/int8'; + +describe('Cairoint8 class test', () => { + test('constructor 1 should throw on < INT_8_MIN', () => { + expect(() => { + new Cairoint8(INT_8_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_8_MIN'); + }); + + test('constructor 1 should throw on > INT_8_MAX', () => { + expect(() => { + new Cairoint8(INT_8_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_8_MAX'); + }); + + test('constructor 2 (number int8)', () => { + const i8 = new Cairoint8(5); + expect(i8.toApiRequest()).toEqual('5'); + }); + + test('validate should throw on < INT_8_MIN', () => { + expect(() => { + Cairoint8.validate(INT_8_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_8_MIN'); + }); + + test('validate should throw on > INT_8_MAX', () => { + expect(() => { + Cairoint8.validate(INT_8_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_8_MAX'); + }); + + test('validate should pass and return bigint', () => { + const validate = Cairoint8.validate(INT_8_MAX); + expect(typeof validate).toBe('bigint'); + }); + + test('is should return true', () => { + const is = Cairoint8.is(INT_8_MIN); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = Cairoint8.is(INT_8_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor 1 should support BigNumberish', () => { + const case1 = new Cairoint8(10n); + const case2 = new Cairoint8(10); + const case3 = new Cairoint8('10'); + const case4 = new Cairoint8('0xA'); + + expect(case1).toEqual(case2); + expect(case3).toEqual(case4); + expect(case1).toEqual(case4); + }); + + test('should convert INT_8_MAX to Int8 dec struct', () => { + const i8 = new Cairoint8(INT_8_MAX); + const i8Hex = i8.toInt8DecimalString(); + expect(i8Hex).toEqual('127'); + }); + + test('should convert INT_8_MAX to Int8 hex struct', () => { + const i8 = new Cairoint8(INT_8_MAX); + const i8Decimal = i8.toInt8HexString(); + expect(i8Decimal).toEqual('0x7f'); + }); + + test('isAbiType should return true', () => { + const isAbiType = Cairoint8.isAbiType('core::integer::i8'); + expect(isAbiType).toBe(true); + }); + + test('should convert INT_8_MAX to BN', () => { + const i8 = new Cairoint8(INT_8_MAX); + expect(i8.toBigInt()).toEqual(INT_8_MAX); + }); + + test('should convert INT_8_MAX to API Request', () => { + const i8 = new Cairoint8(INT_8_MAX); + expect(i8.toApiRequest()).toEqual('127'); + }); + + test('should convert unsigned number to API Request', () => { + const i8 = new Cairoint8(5); + expect(i8.toApiRequest()).toEqual('5'); + }); + + test('should serialize negative number to felt252', () => { + const i8 = new Cairoint8(-5); + expect(i8.toApiRequest()).toEqual( + '3618502788666131213697322783095070105623107215331596699973092056135872020476' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + expect( + Cairoint8.negativeFelt252ToBigInt( + 3618502788666131213697322783095070105623107215331596699973092056135872020476n + ) + ).toEqual(-5n); + }); + + test('should convert negative serialized number to API Request', () => { + expect(() => { + Cairoint8.validate252Bits(P + 1n); + }).toThrow('bigNumberish is bigger than MAX_252_BITS'); + }); + + test('should convert negative serialized number to API Request', () => { + expect(() => { + Cairoint8.validate252Bits(P - INT_8_MAX - 1n); + }).toThrow('bigNumberish is smaller than MIN_252_BITS'); + }); +}); diff --git a/src/utils/cairoDataTypes/int16.ts b/src/utils/cairoDataTypes/int16.ts new file mode 100644 index 000000000..86003aeba --- /dev/null +++ b/src/utils/cairoDataTypes/int16.ts @@ -0,0 +1,107 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i8 data type + */ + +import { BigNumberish } from '../../types'; +import { addHexPrefix } from '../encode'; +import { CairoFelt } from './felt'; + +export const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; +export const INT_16_MAX = (1n << 15n) - 1n; +export const INT_16_MIN = -(1n << 15n) + 1n; +export const MIN_252_BITS = P + INT_16_MIN; +export const MAX_252_BITS = P; + +export class Cairoint16 { + public felt252: bigint; + + static abiSelector = 'core::integer::i8'; + + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i8 + */ + + public constructor(int8: BigNumberish) { + const bigInt8 = Cairoint16.validate(int8); + + if (bigInt8 > 0 && bigInt8 <= INT_16_MAX) { + this.felt252 = bigInt8; + } else { + this.felt252 = P + bigInt8; + } + } + + /** + * Validate if BigNumberish can be represented as i8 + */ + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_16_MIN) throw Error('bigNumberish is smaller than INT_8_MIN'); + if (bigInt > INT_16_MAX) throw new Error('bigNumberish is bigger than INT_8_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_252_BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_252_BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } + + /** + * Check if BigNumberish can be represented as i8 + */ + static is(bigNumberish: BigNumberish) { + try { + Cairoint16.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === Cairoint16.abiSelector; + } + + static negativeFelt252ToBigInt(bigNumberish: BigNumberish) { + const bigInt = this.validate252Bits(bigNumberish); + return BigInt(bigInt - P); + } + + /** + * Return bigint representation + */ + toBigInt() { + return this.felt252; + } + + /** + * Return i8 structure with HexString + */ + toInt16HexString() { + return addHexPrefix(this.felt252.toString(16)); + } + + /** + * Return i8 structure with DecimalString + */ + toInt16DecimalString() { + return this.felt252.toString(10); + } + + /** + * Return api requests representation witch is felt + */ + toApiRequest() { + if (this.felt252 > 0) { + return CairoFelt(this.felt252); + } + return this.felt252.toString(); + } +} diff --git a/src/utils/cairoDataTypes/int8.ts b/src/utils/cairoDataTypes/int8.ts new file mode 100644 index 000000000..187e45d43 --- /dev/null +++ b/src/utils/cairoDataTypes/int8.ts @@ -0,0 +1,107 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i8 data type + */ + +import { BigNumberish } from '../../types'; +import { addHexPrefix } from '../encode'; +import { CairoFelt } from './felt'; + +export const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; +export const INT_8_MAX = (1n << 7n) - 1n; +export const INT_8_MIN = -(1n << 7n) + 1n; +export const MIN_252_BITS = P + INT_8_MIN; +export const MAX_252_BITS = P; + +export class Cairoint8 { + public felt252: bigint; + + static abiSelector = 'core::integer::i8'; + + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i8 + */ + + public constructor(int8: BigNumberish) { + const bigInt8 = Cairoint8.validate(int8); + + if (bigInt8 > 0 && bigInt8 <= INT_8_MAX) { + this.felt252 = bigInt8; + } else { + this.felt252 = P + bigInt8; + } + } + + /** + * Validate if BigNumberish can be represented as i8 + */ + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_8_MIN) throw Error('bigNumberish is smaller than INT_8_MIN'); + if (bigInt > INT_8_MAX) throw new Error('bigNumberish is bigger than INT_8_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_252_BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_252_BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } + + /** + * Check if BigNumberish can be represented as i8 + */ + static is(bigNumberish: BigNumberish) { + try { + Cairoint8.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === Cairoint8.abiSelector; + } + + static negativeFelt252ToBigInt(bigNumberish: BigNumberish) { + const bigInt = this.validate252Bits(bigNumberish); + return BigInt(bigInt - P); + } + + /** + * Return bigint representation + */ + toBigInt() { + return this.felt252; + } + + /** + * Return i8 structure with HexString + */ + toInt8HexString() { + return addHexPrefix(this.felt252.toString(16)); + } + + /** + * Return i8 structure with DecimalString + */ + toInt8DecimalString() { + return this.felt252.toString(10); + } + + /** + * Return api requests representation witch is felt + */ + toApiRequest() { + if (this.felt252 > 0) { + return CairoFelt(this.felt252); + } + return this.felt252.toString(); + } +}