diff --git a/app/exp001/goodness.ts b/app/exp001/goodness.ts index 72e0371..6795209 100644 --- a/app/exp001/goodness.ts +++ b/app/exp001/goodness.ts @@ -1,6 +1,7 @@ import { createPublicClient } from '../../packages/starkweb/dist/esm/clients/createPublicClient' import { http } from '../../packages/starkweb/dist/esm/clients/transports/http' import { mainnet } from '../../packages/starkweb/dist/esm/chains/definitions/mainnet' +import { sepolia } from '../../packages/starkweb/dist/esm/chains/definitions/sepolia'; export const crimeAbi = [ @@ -796,14 +797,33 @@ export const crimeAbi = [ const client = createPublicClient({ transport: http(), - chain: mainnet, + chain: sepolia, }) -const result = await client.readContract({ - address: '0x020bd5ec01c672e69e3ca74df376620a6be8a2b104ab70a9f0885be00dd38fb9', - abi: crimeAbi, - functionName: 'owner', - args: [], + + const result = await client.transport.request({ + jsonrpc: '2.0', + method: 'starknet_call', + params: [ + { + "calldata":["0x03b56013adf5ce1febefc5dbea283d4a5fb0ce2b9d9e8a174b8e8df005e88fe2"], +"contract_address":"0x01f7e900d8d0eb877e48c7637496f7727efaccd221c9006ee26f2b2376c9773f","entry_point_selector":"0x00cf37a862e5bf34bd0e858865ea02d4ba6db9cc722f3424eb452c94d4ea567f" + +}, + { + "calldata":["0x03b56013adf5ce1febefc5dbea283d4a5fb0ce2b9d9e8a174b8e8df005e88fe2"], +"contract_address":"0x01f7e900d8d0eb877e48c7637496f7727efaccd221c9006ee26f2b2376c9773f","entry_point_selector":"0x00cf37a862e5bf34bd0e858865ea02d4ba6db9cc722f3424eb452c94d4ea567f" + +}, + "latest" +], + id: 1, }) +// const result = await client.readContract({ +// address: '0x020bd5ec01c672e69e3ca74df376620a6be8a2b104ab70a9f0885be00dd38fb9', +// abi: crimeAbi, +// functionName: 'owner', +// args: [], +// }) console.log(result) diff --git a/app/next/pages/wallet.tsx b/app/next/pages/wallet.tsx index 7c6f7b1..2ff4f97 100644 --- a/app/next/pages/wallet.tsx +++ b/app/next/pages/wallet.tsx @@ -6,9 +6,11 @@ import { useAccount, useBalance, useWriteContract } from 'starkweb/react'; import { useState, useCallback } from 'react'; import { useTheme } from 'next-themes'; import Link from 'next/link'; -import { createWalletClient, custom, WalletClient } from 'starkweb'; import { erc20Abi } from '../utils/abi/strk'; import 'starkweb/window' +import { uint256 } from 'starkweb/utils'; +import { Address } from 'starkweb/dist/types/abi/starkweb-abi'; + const Wallet: NextPage = () => { const { theme, setTheme } = useTheme(); const [recipient, setRecipient] = useState(''); @@ -122,10 +124,10 @@ function SendTransactionCard({ amount, setAmount }: { - recipient: string; - setRecipient: (value: string) => void; - amount: string; - setAmount: (value: string) => void; + recipient: Address; + setRecipient: (value: Address) => void; + amount: bigint; + setAmount: (value: bigint) => void; }) { const [isPending, setIsPending] = useState(false); const [isError, setIsError] = useState(false); @@ -143,11 +145,8 @@ function SendTransactionCard({ abi: erc20Abi, functionName: 'transfer', args: { - recipient: recipient as 'contract_address', - amount: { - high: parseFloat(amount), - low: 0, - } as unknown as 'u256', + recipient: recipient, + amount: uint256(amount), } }); @@ -193,7 +192,7 @@ function SendTransactionCard({ id="recipient" type="text" value={recipient} - onChange={(e) => setRecipient(e.target.value)} + onChange={(e) => setRecipient(e.target.value as Address)} className="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white" placeholder="0x..." /> @@ -206,8 +205,8 @@ function SendTransactionCard({ setAmount(e.target.value)} + value={amount.toString()} + onChange={(e) => setAmount(BigInt(e.target.value))} className="w-full p-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white" placeholder="0.0" /> diff --git a/app/starkweb-client/src/index.ts b/app/starkweb-client/src/index.ts index 104f747..acfd4d3 100644 --- a/app/starkweb-client/src/index.ts +++ b/app/starkweb-client/src/index.ts @@ -7,16 +7,48 @@ import { createPublicClient, createWalletClient, custom, + erc20Abi, http, } from 'starkweb'; -import { sepolia } from 'starkweb/chains'; +import { getStarknetId, getStarknetIdName } from 'starkweb/actions'; +import { mainnet, sepolia } from 'starkweb/chains'; const publicClient = createPublicClient({ - chain: sepolia, - transport: http(), + chain: mainnet, + transport: http('https://starknet-mainnet.infura.io/v3/db72641028ee47f5b18bcbb791a3f829'), }); +const id = await getStarknetId(publicClient, { + domain: 'solene.stark', +}) +// const name = await getStarknetIdName(publicClient, { +// address: '0x061b6c0a78f9edf13cea17b50719f3344533fadd470b8cb29c2b4318014f52d3', +// }) +console.log(id) +// console.log(name) -const block = await publicClient.getBlockStateUpdate({ - block_tag: 'latest', -}); -console.log(block.state_diff); \ No newline at end of file +// const result = await publicClient.readContracts({ +// contracts: [ +// { +// abi: erc20Abi, +// functionName: 'balanceOf', +// args: +// { +// account: '0x005c475b6089156c0CD4Fc9d64De149992431c442AF882d6332e7c736c99DE91', +// }, +// address: +// '0x04718f5a0Fc34cC1AF16A1cdee98fFB20C31f5cD61D6Ab07201858f4287c938D', +// }, +// { +// abi: erc20Abi, +// functionName: 'balanceOf', +// args: +// { +// account: '0x034abecf49cedc634d0c3145da7b1caea99d8d4f2da5b5d41e532ea05192d523', +// }, +// address: +// '0x04718f5a0Fc34cC1AF16A1cdee98fFB20C31f5cD61D6Ab07201858f4287c938D', +// }, +// ], +// }) + +// console.log(result); diff --git a/packages/starkweb/src/abi/abitype.ts b/packages/starkweb/src/abi/abitype.ts index 2a08842..688356d 100644 --- a/packages/starkweb/src/abi/abitype.ts +++ b/packages/starkweb/src/abi/abitype.ts @@ -1,13 +1,13 @@ import type { Abi } from '../strk-types/abi.js'; - +import type { Uint512 } from '../strk-types/lib.js'; +import type { Uint256 } from '../strk-types/lib.js'; import type { AbiType, + Address, } from './starkweb-abi.js'; // import type { testAbi } from './testabi.js'; -export type CairoInt = 'u8' | 'u16' | 'u32' | 'u64' | 'u128' | 'u256' - - + export type CairoInt = 'u8' | 'u16' | 'u32' | 'u64' | 'u128' | 'u256' | 'u512' @@ -24,17 +24,18 @@ export type AbiParameterKind = 'inputs' | 'outputs'; */ interface PrimitiveTypeLookup { 'core::felt252': { inputs: 'felt252'; outputs: 'felt252' }; - 'core::integer::u8': { inputs: 'u8'; outputs: 'u8' }; - 'core::integer::u16': { inputs: 'u16'; outputs: 'u16' }; - 'core::integer::u32': { inputs: 'u32'; outputs: 'u32' }; - 'core::integer::u64': { inputs: 'u64'; outputs: 'u64' }; - 'core::integer::u128': { inputs: 'u128'; outputs: 'u128' }; - 'core::integer::u256': { inputs: 'u256'; outputs: 'u256' }; + 'core::integer::u8': { inputs: number; outputs: number }; + 'core::integer::u16': { inputs: number; outputs: number }; + 'core::integer::u32': { inputs: number; outputs: number }; + 'core::integer::u64': { inputs: number; outputs: number }; + 'core::integer::u128': { inputs: number; outputs: number }; + 'core::integer::u256': { inputs: Uint256; outputs: Uint256 }; + 'core::integer::u512': { inputs: Uint512; outputs: Uint512 }; 'core::array::Array': { inputs: 'T[]'; outputs: 'T[]' }; - 'core::bool': { inputs: 'boolean'; outputs: 'boolean' }; - 'core::starknet::contract_address::ContractAddress': { inputs: 'contract_address'; outputs: 'contract_address' }; - 'core::string::String': { inputs: 'string'; outputs: 'string' }; - 'core::starknet::class_hash::ClassHash': { inputs: 'string'; outputs: 'string' }; + 'core::bool': { inputs: boolean; outputs: boolean }; + 'core::starknet::contract_address::ContractAddress': { inputs: Address; outputs: Address }; + 'core::string::String': { inputs: string; outputs: string }; + 'core::starknet::class_hash::ClassHash': { inputs: string; outputs: string }; tuple: Record; } diff --git a/packages/starkweb/src/actions/public/readContract.ts b/packages/starkweb/src/actions/public/readContract.ts index 86187b6..9978477 100644 --- a/packages/starkweb/src/actions/public/readContract.ts +++ b/packages/starkweb/src/actions/public/readContract.ts @@ -107,6 +107,8 @@ export async function readContract< parameters as ReadContractParameters const calldata: string[] = args ? compile(args as any) : [] + // Simplified block_id determination + const txCall: CallParameters = { contract_address: address, entry_point_selector: getSelectorFromName(functionName), diff --git a/packages/starkweb/src/actions/public/readContracts.ts b/packages/starkweb/src/actions/public/readContracts.ts index ec113cb..79c485a 100644 --- a/packages/starkweb/src/actions/public/readContracts.ts +++ b/packages/starkweb/src/actions/public/readContracts.ts @@ -4,12 +4,14 @@ import type { Transport } from '../../clients/transports/createTransport.js' import { calldataToHex, compile } from '../../strk-utils/calldata/compile.js' import { getSelectorFromName } from '../../strk-utils/hash/selector.js' import type { Chain } from '../../types/chain.js' -import { call } from './call.js' +import { call, type CallParameters } from './call.js' import type { PrimaryReadContractParameters, SecondaryReadContractParameters, } from './readContract.js' import type { ContractFunctionName } from '../../types/contract.js' +import { createBatchScheduler } from '../../utils/promise/createBatchScheduler.js' +import { decodeFunctionCall } from '../../abi/output.js' export type ReadContractsParameters< abi extends Abi | readonly unknown[] = Abi, @@ -37,11 +39,14 @@ export async function readContracts< ): Promise { const { contracts, blockHash, blockNumber, blockTag } = parameters as ReadContractsParameters - const txCallsPromise = contracts.map((callParams) => { + if (contracts.length === 0) return [] + + // Prepare all call requests + const callRequests = contracts.map((callParams) => { const { address, functionName, args } = callParams const calldata: string[] = args ? compile(args as any) : [] - const txCall = { + return { contract_address: address, entry_point_selector: getSelectorFromName(functionName), calldata: calldataToHex(calldata), @@ -49,9 +54,31 @@ export async function readContracts< block_number: blockNumber, block_tag: blockTag, } - - return call(client, txCall) }) - return Promise.all(txCallsPromise) + // Create a batch scheduler for processing calls + const { schedule } = createBatchScheduler({ + id: 'readContracts', + fn: async (requests) => { + // Process all requests in a batch + const results = await Promise.all( + requests.map(request => call(client, request as CallParameters)) + ) + return results + } + }) + // Schedule all calls and collect results + const results = await Promise.all( + callRequests.map((request, index) => { + const contract = contracts[index]; + return schedule(request).then(([result]) => { + return decodeFunctionCall( + result as unknown as string[], + contract?.functionName, + contract?.abi as any + ); + }); + }) + ) + return results } diff --git a/packages/starkweb/src/actions/starknetId/getStarknetIdName.ts b/packages/starkweb/src/actions/starknetId/getStarknetIdName.ts index faadf67..dc596d8 100644 --- a/packages/starkweb/src/actions/starknetId/getStarknetIdName.ts +++ b/packages/starkweb/src/actions/starknetId/getStarknetIdName.ts @@ -33,7 +33,7 @@ export async function getStarknetIdName< client: Client, { address }: GetStarknetIdNameParameters, ): Promise { - const chainId = client.chain?.id as unknown as StarknetChainId + const chainId = client.chain?.chain_id as unknown as StarknetChainId if (!chainId) { throw new Error('Chain ID is required') } diff --git a/packages/starkweb/src/exports/utils.ts b/packages/starkweb/src/exports/utils.ts index 12ebe17..1255974 100644 --- a/packages/starkweb/src/exports/utils.ts +++ b/packages/starkweb/src/exports/utils.ts @@ -499,9 +499,10 @@ export { isBoolean, isNumber, isObject, isString, isUndefined } from '../strk-ut export { validateTypedData as snValidateTypedData, encodeData, encodeType, encodeValue } from '../strk-utils/typedData.js' export { CairoFelt } from '../strk-utils/cairoDataTypes/felt.js' -export { CairoUint256 } from '../strk-utils/cairoDataTypes/uint256.js' +export { createUint256 } from '../strk-utils/cairoDataTypes/uint256.js' +export { toUint512 } from '../strk-utils/cairoDataTypes/uint512.js' export { byteArrayFromString } from '../strk-utils/calldata/byteArray.js' -export { felt, uint256 } from '../strk-utils/calldata/cairo.js' +export { felt, uint256, uint512 } from '../strk-utils/calldata/cairo.js' export { compile, calldataToHex } from '../strk-utils/calldata/compile.js' export { CairoCustomEnum } from '../strk-utils/calldata/enum/CairoCustomEnum.js' export { CairoOption, CairoOptionVariant } from '../strk-utils/calldata/enum/CairoOption.js' diff --git a/packages/starkweb/src/strk-utils/cairoDataTypes/felt.ts b/packages/starkweb/src/strk-utils/cairoDataTypes/felt.ts index 35045ae..d6d83b9 100644 --- a/packages/starkweb/src/strk-utils/cairoDataTypes/felt.ts +++ b/packages/starkweb/src/strk-utils/cairoDataTypes/felt.ts @@ -3,37 +3,45 @@ import { isHex, isStringWholeNumber } from '../num.js' import { encodeShortString, isShortString, isText } from '../shortString.js' import { isBigInt, isBoolean, isString } from '../typed.js' + +/** + * Converts a BigNumberish value to a Cairo felt representation in string format + * @param it The value to convert to a felt + * @returns A string representation of the felt value + * @throws Error if the value cannot be converted to a felt + */ export function CairoFelt(it: BigNumberish): string { - // BN or number + // Handle BigInt or integer numbers if (isBigInt(it) || Number.isInteger(it)) { return it.toString() } - // Handling strings + // Handle string types if (isString(it)) { - // Hex strings + // Convert hex strings if (isHex(it)) { return BigInt(it).toString() } - // Text strings that must be short + // Handle text strings (must be short strings) if (isText(it)) { if (!isShortString(it)) { throw new Error( `${it} is a long string > 31 chars. Please split it into an array of short strings.`, ) } - // Assuming encodeShortString returns a hex representation of the string + // Convert short strings to felt return BigInt(encodeShortString(it)).toString() } - // Whole numeric strings + // Handle whole number strings if (isStringWholeNumber(it)) { return it } } - // bool to felt + // Handle boolean values if (isBoolean(it)) { return `${+it}` } + // Error for values that cannot be converted throw new Error(`${it} can't be computed by felt()`) } diff --git a/packages/starkweb/src/strk-utils/cairoDataTypes/uint256.ts b/packages/starkweb/src/strk-utils/cairoDataTypes/uint256.ts index d7eb051..a745db2 100644 --- a/packages/starkweb/src/strk-utils/cairoDataTypes/uint256.ts +++ b/packages/starkweb/src/strk-utils/cairoDataTypes/uint256.ts @@ -9,89 +9,129 @@ export const UINT_256_LOW_MAX = 340282366920938463463374607431768211455n export const UINT_256_HIGH_MAX = 340282366920938463463374607431768211455n export const UINT_256_LOW_MIN = 0n export const UINT_256_HIGH_MIN = 0n +export const UINT_256_ABI_SELECTOR = 'core::integer::u256' -export class CairoUint256 { - public low: bigint - - public high: bigint - - static abiSelector = 'core::integer::u256' - - public constructor(bigNumberish: BigNumberish) - - public constructor(low: BigNumberish, high: BigNumberish) - - public constructor(uint256: Uint256) +/** + * Validates if BigNumberish can be represented as Uint256 + * @param bigNumberish - The value to validate + * @returns The validated bigint + * @throws Error if the value is out of the valid range + */ +export function validateUint256(bigNumberish: BigNumberish): bigint { + const bigInt = BigInt(bigNumberish) + if (bigInt < UINT_256_MIN) + throw Error('bigNumberish is smaller than UINT_256_MIN') + if (bigInt > UINT_256_MAX) + throw new Error('bigNumberish is bigger than UINT_256_MAX') + return bigInt +} - public constructor(...arr: any[]) { - if ( - typeof arr[0] === 'object' && - arr.length === 1 && - 'low' in arr[0] && - 'high' in arr[0] - ) { - const props = CairoUint256.validateProps(arr[0].low, arr[0].high) - this.low = props.low - this.high = props.high - } else if (arr.length === 1) { - const bigInt = CairoUint256.validate(arr[0]) - this.low = bigInt & UINT_128_MAX - this.high = bigInt >> 128n - } else if (arr.length === 2) { - const props = CairoUint256.validateProps(arr[0], arr[1]) - this.low = props.low - this.high = props.high - } else { - throw Error('Incorrect constructor parameters') - } +/** + * Validates if low and high values can be represented as Uint256 + * @param low - The low part of the uint256 value + * @param high - The high part of the uint256 value + * @returns The validated low and high as bigints + * @throws Error if any value is out of the valid range + */ +export function validateUint256Props( + low: BigNumberish, + high: BigNumberish +): { low: bigint; high: bigint } { + const bigIntLow = BigInt(low) + const bigIntHigh = BigInt(high) + if (bigIntLow < UINT_256_LOW_MIN || bigIntLow > UINT_256_LOW_MAX) { + throw new Error('low is out of range UINT_256_LOW_MIN - UINT_256_LOW_MAX') } - - static validate(bigNumberish: BigNumberish) { - const bigInt = BigInt(bigNumberish) - if (bigInt < UINT_256_MIN) - throw Error('bigNumberish is smaller than UINT_256_MIN') - if (bigInt > UINT_256_MAX) - throw new Error('bigNumberish is bigger than UINT_256_MAX') - return bigInt + if (bigIntHigh < UINT_256_HIGH_MIN || bigIntHigh > UINT_256_HIGH_MAX) { + throw new Error( + 'high is out of range UINT_256_HIGH_MIN - UINT_256_HIGH_MAX', + ) } + return { low: bigIntLow, high: bigIntHigh } +} + +/** + * Checks if the given ABI type is a Uint256 + * @param abiType - The ABI type to check + * @returns True if the ABI type is a Uint256, false otherwise + */ +export function isUint256AbiType(abiType: string): boolean { + return abiType === UINT_256_ABI_SELECTOR +} - static validateProps(low: BigNumberish, high: BigNumberish) { - const bigIntLow = BigInt(low) - const bigIntHigh = BigInt(high) - if (bigIntLow < UINT_256_LOW_MIN || bigIntLow > UINT_256_LOW_MAX) { - throw new Error('low is out of range UINT_256_LOW_MIN - UINT_256_LOW_MAX') +/** + * Creates a Uint256 object from various input formats + * @param args - The arguments to create the Uint256 from + * @returns A Uint256 object + * @throws Error if the arguments are invalid + */ +export function createUint256(...args: any[]): Uint256 { + if ( + typeof args[0] === 'object' && + args.length === 1 && + 'low' in args[0] && + 'high' in args[0] + ) { + const props = validateUint256Props(args[0].low, args[0].high) + return { + low: props.low, + high: props.high } - if (bigIntHigh < UINT_256_HIGH_MIN || bigIntHigh > UINT_256_HIGH_MAX) { - throw new Error( - 'high is out of range UINT_256_HIGH_MIN - UINT_256_HIGH_MAX', - ) + } else if (args.length === 1) { + const bigInt = validateUint256(args[0]) + return { + low: bigInt & UINT_128_MAX, + high: bigInt >> 128n } - return { low: bigIntLow, high: bigIntHigh } - } - - static isAbiType(abiType: string) { - return abiType === CairoUint256.abiSelector - } - - toBigInt() { - return (this.high << 128n) + this.low - } - - toUint256HexString() { + } else if (args.length === 2) { + const props = validateUint256Props(args[0], args[1]) return { - low: addHexPrefix(this.low.toString(16)), - high: addHexPrefix(this.high.toString(16)), + low: props.low, + high: props.high } + } else { + throw Error('Incorrect Uint256 parameters') } +} - toUint256DecimalString() { - return { - low: this.low.toString(10), - high: this.high.toString(10), - } +/** + * Converts a Uint256 object to a bigint + * @param uint256 - The Uint256 object + * @returns The bigint representation + */ +export function uint256ToBigInt(uint256: Uint256): bigint { + return (BigInt(uint256.high) << 128n) + BigInt(uint256.low) +} + +/** + * Converts a Uint256 object to a hex string representation + * @param uint256 - The Uint256 object + * @returns An object with hex string representations of low and high + */ +export function uint256ToHexString(uint256: Uint256) { + return { + low: addHexPrefix(uint256.low.toString(16)), + high: addHexPrefix(uint256.high.toString(16)), } +} - toApiRequest() { - return [CairoFelt(this.low), CairoFelt(this.high)] +/** + * Converts a Uint256 object to a decimal string representation + * @param uint256 - The Uint256 object + * @returns An object with decimal string representations of low and high + */ +export function uint256ToDecimalString(uint256: Uint256) { + return { + low: uint256.low.toString(10), + high: uint256.high.toString(10), } } + +/** + * Converts a Uint256 object to an API request representation + * @param uint256 - The Uint256 object + * @returns An array of felt strings + */ +export function uint256ToApiRequest(uint256: Uint256): string[] { + return [CairoFelt(uint256.low), CairoFelt(uint256.high)] +} diff --git a/packages/starkweb/src/strk-utils/cairoDataTypes/uint512.ts b/packages/starkweb/src/strk-utils/cairoDataTypes/uint512.ts new file mode 100644 index 0000000..f45fab5 --- /dev/null +++ b/packages/starkweb/src/strk-utils/cairoDataTypes/uint512.ts @@ -0,0 +1,198 @@ +/* eslint-disable no-bitwise */ +/** + * Functions for handling cairo u512 data type + */ + +import type { BigNumberish, Uint512 } from '../../strk-types/lib.js'; +import { addHexPrefix } from '../encode.js'; +import { CairoFelt } from './felt.js'; +import { UINT_128_MAX } from './uint256.js'; + +export const UINT_512_MAX = (1n << 512n) - 1n; +export const UINT_512_MIN = 0n; +export const UINT_128_MIN = 0n; +export const UINT_512_ABI_SELECTOR = 'core::integer::u512'; + +/** + * Validates if BigNumberish can be represented as Uint512 + * @param bigNumberish - The value to validate + * @returns The validated bigint + * @throws Error if the value is out of the valid range + */ +export function validateUint512(bigNumberish: BigNumberish): bigint { + const bigInt = BigInt(bigNumberish); + if (bigInt < UINT_512_MIN) throw Error('bigNumberish is smaller than UINT_512_MIN.'); + if (bigInt > UINT_512_MAX) throw Error('bigNumberish is bigger than UINT_512_MAX.'); + return bigInt; +} + +/** + * Validates if limbs can be represented as Uint512 + * @param limb0 - The first limb (least significant) + * @param limb1 - The second limb + * @param limb2 - The third limb + * @param limb3 - The fourth limb (most significant) + * @returns The validated limbs as bigints + * @throws Error if any limb is out of the valid range + */ +export function validateUint512Props( + limb0: BigNumberish, + limb1: BigNumberish, + limb2: BigNumberish, + limb3: BigNumberish +): { limb0: bigint; limb1: bigint; limb2: bigint; limb3: bigint } { + const l0 = BigInt(limb0); + const l1 = BigInt(limb1); + const l2 = BigInt(limb2); + const l3 = BigInt(limb3); + [l0, l1, l2, l3].forEach((value: bigint, index) => { + if (value < UINT_128_MIN || value > UINT_128_MAX) { + throw Error(`limb${index} is not in the range of a u128 number`); + } + }); + return { limb0: l0, limb1: l1, limb2: l2, limb3: l3 }; +} + +/** + * Checks if BigNumberish can be represented as Uint512 + * @param bigNumberish - The value to check + * @returns True if the value can be represented as Uint512, false otherwise + */ +export function isUint512(bigNumberish: BigNumberish): boolean { + try { + validateUint512(bigNumberish); + } catch (error) { + return false; + } + return true; +} + +/** + * Checks if provided abi type is the Uint512 data type + * @param abiType - The ABI type to check + * @returns True if the ABI type is Uint512, false otherwise + */ +export function isUint512AbiType(abiType: string): boolean { + return abiType === UINT_512_ABI_SELECTOR; +} + +/** + * Converts a BigNumberish value to a Uint512 representation + * @param value - The value to convert + * @returns A Uint512 object + */ +export function toUint512(value: BigNumberish): Uint512; +/** + * Converts limbs to a Uint512 representation + * @param limb0 - The first limb (least significant) + * @param limb1 - The second limb + * @param limb2 - The third limb + * @param limb3 - The fourth limb (most significant) + * @returns A Uint512 object + */ +export function toUint512( + limb0: BigNumberish, + limb1: BigNumberish, + limb2: BigNumberish, + limb3: BigNumberish +): Uint512; +/** + * Converts a Uint512 object to a Uint512 representation + * @param uint512 - The Uint512 object + * @returns A Uint512 object + */ +export function toUint512(uint512: Uint512): Uint512; + +export function toUint512(...args: any[]): Uint512 { + if ( + typeof args[0] === 'object' && + args.length === 1 && + 'limb0' in args[0] && + 'limb1' in args[0] && + 'limb2' in args[0] && + 'limb3' in args[0] + ) { + const props = validateUint512Props( + args[0].limb0, + args[0].limb1, + args[0].limb2, + args[0].limb3 + ); + return { + limb0: props.limb0, + limb1: props.limb1, + limb2: props.limb2, + limb3: props.limb3 + }; + } else if (args.length === 1) { + const bigInt = validateUint512(args[0]); + return { + limb0: bigInt & UINT_128_MAX, + limb1: (bigInt & (UINT_128_MAX << 128n)) >> 128n, + limb2: (bigInt & (UINT_128_MAX << 256n)) >> 256n, + limb3: bigInt >> 384n + }; + } else if (args.length === 4) { + const props = validateUint512Props(args[0], args[1], args[2], args[3]); + return { + limb0: props.limb0, + limb1: props.limb1, + limb2: props.limb2, + limb3: props.limb3 + }; + } else { + throw Error('Incorrect Uint512 parameters'); + } +} + +/** + * Converts a Uint512 object to a bigint + * @param uint512 - The Uint512 object + * @returns The bigint representation + */ +export function uint512ToBigInt(uint512: Uint512): bigint { + return (BigInt(uint512.limb3) << 384n) + (BigInt(uint512.limb2) << 256n) + (BigInt(uint512.limb1) << 128n) + BigInt(uint512.limb0); +} + +/** + * Converts a Uint512 object to a hex string representation + * @param uint512 - The Uint512 object + * @returns An object with hex string representations of each limb + */ +export function uint512ToHexString(uint512: Uint512) { + return { + limb0: addHexPrefix(uint512.limb0.toString(16)), + limb1: addHexPrefix(uint512.limb1.toString(16)), + limb2: addHexPrefix(uint512.limb2.toString(16)), + limb3: addHexPrefix(uint512.limb3.toString(16)), + }; +} + +/** + * Converts a Uint512 object to a decimal string representation + * @param uint512 - The Uint512 object + * @returns An object with decimal string representations of each limb + */ +export function uint512ToDecimalString(uint512: Uint512) { + return { + limb0: uint512.limb0.toString(10), + limb1: uint512.limb1.toString(10), + limb2: uint512.limb2.toString(10), + limb3: uint512.limb3.toString(10), + }; +} + +/** + * Converts a Uint512 object to an API request representation + * @param uint512 - The Uint512 object + * @returns An array of felt strings + */ +export function uint512ToApiRequest(uint512: Uint512): string[] { + // lower limb first : https://github.com/starkware-libs/cairo/blob/07484c52791b76abcc18fd86265756904557d0d2/corelib/src/test/integer_test.cairo#L767 + return [ + CairoFelt(uint512.limb0), + CairoFelt(uint512.limb1), + CairoFelt(uint512.limb2), + CairoFelt(uint512.limb3), + ]; +} diff --git a/packages/starkweb/src/strk-utils/calldata/cairo.ts b/packages/starkweb/src/strk-utils/calldata/cairo.ts index dd1a38d..4a2f0e2 100644 --- a/packages/starkweb/src/strk-utils/calldata/cairo.ts +++ b/packages/starkweb/src/strk-utils/calldata/cairo.ts @@ -1,11 +1,16 @@ -import type { BigNumberish, Uint256 } from '../../strk-types/lib.js' +import type { BigNumberish, Uint256, Uint512 } from '../../strk-types/lib.js' import { CairoFelt } from '../cairoDataTypes/felt.js' -import { CairoUint256 } from '../cairoDataTypes/uint256.js' +import { createUint256 } from '../cairoDataTypes/uint256.js' +import { toUint512 } from '../cairoDataTypes/uint512.js' export function felt(it: BigNumberish): string { return CairoFelt(it) } export const uint256 = (it: BigNumberish): Uint256 => { - return new CairoUint256(it).toUint256DecimalString() + return createUint256(it) +} + +export const uint512 = (it: BigNumberish): Uint512 => { + return toUint512(it) } diff --git a/packages/starkweb/src/utils/chain/extractChain.ts b/packages/starkweb/src/utils/chain/extractChain.ts index 2bb828d..f71fc9e 100644 --- a/packages/starkweb/src/utils/chain/extractChain.ts +++ b/packages/starkweb/src/utils/chain/extractChain.ts @@ -3,22 +3,22 @@ import type { Chain } from '../../types/chain.js' export type ExtractChainParameters< chains extends readonly Chain[], - chainId extends chains[number]['id'], + chainId extends chains[number]['chain_id'], > = { chains: chains - id: chainId | chains[number]['id'] + id: chainId | chains[number]['chain_id'] } export type ExtractChainReturnType< chains extends readonly Chain[], - chainId extends chains[number]['id'], -> = Extract + chainId extends chains[number]['chain_id'], +> = Extract export type ExtractChainErrorType = ErrorType export function extractChain< const chains extends readonly Chain[], - chainId extends chains[number]['id'], + chainId extends chains[number]['chain_id'], >({ chains, id, @@ -26,8 +26,7 @@ export function extractChain< chains, chainId > { - return chains.find((chain) => chain.id === id) as ExtractChainReturnType< - chains, - chainId - > + return chains.find( + (chain) => chain.chain_id === id, + ) as ExtractChainReturnType }