diff --git a/__tests__/utils/CairoTypes/CairoInt128.test.ts b/__tests__/utils/CairoTypes/CairoInt128.test.ts new file mode 100644 index 000000000..b90a123d1 --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt128.test.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-new */ +import { CairoInt128, INT_128_MAX, INT_128_MIN } from '../../../src/utils/cairoDataTypes/int128'; + +describe('CairoInt128 class test', () => { + test('constructor 1 should throw on < INT_128_MIN', () => { + expect(() => { + new CairoInt128(INT_128_MIN - 1n); + }).toThrow('bigNumberish is smaller than the int minimum'); + }); + + test('constructor should throw on > INT_128_MAX', () => { + expect(() => { + new CairoInt128(INT_128_MAX + 1n); + }).toThrow('bigNumberish is bigger than the int maximum'); + }); + + test('should convert INT_128_MAX to API Request', () => { + const i128 = new CairoInt128(INT_128_MAX); + expect(i128.toApiRequest()).toEqual('170141183460469231731687303715884105727'); + }); + + test('should serialize negative number to felt252', () => { + const i128 = new CairoInt128(INT_128_MIN); + expect(i128.toApiRequest()).toEqual( + '3618502788666131213697322783095070105452966031871127468241404752419987914754' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + const i128 = new CairoInt128(INT_128_MIN); + expect(i128.negativeFelt252ToBigInt()).toEqual(-170141183460469231731687303715884105727n); + }); + + test('validate should throw on < INT_128_MIN', () => { + expect(() => { + CairoInt128.validate(INT_128_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_128_MIN'); + }); + + test('validate should throw on > INT_128_MAX', () => { + expect(() => { + CairoInt128.validate(INT_128_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_128_MAX'); + }); + + test('validate should pass and return bigint', () => { + const validate = CairoInt128.validate(INT_128_MAX); + expect(typeof validate).toBe('bigint'); + }); + + test('is should return true', () => { + const is = CairoInt128.is(INT_128_MAX); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = CairoInt128.is(INT_128_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor should support BigNumberish', () => { + const case1 = new CairoInt128(10n); + const case2 = new CairoInt128(10); + const case3 = new CairoInt128('10'); + const case4 = new CairoInt128('0xA'); + + expect(case1).toEqual(case2); + expect(case3).toEqual(case4); + expect(case1).toEqual(case4); + }); + + test('should convert INT_128_MAX to Int128 dec struct', () => { + const i128 = new CairoInt128(INT_128_MAX); + const i128Decimal = i128.toIntDecimalString().int; + expect(i128Decimal).toEqual('170141183460469231731687303715884105727'); + }); + + test('should convert INT_128_MAX to Int128 hex struct', () => { + const i128 = new CairoInt128(INT_128_MAX); + const i128Hex = i128.toIntHexString(); + expect(i128Hex).toEqual('0x7fffffffffffffffffffffffffffffff'); + }); + + test('isAbiType should return true', () => { + const isAbiType = CairoInt128.isAbiType('core::integer::i128'); + expect(isAbiType).toBe(true); + }); + + test('should convert INT_128_MAX to BigInt', () => { + const i128 = new CairoInt128(INT_128_MAX); + expect(i128.toBigInt()).toEqual(INT_128_MAX); + }); +}); diff --git a/__tests__/utils/CairoTypes/CairoInt16.test.ts b/__tests__/utils/CairoTypes/CairoInt16.test.ts new file mode 100644 index 000000000..b7b97448b --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt16.test.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-new */ +import { CairoInt16, INT_16_MAX, INT_16_MIN } from '../../../src/utils/cairoDataTypes/int16'; + +describe('CairoInt16 class test', () => { + test('constructor 1 should throw on < INT_16_MIN', () => { + expect(() => { + new CairoInt16(INT_16_MIN - 1n); + }).toThrow('bigNumberish is smaller than the int minimum'); + }); + + test('constructor should throw on > INT_16_MAX', () => { + expect(() => { + new CairoInt16(INT_16_MAX + 1n); + }).toThrow('bigNumberish is bigger than the int maximum'); + }); + + test('should convert INT_16_MAX to API Request', () => { + const i16 = new CairoInt16(INT_16_MAX); + expect(i16.toApiRequest()).toEqual('32767'); + }); + + test('should serialize negative number to felt252', () => { + const i16 = new CairoInt16(INT_16_MIN); + expect(i16.toApiRequest()).toEqual( + '3618502788666131213697322783095070105623107215331596699973092056135871987714' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + const i16 = new CairoInt16(INT_16_MIN); + expect(i16.negativeFelt252ToBigInt()).toEqual(-32767n); + }); + + test('validate should throw on < INT_16_MIN', () => { + expect(() => { + CairoInt16.validate(INT_16_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_16_MIN'); + }); + + test('validate should throw on > INT_16_MAX', () => { + expect(() => { + CairoInt16.validate(INT_16_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_16_MAX'); + }); + + test('validate should pass and return bigint', () => { + const validate = CairoInt16.validate(INT_16_MAX); + expect(typeof validate).toBe('bigint'); + }); + + test('is should return true', () => { + const is = CairoInt16.is(INT_16_MAX); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = CairoInt16.is(INT_16_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor should support BigNumberish', () => { + const case1 = new CairoInt16(10n); + const case2 = new CairoInt16(10); + const case3 = new CairoInt16('10'); + const case4 = new CairoInt16('0xA'); + + expect(case1).toEqual(case2); + expect(case3).toEqual(case4); + expect(case1).toEqual(case4); + }); + + test('should convert INT_16_MAX to Int16 dec struct', () => { + const i16 = new CairoInt16(INT_16_MAX); + const i16Decimal = i16.toIntDecimalString().int; + expect(i16Decimal).toEqual('32767'); + }); + + test('should convert INT_16_MAX to Int16 hex struct', () => { + const i16 = new CairoInt16(INT_16_MAX); + const i16Hex = i16.toIntHexString(); + expect(i16Hex).toEqual('0x7fff'); + }); + + test('isAbiType should return true', () => { + const isAbiType = CairoInt16.isAbiType('core::integer::i16'); + expect(isAbiType).toBe(true); + }); + + test('should convert INT_16_MAX to BigInt', () => { + const i16 = new CairoInt16(INT_16_MAX); + expect(i16.toBigInt()).toEqual(INT_16_MAX); + }); +}); diff --git a/__tests__/utils/CairoTypes/CairoInt32.test.ts b/__tests__/utils/CairoTypes/CairoInt32.test.ts new file mode 100644 index 000000000..43fa9404c --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt32.test.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-new */ +import { CairoInt32, INT_32_MAX, INT_32_MIN } from '../../../src/utils/cairoDataTypes/int32'; + +describe('CairoInt32 class test', () => { + test('constructor 1 should throw on < INT_32_MIN', () => { + expect(() => { + new CairoInt32(INT_32_MIN - 1n); + }).toThrow('bigNumberish is smaller than the int minimum'); + }); + + test('constructor should throw on > INT_32_MAX', () => { + expect(() => { + new CairoInt32(INT_32_MAX + 1n); + }).toThrow('bigNumberish is bigger than the int maximum'); + }); + + test('should convert INT_32_MAX to API Request', () => { + const i32 = new CairoInt32(INT_32_MAX); + expect(i32.toApiRequest()).toEqual('2147483647'); + }); + + test('should serialize negative number to felt252', () => { + const i32 = new CairoInt32(INT_32_MIN); + expect(i32.toApiRequest()).toEqual( + '3618502788666131213697322783095070105623107215331596699973092056133724536834' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + const i32 = new CairoInt32(INT_32_MIN); + expect(i32.negativeFelt252ToBigInt()).toEqual(-2147483647n); + }); + + test('validate should throw on < INT_32_MIN', () => { + expect(() => { + CairoInt32.validate(INT_32_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_32_MIN'); + }); + + test('validate should throw on > INT_32_MAX', () => { + expect(() => { + CairoInt32.validate(INT_32_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_32_MAX'); + }); + + test('validate should pass and return bigint', () => { + const validate = CairoInt32.validate(INT_32_MAX); + expect(typeof validate).toBe('bigint'); + }); + + test('is should return true', () => { + const is = CairoInt32.is(INT_32_MAX); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = CairoInt32.is(INT_32_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor should support BigNumberish', () => { + const case1 = new CairoInt32(10n); + const case2 = new CairoInt32(10); + const case3 = new CairoInt32('10'); + const case4 = new CairoInt32('0xA'); + + expect(case1).toEqual(case2); + expect(case3).toEqual(case4); + expect(case1).toEqual(case4); + }); + + test('should convert INT_32_MAX to Int32 dec struct', () => { + const i32 = new CairoInt32(INT_32_MAX); + const i32Decimal = i32.toIntDecimalString().int; + expect(i32Decimal).toEqual('2147483647'); + }); + + test('should convert INT_32_MAX to Int32 hex struct', () => { + const i32 = new CairoInt32(INT_32_MAX); + const i32Hex = i32.toIntHexString(); + expect(i32Hex).toEqual('0x7fffffff'); + }); + + test('isAbiType should return true', () => { + const isAbiType = CairoInt32.isAbiType('core::integer::i32'); + expect(isAbiType).toBe(true); + }); + + test('should convert INT_32_MAX to BigInt', () => { + const i32 = new CairoInt32(INT_32_MAX); + expect(i32.toBigInt()).toEqual(INT_32_MAX); + }); +}); diff --git a/__tests__/utils/CairoTypes/CairoInt64.test.ts b/__tests__/utils/CairoTypes/CairoInt64.test.ts new file mode 100644 index 000000000..a03ba1184 --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt64.test.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-new */ +import { CairoInt64, INT_64_MAX, INT_64_MIN } from '../../../src/utils/cairoDataTypes/int64'; + +describe('CairoInt64 class test', () => { + test('constructor 1 should throw on < INT_64_MIN', () => { + expect(() => { + new CairoInt64(INT_64_MIN - 1n); + }).toThrow('bigNumberish is smaller than the int minimum'); + }); + + test('constructor should throw on > INT_64_MAX', () => { + expect(() => { + new CairoInt64(INT_64_MAX + 1n); + }).toThrow('bigNumberish is bigger than the int maximum'); + }); + + test('should convert INT_64_MAX to API Request', () => { + const i64 = new CairoInt64(INT_64_MAX); + expect(i64.toApiRequest()).toEqual('9223372036854775807'); + }); + + test('should serialize negative number to felt252', () => { + const i64 = new CairoInt64(INT_64_MIN); + expect(i64.toApiRequest()).toEqual( + '3618502788666131213697322783095070105623107215331596699963868684099017244674' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + const i64 = new CairoInt64(INT_64_MIN); + expect(i64.negativeFelt252ToBigInt()).toEqual(-9223372036854775807n); + }); + + test('validate should throw on < INT_64_MIN', () => { + expect(() => { + CairoInt64.validate(INT_64_MIN - 1n); + }).toThrow('bigNumberish is smaller than INT_64_MIN'); + }); + + test('validate should throw on > INT_64_MAX', () => { + expect(() => { + CairoInt64.validate(INT_64_MAX + 1n); + }).toThrow('bigNumberish is bigger than INT_64_MAX'); + }); + + test('validate should pass and return bigint', () => { + const validate = CairoInt64.validate(INT_64_MAX); + expect(typeof validate).toBe('bigint'); + }); + + test('is should return true', () => { + const is = CairoInt64.is(INT_64_MAX); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = CairoInt64.is(INT_64_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor should support BigNumberish', () => { + const case1 = new CairoInt64(10n); + const case2 = new CairoInt64(10); + const case3 = new CairoInt64('10'); + const case4 = new CairoInt64('0xA'); + + expect(case1).toEqual(case2); + expect(case3).toEqual(case4); + expect(case1).toEqual(case4); + }); + + test('should convert INT_64_MAX to Int64 dec struct', () => { + const i64 = new CairoInt64(INT_64_MAX); + const i64Decimal = i64.toIntDecimalString().int; + expect(i64Decimal).toEqual('9223372036854775807'); + }); + + test('should convert INT_64_MAX to Int64 hex struct', () => { + const i64 = new CairoInt64(INT_64_MAX); + const i64Hex = i64.toIntHexString(); + expect(i64Hex).toEqual('0x7fffffffffffffff'); + }); + + test('isAbiType should return true', () => { + const isAbiType = CairoInt64.isAbiType('core::integer::i64'); + expect(isAbiType).toBe(true); + }); + + test('should convert INT_64_MAX to BigInt', () => { + const i64 = new CairoInt64(INT_64_MAX); + expect(i64.toBigInt()).toEqual(INT_64_MAX); + }); +}); diff --git a/__tests__/utils/CairoTypes/CairoInt8.test.ts b/__tests__/utils/CairoTypes/CairoInt8.test.ts new file mode 100644 index 000000000..31d501d23 --- /dev/null +++ b/__tests__/utils/CairoTypes/CairoInt8.test.ts @@ -0,0 +1,93 @@ +/* eslint-disable no-new */ +import { CairoInt8, 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 the int minimum'); + }); + + test('constructor should throw on > INT_8_MAX', () => { + expect(() => { + new CairoInt8(INT_8_MAX + 1n); + }).toThrow('bigNumberish is bigger than the int maximum'); + }); + + test('should convert INT_8_MAX to API Request', () => { + const i8 = new CairoInt8(INT_8_MAX); + expect(i8.toApiRequest()).toEqual('127'); + }); + + test('should serialize negative number to felt252', () => { + const i8 = new CairoInt8(INT_8_MIN); + expect(i8.toApiRequest()).toEqual( + '3618502788666131213697322783095070105623107215331596699973092056135872020354' + ); + }); + + test('should convert negative serialized number to BigInt', () => { + const i8 = new CairoInt8(-5); + expect(i8.negativeFelt252ToBigInt()).toEqual(-5n); + }); + + 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_MAX); + expect(is).toBe(true); + }); + + test('is should return false', () => { + const is = CairoInt8.is(INT_8_MAX + 1n); + expect(is).toBe(false); + }); + + test('constructor 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 i8Decimal = i8.toIntDecimalString().int; + expect(i8Decimal).toEqual('127'); + }); + + test('should convert INT_8_MAX to Int8 hex struct', () => { + const i8 = new CairoInt8(INT_8_MAX); + const i8Hex = i8.toIntHexString(); + expect(i8Hex).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 BigInt', () => { + const i8 = new CairoInt8(INT_8_MAX); + expect(i8.toBigInt()).toEqual(INT_8_MAX); + }); +}); diff --git a/src/types/calldata.ts b/src/types/calldata.ts index 2a5f32ab5..c496adccb 100644 --- a/src/types/calldata.ts +++ b/src/types/calldata.ts @@ -18,8 +18,18 @@ export const Uint = { u512: 'core::integer::u512', // This one is struct } as const; +export const IntVal = { + i8: 'core::integer::i8', + i16: 'core::integer::i16', + i32: 'core::integer::i32', + i64: 'core::integer::i64', + i128: 'core::integer::i128', +} as const; + export type Uint = ValuesType; +export type IntVal = ValuesType; + export const Literal = { ClassHash: 'core::starknet::class_hash::ClassHash', ContractAddress: 'core::starknet::contract_address::ContractAddress', diff --git a/src/types/lib/index.ts b/src/types/lib/index.ts index 69be02c71..3d84150fb 100644 --- a/src/types/lib/index.ts +++ b/src/types/lib/index.ts @@ -45,6 +45,13 @@ export interface Uint512 { // The higher 128 bits of the value limb3: BigNumberish; } +/** + * Represents an integer in the range [0, 2^256) + */ +export interface Int { + // The lowest 128 bits of the value + int: BigNumberish; +} /** * BigNumberish array diff --git a/src/utils/cairoDataTypes/cairoInt.ts b/src/utils/cairoDataTypes/cairoInt.ts new file mode 100644 index 000000000..d5fad30e2 --- /dev/null +++ b/src/utils/cairoDataTypes/cairoInt.ts @@ -0,0 +1,105 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo integer 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 CairoInt { + public felt252: bigint; + + public INT_MAX: bigint = 0n; + + public INT_MIN: bigint = 0n; + + public MAX_FELT_8BITS = P; + + public MIN_FELT_8BITS: bigint = 0n; + + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i8 + */ + + public constructor(int: BigNumberish, INT_MAX: bigint, INT_MIN: bigint) { + this.INT_MAX = INT_MAX; + this.INT_MIN = INT_MIN; + this.MIN_FELT_8BITS = P + this.INT_MIN; + const bigInt = this.validate(int); + + if (bigInt > 0 && bigInt <= this.INT_MAX) { + this.felt252 = bigInt; + } else { + this.felt252 = P + bigInt; + } + } + + /** + * Validate if BigNumberish can be represented as i8 + */ + validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < this.INT_MIN) throw new Error('bigNumberish is smaller than the int minimum'); + if (bigInt > this.INT_MAX) throw new Error('bigNumberish is bigger than the int maximum'); + return bigInt; + } + + /** + * Validate if BigNumberish is a 8 bits felt252 + */ + validate252Bits(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt > this.MAX_FELT_8BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < this.MIN_FELT_8BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } + + /* + * Return a negative number (felt252) back to bigint + */ + negativeFelt252ToBigInt() { + const bigInt = this.validate252Bits(this.felt252); + return BigInt(bigInt - P); + } + + /** + * Return bigint representation + */ + toBigInt() { + return this.felt252; + } + + /** + * Return i8 structure with HexString + */ + toIntHexString() { + return addHexPrefix(this.felt252.toString(16)); + } + + /** + * Return i8 structure with DecimalString + */ + toIntDecimalString() { + return { + int: 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/int128.ts b/src/utils/cairoDataTypes/int128.ts new file mode 100644 index 000000000..623af1319 --- /dev/null +++ b/src/utils/cairoDataTypes/int128.ts @@ -0,0 +1,58 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i128 data type + */ + +import { BigNumberish } from '../../types'; +import { CairoInt } from './cairoInt'; + +export const INT_128_MAX = (1n << 127n) - 1n; +export const INT_128_MIN = -(1n << 127n) + 1n; +const abiSelector = 'core::integer::i128'; + +export class CairoInt128 extends CairoInt { + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i128 + */ + + public constructor(int128: BigNumberish) { + super(int128, INT_128_MAX, INT_128_MIN); + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === abiSelector; + } + + /* + * Check if BigNumberish can be represented as 128 bits integer + */ + static is(bigNumberish: BigNumberish) { + try { + CairoInt128.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_128_MIN) throw new Error('bigNumberish is smaller than INT_128_MIN'); + if (bigInt > INT_128_MAX) throw new Error('bigNumberish is bigger than INT_128_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; + const MAX_FELT_128BITS = P; + const MIN_FELT_128BITS = P + INT_128_MIN; + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_FELT_128BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_FELT_128BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } +} diff --git a/src/utils/cairoDataTypes/int16.ts b/src/utils/cairoDataTypes/int16.ts new file mode 100644 index 000000000..56b65f4f8 --- /dev/null +++ b/src/utils/cairoDataTypes/int16.ts @@ -0,0 +1,58 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i16 data type + */ + +import { BigNumberish } from '../../types'; +import { CairoInt } from './cairoInt'; + +export const INT_16_MAX = (1n << 15n) - 1n; +export const INT_16_MIN = -(1n << 15n) + 1n; +const abiSelector = 'core::integer::i16'; + +export class CairoInt16 extends CairoInt { + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i16 + */ + + public constructor(int16: BigNumberish) { + super(int16, INT_16_MAX, INT_16_MIN); + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === abiSelector; + } + + /* + * Check if BigNumberish can be represented as 16 bits integer + */ + static is(bigNumberish: BigNumberish) { + try { + CairoInt16.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_16_MIN) throw new Error('bigNumberish is smaller than INT_16_MIN'); + if (bigInt > INT_16_MAX) throw new Error('bigNumberish is bigger than INT_16_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; + const MAX_FELT_16BITS = P; + const MIN_FELT_16BITS = P + INT_16_MIN; + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_FELT_16BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_FELT_16BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } +} diff --git a/src/utils/cairoDataTypes/int32.ts b/src/utils/cairoDataTypes/int32.ts new file mode 100644 index 000000000..7240f28c2 --- /dev/null +++ b/src/utils/cairoDataTypes/int32.ts @@ -0,0 +1,58 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i32 data type + */ + +import { BigNumberish } from '../../types'; +import { CairoInt } from './cairoInt'; + +export const INT_32_MAX = (1n << 31n) - 1n; +export const INT_32_MIN = -(1n << 31n) + 1n; +const abiSelector = 'core::integer::i32'; + +export class CairoInt32 extends CairoInt { + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i32 + */ + + public constructor(int32: BigNumberish) { + super(int32, INT_32_MAX, INT_32_MIN); + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === abiSelector; + } + + /* + * Check if BigNumberish can be represented as 32 bits integer + */ + static is(bigNumberish: BigNumberish) { + try { + CairoInt32.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_32_MIN) throw new Error('bigNumberish is smaller than INT_32_MIN'); + if (bigInt > INT_32_MAX) throw new Error('bigNumberish is bigger than INT_32_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; + const MAX_FELT_32BITS = P; + const MIN_FELT_32BITS = P + INT_32_MIN; + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_FELT_32BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_FELT_32BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } +} diff --git a/src/utils/cairoDataTypes/int64.ts b/src/utils/cairoDataTypes/int64.ts new file mode 100644 index 000000000..763a5acfc --- /dev/null +++ b/src/utils/cairoDataTypes/int64.ts @@ -0,0 +1,58 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i64 data type + */ + +import { BigNumberish } from '../../types'; +import { CairoInt } from './cairoInt'; + +export const INT_64_MAX = (1n << 63n) - 1n; +export const INT_64_MIN = -(1n << 63n) + 1n; +const abiSelector = 'core::integer::i64'; + +export class CairoInt64 extends CairoInt { + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i64 + */ + + public constructor(int64: BigNumberish) { + super(int64, INT_64_MAX, INT_64_MIN); + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === abiSelector; + } + + /* + * Check if BigNumberish can be represented as 64 bits integer + */ + static is(bigNumberish: BigNumberish) { + try { + CairoInt64.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_64_MIN) throw new Error('bigNumberish is smaller than INT_64_MIN'); + if (bigInt > INT_64_MAX) throw new Error('bigNumberish is bigger than INT_64_MAX'); + return bigInt; + } + + static validate252Bits(bigNumberish: BigNumberish) { + const P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; + const MAX_FELT_64BITS = P; + const MIN_FELT_64BITS = P + INT_64_MIN; + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_FELT_64BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_FELT_64BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } +} diff --git a/src/utils/cairoDataTypes/int8.ts b/src/utils/cairoDataTypes/int8.ts new file mode 100644 index 000000000..019f10b76 --- /dev/null +++ b/src/utils/cairoDataTypes/int8.ts @@ -0,0 +1,60 @@ +/* eslint-disable no-bitwise */ +/** + * Singular class handling cairo i8 data type + */ + +import { BigNumberish } from '../../types'; +import { CairoInt } from './cairoInt'; + +export const INT_8_MAX = (1n << 7n) - 1n; +export const INT_8_MIN = -(1n << 7n) + 1n; +const abiSelector = 'core::integer::i8'; + +export class CairoInt8 extends CairoInt { + /** + * Default constructor (Lib usage) + * @param bigNumberish BigNumberish value representing i8 + */ + + public constructor(bigNumberish: BigNumberish); + + public constructor(int8: any) { + super(int8, INT_8_MAX, INT_8_MIN); + } + + /** + * Check if provided abi type is this data type + */ + static isAbiType(abiType: string) { + return abiType === abiSelector; + } + + /* + * Check if BigNumberish can be represented as 8 bits integer + */ + static is(bigNumberish: BigNumberish) { + try { + CairoInt8.validate(bigNumberish); + } catch (error) { + return false; + } + return true; + } + + static validate(bigNumberish: BigNumberish) { + const bigInt = BigInt(bigNumberish); + if (bigInt < INT_8_MIN) throw new 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 P: bigint = 2n ** 251n + 17n * 2n ** 192n + 1n; + const MAX_FELT_8BITS = P; + const MIN_FELT_8BITS = P + INT_8_MIN; + const bigInt = BigInt(bigNumberish); + if (bigInt > MAX_FELT_8BITS) throw new Error('bigNumberish is bigger than MAX_252_BITS'); + if (bigInt < MIN_FELT_8BITS) throw new Error('bigNumberish is smaller than MIN_252_BITS'); + return bigInt; + } +} diff --git a/src/utils/calldata/cairo.ts b/src/utils/calldata/cairo.ts index d0534918a..3c6fbc6a1 100644 --- a/src/utils/calldata/cairo.ts +++ b/src/utils/calldata/cairo.ts @@ -14,6 +14,12 @@ import { import { CairoFelt } from '../cairoDataTypes/felt'; import { CairoUint256 } from '../cairoDataTypes/uint256'; import { CairoUint512 } from '../cairoDataTypes/uint512'; +import { CairoInt8 } from '../cairoDataTypes/int8'; +import { CairoInt16 } from '../cairoDataTypes/int16'; +import { CairoInt32 } from '../cairoDataTypes/int32'; +import { CairoInt64 } from '../cairoDataTypes/int64'; +import { CairoInt128 } from '../cairoDataTypes/int128'; +import { Int } from '../../types/lib'; // Intended for internal usage, maybe should be exported somewhere else and not exported to utils /** @@ -244,6 +250,13 @@ export function getAbiContractVersion(abi: Abi): ContractVersion { export const uint256 = (it: BigNumberish): Uint256 => { return new CairoUint256(it).toUint256DecimalString(); }; +/** + * Create Uint256 Cairo type (helper for common struct type) + * @example + * ```typescript + * uint256('892349863487563453485768723498'); + * ``` + */ /** * Create Uint512 Cairo type (helper for common struct type) @@ -258,6 +271,57 @@ export const uint512 = (it: BigNumberish): Uint512 => { return new CairoUint512(it).toUint512DecimalString(); }; +/** + * Create int8 Cairo type (helper for common struct type) + * @example + * ```typescript + * int8('100'); + * ``` + */ +export const int8 = (it: BigNumberish): Int => { + return new CairoInt8(it).toIntDecimalString(); +}; +/** + * Create int16 Cairo type (helper for common struct type) + * @example + * ```typescript + * int16('30000'); + * ``` + */ +export const int16 = (it: BigNumberish): Int => { + return new CairoInt16(it).toIntDecimalString(); +}; +/** + * Create int32 Cairo type (helper for common struct type) + * @example + * ```typescript + * int32('2000000000'); + * ``` + */ +export const int32 = (it: BigNumberish): Int => { + return new CairoInt32(it).toIntDecimalString(); +}; +/** + * Create int64 Cairo type (helper for common struct type) + * @example + * ```typescript + * int64('9000000000000000000'); + * ``` + */ +export const int64 = (it: BigNumberish): Int => { + return new CairoInt64(it).toIntDecimalString(); +}; +/** + * Create int128 Cairo type (helper for common struct type) + * @example + * ```typescript + * int128('170000000000000000000000000000000000000'); + * ``` + */ +export const int128 = (it: BigNumberish): Int => { + return new CairoInt128(it).toIntDecimalString(); +}; + /** * Create unnamed tuple Cairo type (helper same as common struct type) * @example diff --git a/src/utils/calldata/requestParser.ts b/src/utils/calldata/requestParser.ts index 203b17ba4..5844197be 100644 --- a/src/utils/calldata/requestParser.ts +++ b/src/utils/calldata/requestParser.ts @@ -9,6 +9,11 @@ import { ParsedStruct, Tupled, } from '../../types'; +import { CairoInt128 } from '../cairoDataTypes/int128'; +import { CairoInt16 } from '../cairoDataTypes/int16'; +import { CairoInt32 } from '../cairoDataTypes/int32'; +import { CairoInt64 } from '../cairoDataTypes/int64'; +import { CairoInt8 } from '../cairoDataTypes/int8'; import { CairoUint256 } from '../cairoDataTypes/uint256'; import { CairoUint512 } from '../cairoDataTypes/uint512'; import { addHexPrefix, removeHexPrefix } from '../encode'; @@ -53,6 +58,17 @@ function parseBaseTypes(type: string, val: BigNumberish): AllowArray { return new CairoUint256(val).toApiRequest(); case CairoUint512.isAbiType(type): return new CairoUint512(val).toApiRequest(); + case CairoInt8.isAbiType(type): + return new CairoInt8(val).toApiRequest(); + case CairoInt16.isAbiType(type): + return new CairoInt16(val).toApiRequest(); + case CairoInt32.isAbiType(type): + return new CairoInt32(val).toApiRequest(); + case CairoInt64.isAbiType(type): + return new CairoInt64(val).toApiRequest(); + case CairoInt128.isAbiType(type): + return new CairoInt128(val).toApiRequest(); + case isTypeBytes31(type): return encodeShortString(val.toString()); case isTypeSecp256k1Point(type): { @@ -179,6 +195,26 @@ function parseCalldataValue( if (CairoUint512.isAbiType(type)) { return new CairoUint512(element as any).toApiRequest(); } + // check if i8 + if (CairoInt8.isAbiType(type)) { + return new CairoInt8(element as any).toApiRequest(); + } + // check if i16 + if (CairoInt16.isAbiType(type)) { + return new CairoInt16(element as any).toApiRequest(); + } + // check if i32 + if (CairoInt32.isAbiType(type)) { + return new CairoInt32(element as any).toApiRequest(); + } + // check if i64 + if (CairoInt64.isAbiType(type)) { + return new CairoInt64(element as any).toApiRequest(); + } + // check if i128 + if (CairoInt128.isAbiType(type)) { + return new CairoInt128(element as any).toApiRequest(); + } // check if Enum if (isTypeEnum(type, enums)) { const { variants } = enums[type]; diff --git a/src/utils/calldata/validate.ts b/src/utils/calldata/validate.ts index eac8198a4..21c90f7d0 100644 --- a/src/utils/calldata/validate.ts +++ b/src/utils/calldata/validate.ts @@ -6,8 +6,14 @@ import { FunctionAbi, Literal, Uint, + IntVal, } from '../../types'; import assert from '../assert'; +import { CairoInt128 } from '../cairoDataTypes/int128'; +import { CairoInt16 } from '../cairoDataTypes/int16'; +import { CairoInt32 } from '../cairoDataTypes/int32'; +import { CairoInt64 } from '../cairoDataTypes/int64'; +import { CairoInt8 } from '../cairoDataTypes/int8'; import { CairoUint256 } from '../cairoDataTypes/uint256'; import { CairoUint512 } from '../cairoDataTypes/uint512'; import { isHex, toBigInt } from '../num'; @@ -137,6 +143,40 @@ const validateUint = (parameter: any, input: AbiEntry) => { ); break; + case IntVal.i8: + assert( + CairoInt8.is(param), + `Validate: arg ${input.name} is ${input.type} should be in range 0 - ` + ); + break; + + case IntVal.i16: + assert( + CairoInt16.is(param), + `Validate: arg ${input.name} is ${input.type} should be in range 0 - ` + ); + break; + + case IntVal.i32: + assert( + CairoInt32.is(param), + `Validate: arg ${input.name} is ${input.type} should be in range 0 - ` + ); + break; + + case IntVal.i64: + assert( + CairoInt64.is(param), + `Validate: arg ${input.name} is ${input.type} should be in range 0 - ` + ); + break; + + case IntVal.i128: + assert( + CairoInt128.is(param), + `Validate: arg ${input.name} is ${input.type} should be in range 0 - ` + ); + break; case Literal.ClassHash: assert( // from : https://github.com/starkware-libs/starknet-specs/blob/29bab650be6b1847c92d4461d4c33008b5e50b1a/api/starknet_api_openrpc.json#L1670 diff --git a/www/versioned_docs/version-6.11.0/API/classes/CairoInt8.md b/www/versioned_docs/version-6.11.0/API/classes/CairoInt8.md new file mode 100644 index 000000000..6f37b6a70 --- /dev/null +++ b/www/versioned_docs/version-6.11.0/API/classes/CairoInt8.md @@ -0,0 +1,265 @@ +--- +id: 'CairoInt8' +title: 'Class: CairoInt8' +sidebar_label: 'CairoInt8' +sidebar_position: 0 +custom_edit_url: null +--- + +## Constructors + +### constructor + +• **new CairoInt8**(`bigNumberish`): [`CairoInt8`](CairoInt8.md) + +Default constructor (Lib usage) + +#### Parameters + +| Name | Type | Description | +| :------------- | :---------------------------------------------------- | :---------------------------------- | +| `bigNumberish` | [`BigNumberish`](../namespaces/types.md#bignumberish) | BigNumberish value representing in8 | + +#### Returns + +[`CairoInt8`](CairoInt8.md) + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:29](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L29) + +• **new CairoInt8**(`int8`): [`CairoInt8`](CairoInt8.md) + +Direct props initialization (Api response) + +#### Parameters + +| Name | Type | +| :----- | :---------------------------------------------------- | +| `int8` | [`BigNumberish`](../namespaces/types.md#bignumberish) | + +#### Returns + +[`CairoInt8`](CairoInt8.md) + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:33](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L19) + +• **new CairoInt8**(`Int8`): [`CairoInt8`](CairoInt8.md) + +Initialization from Int8 object + +#### Parameters + +| Name | Type | +| :----- | :------------------------------------ | +| `int8` | [`int8`](../interfaces/types.Int8.md) | + +#### Returns + +[`CairoInt8`](CairoInt8.md) + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:37](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L37) + +## Properties + +### abiSelector + +▪ `Static` **abiSelector**: `string` = `'core::integer::u256'` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:23](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L23) + +--- + +### low + +• **low**: `bigint` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:19](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L19) + +--- + +### high + +• **high**: `bigint` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:21](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L21) + +## Methods + +### validate + +▸ **validate**(`bigNumberish`): `bigint` + +Validate if BigNumberish can be represented as Int8 + +#### Parameters + +| Name | Type | +| :------------- | :---------------------------------------------------- | +| `bigNumberish` | [`BigNumberish`](../namespaces/types.md#bignumberish) | + +#### Returns + +`bigint` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:60](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L60) + +--- + +### validateProps + +▸ **validateProps**(`low`, `high`): `Object` + +Validate if low and high can be represented as Int8 + +#### Parameters + +| Name | Type | +| :----- | :---------------------------------------------------- | +| `low` | [`BigNumberish`](../namespaces/types.md#bignumberish) | +| `high` | [`BigNumberish`](../namespaces/types.md#bignumberish) | + +#### Returns + +`Object` + +| Name | Type | +| :----- | :------- | +| `low` | `bigint` | +| `high` | `bigint` | + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:70](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L70) + +--- + +### is + +▸ **is**(`bigNumberish`): `boolean` + +Check if BigNumberish can be represented as Int8 + +#### Parameters + +| Name | Type | +| :------------- | :---------------------------------------------------- | +| `bigNumberish` | [`BigNumberish`](../namespaces/types.md#bignumberish) | + +#### Returns + +`boolean` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:85](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L85) + +--- + +### isAbiType + +▸ **isAbiType**(`abiType`): `boolean` + +Check if provided abi type is this data type + +#### Parameters + +| Name | Type | +| :-------- | :------- | +| `abiType` | `string` | + +#### Returns + +`boolean` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:97](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L97) + +--- + +### toBigInt + +▸ **toBigInt**(): `bigint` + +Return bigint representation + +#### Returns + +`bigint` + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:104](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L104) + +--- + +### toInt8HexString + +▸ **toInt8HexString**(): `Object` + +Return c structure with HexString props +{low: HexString, high: HexString} + +#### Returns + +`Object` + +| Name | Type | +| :----- | :------- | +| `low` | `string` | +| `high` | `string` | + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:112](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L112) + +--- + +### toInt8DecimalString + +▸ **toInt8DecimalString**(): `Object` + +Return int8 structure with DecimalString props +{low: DecString, high: DecString} + +#### Returns + +`Object` + +| Name | Type | +| :----- | :------- | +| `low` | `string` | +| `high` | `string` | + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:123](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L123) + +--- + +### toApiRequest + +▸ **toApiRequest**(): `string`[] + +Return api requests representation witch is felt array + +#### Returns + +`string`[] + +#### Defined in + +[src/utils/cairoDataTypes/int8.ts:133](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/utils/cairoDataTypes/int8.ts#L133) diff --git a/www/versioned_docs/version-6.11.0/API/interfaces/types.Int8.md b/www/versioned_docs/version-6.11.0/API/interfaces/types.Int8.md new file mode 100644 index 000000000..ad9c857d9 --- /dev/null +++ b/www/versioned_docs/version-6.11.0/API/interfaces/types.Int8.md @@ -0,0 +1,30 @@ +--- +id: 'types.int8' +title: 'Interface: int8' +sidebar_label: 'int8' +custom_edit_url: null +--- + +[types](../namespaces/types.md).int8 + +Represents an integer in the range [0, 2^256) + +## Properties + +### low + +• **low**: [`BigNumberish`](../namespaces/types.md#bignumberish) + +#### Defined in + +[src/types/lib/index.ts:31](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/types/lib/index.ts#L31) + +--- + +### high + +• **high**: [`BigNumberish`](../namespaces/types.md#bignumberish) + +#### Defined in + +[src/types/lib/index.ts:33](https://github.com/starknet-io/starknet.js/blob/v6.11.0/src/types/lib/index.ts#L33)