Skip to content

Commit

Permalink
fix: cleanup and docs update, string types descriptive
Browse files Browse the repository at this point in the history
  • Loading branch information
tabaktoni committed Sep 8, 2023
1 parent 395b6e4 commit 08bd45f
Show file tree
Hide file tree
Showing 13 changed files with 420 additions and 100 deletions.
2 changes: 1 addition & 1 deletion src/account/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class Account extends Provider implements AccountInterface {
? new Signer(pkOrSigner)
: pkOrSigner;

this.cairoVersion = cairoVersion;
this.cairoVersion = cairoVersion.toString() as CairoVersion;
}

public async getNonce(blockIdentifier?: BlockIdentifier): Promise<Nonce> {
Expand Down
9 changes: 9 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
export { IS_BROWSER } from './utils/encode';

/**
* Cairo Felt support storing max 31 character
*/
export const TEXT_TO_FELT_MAX_LEN = 31;

export const HEX_STR_TRANSACTION_VERSION_1 = '0x1';
export const HEX_STR_TRANSACTION_VERSION_2 = '0x2';
export const BN_TRANSACTION_VERSION_1 = 1n;
export const BN_TRANSACTION_VERSION_2 = 2n;
export const BN_FEE_TRANSACTION_VERSION_1 = 2n ** 128n + BN_TRANSACTION_VERSION_1;
export const BN_FEE_TRANSACTION_VERSION_2 = 2n ** 128n + BN_TRANSACTION_VERSION_2;

export const ZERO = 0n;
export const MASK_250 = 2n ** 250n - 1n; // 2 ** 250 - 1
Expand Down
4 changes: 2 additions & 2 deletions src/utils/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { cleanHex } from './num';

/**
* Parse Transaction Receipt Event from UDC invoke transaction and
* create DeployContractResponse compatibile response with adition of UDC Event data
* create DeployContractResponse compatible response with addition of the UDC Event data
*
* @param txReceipt
* @param txReceipt InvokeTransactionReceiptResponse
* @returns DeployContractResponse | UDC Event Response data
*/
export function parseUDCEvent(txReceipt: InvokeTransactionReceiptResponse) {
Expand Down
124 changes: 110 additions & 14 deletions src/utils/hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
/* eslint-disable import/extensions */
import { poseidonHashMany } from '@scure/starknet';

import { API_VERSION, StarknetChainId, TransactionHashPrefix } from '../constants';
import {
API_VERSION,
BN_FEE_TRANSACTION_VERSION_1,
BN_FEE_TRANSACTION_VERSION_2,
BN_TRANSACTION_VERSION_1,
BN_TRANSACTION_VERSION_2,
StarknetChainId,
TransactionHashPrefix,
} from '../constants';
import {
BigNumberish,
Builtins,
Expand All @@ -27,14 +35,13 @@ import { encodeShortString } from './shortString';
export * as poseidon from '@noble/curves/abstract/poseidon';
export * from './selector'; // Preserve legacy export structure

export const transactionVersion = 1n;
export const transactionVersion_2 = 2n;
// TODO: check do we need to use feeTransactionVersion at all for feeEstimation ?
export const feeTransactionVersion = 2n ** 128n + transactionVersion;
export const feeTransactionVersion_2 = 2n ** 128n + transactionVersion_2;
export const transactionVersion = BN_TRANSACTION_VERSION_1;
export const transactionVersion_2 = BN_TRANSACTION_VERSION_2;
export const feeTransactionVersion = BN_FEE_TRANSACTION_VERSION_1;
export const feeTransactionVersion_2 = BN_FEE_TRANSACTION_VERSION_2;

/**
* Return versions based on version type, default transaction versions
* Return transaction versions based on version type, default version type is 'transaction'
* @param versionType 'fee' | 'transaction'
* @returns versions { v1: bigint; v2: bigint; }
*/
Expand All @@ -44,15 +51,30 @@ export function getVersionsByType(versionType?: 'fee' | 'transaction') {
: { v1: transactionVersion, v2: transactionVersion_2 };
}

/**
* Compute pedersen hash from data
* @param data BigNumberish[]
* @returns hex-string - pedersen hash
*/
export function computeHashOnElements(data: BigNumberish[]): string {
return [...data, data.length]
.reduce((x: BigNumberish, y: BigNumberish) => starkCurve.pedersen(toBigInt(x), toBigInt(y)), 0)
.toString();
}

// following implementation is based on this python implementation:
// https://github.com/starkware-libs/cairo-lang/blob/b614d1867c64f3fb2cf4a4879348cfcf87c3a5a7/src/starkware/starknet/core/os/transaction_hash/transaction_hash.py

/**
* Calculate transaction pedersen hash for common properties
* following implementation is based on this python implementation: https://github.com/starkware-libs/cairo-lang/blob/b614d1867c64f3fb2cf4a4879348cfcf87c3a5a7/src/starkware/starknet/core/os/transaction_hash/transaction_hash.py
* @param txHashPrefix TransactionHashPrefix
* @param version BigNumberish
* @param contractAddress BigNumberish
* @param entryPointSelector BigNumberish
* @param calldata RawCalldata
* @param maxFee BigNumberish
* @param chainId StarknetChainId
* @param additionalData BigNumberish[]
* @returns hex-string
*/
export function calculateTransactionHashCommon(
txHashPrefix: TransactionHashPrefix,
version: BigNumberish,
Expand All @@ -77,6 +99,15 @@ export function calculateTransactionHashCommon(
return computeHashOnElements(dataToHash);
}

/**
* Calculate deploy transaction hash
* @param contractAddress BigNumberish
* @param constructorCalldata RawCalldata
* @param version BigNumberish
* @param chainId StarknetChainId
* @param constructorName string
* @returns hex-string
*/
export function calculateDeployTransactionHash(
contractAddress: BigNumberish,
constructorCalldata: RawCalldata,
Expand All @@ -95,6 +126,17 @@ export function calculateDeployTransactionHash(
);
}

/**
* Calculate declare transaction hash
* @param classHash hex-string
* @param senderAddress BigNumberish
* @param version BigNumberish
* @param maxFee BigNumberish
* @param chainId StarknetChainId
* @param nonce BigNumberish
* @param compiledClassHash hex-string
* @returns hex-string
*/
export function calculateDeclareTransactionHash(
classHash: string,
senderAddress: BigNumberish,
Expand All @@ -116,6 +158,18 @@ export function calculateDeclareTransactionHash(
);
}

/**
* Calculate deploy_account transaction hash
* @param contractAddress BigNumberish
* @param classHash BigNumberish
* @param constructorCalldata RawCalldata
* @param salt BigNumberish
* @param version BigNumberish
* @param maxFee BigNumberish
* @param chainId StarknetChainId
* @param nonce BigNumberish
* @returns hex-string
*/
export function calculateDeployAccountTransactionHash(
contractAddress: BigNumberish,
classHash: BigNumberish,
Expand All @@ -140,6 +194,16 @@ export function calculateDeployAccountTransactionHash(
);
}

/**
* Calculate invoke transaction hash
* @param contractAddress BigNumberish
* @param version BigNumberish
* @param calldata RawCalldata
* @param maxFee BigNumberish
* @param chainId StarknetChainId
* @param nonce BigNumberish
* @returns hex-string
*/
export function calculateTransactionHash(
contractAddress: BigNumberish,
version: BigNumberish,
Expand All @@ -160,6 +224,14 @@ export function calculateTransactionHash(
);
}

/**
* Calculate contract address from class hash
* @param salt BigNumberish
* @param classHash BigNumberish
* @param constructorCalldata RawArgs
* @param deployerAddress BigNumberish
* @returns hex-string
*/
export function calculateContractAddressFromHash(
salt: BigNumberish,
classHash: BigNumberish,
Expand Down Expand Up @@ -192,7 +264,11 @@ function nullSkipReplacer(key: string, value: any) {
return value === null ? undefined : value;
}

// about 10x to 100x faster using array to build string
/**
* Format json-string to conform starknet json-string
* @param json json-string
* @returns json-string
*/
export function formatSpaces(json: string) {
let insideQuotes = false;
const newString = [];
Expand All @@ -211,6 +287,11 @@ export function formatSpaces(json: string) {
return newString.join('');
}

/**
* Compute hinted class hash for legacy compiled contract (Cairo 0)
* @param compiledContract LegacyCompiledContract
* @returns hex-string
*/
export default function computeHintedClassHash(compiledContract: LegacyCompiledContract) {
const { abi, program } = compiledContract;
const contractClass = { abi, program };
Expand All @@ -219,7 +300,11 @@ export default function computeHintedClassHash(compiledContract: LegacyCompiledC
return addHexPrefix(starkCurve.keccak(utf8ToArray(serializedJson)).toString(16));
}

// Computes the class hash of a given contract class
/**
* Computes the class hash for legacy compiled contract (Cairo 0)
* @param contract LegacyCompiledContract
* @returns hex-string
*/
export function computeLegacyContractClassHash(contract: LegacyCompiledContract | string) {
const compiledContract =
typeof contract === 'string' ? (parse(contract) as LegacyCompiledContract) : contract;
Expand Down Expand Up @@ -257,7 +342,8 @@ export function computeLegacyContractClassHash(contract: LegacyCompiledContract
]);
}

// Cairo1 below
// Cairo 1 code

function hashBuiltins(builtins: Builtins) {
return poseidonHashMany(
builtins.flatMap((it: any) => {
Expand All @@ -273,6 +359,11 @@ function hashEntryPoint(data: ContractEntryPointFields[]) {
return poseidonHashMany(base);
}

/**
* Compute compiled class hash for contract (Cairo 1)
* @param casm CompiledSierraCasm
* @returns hex-string
*/
export function computeCompiledClassHash(casm: CompiledSierraCasm) {
const COMPILED_CLASS_VERSION = 'COMPILED_CLASS_V1';

Expand Down Expand Up @@ -314,6 +405,11 @@ function hashAbi(sierra: CompiledSierra) {
return BigInt(addHexPrefix(starkCurve.keccak(utf8ToArray(indentString)).toString(16)));
}

/**
* Compute sierra contract class hash (Cairo 1)
* @param sierra CompiledSierra
* @returns hex-string
*/
export function computeSierraContractClassHash(sierra: CompiledSierra) {
const CONTRACT_CLASS_VERSION = 'CONTRACT_CLASS_V0.1.0';

Expand Down Expand Up @@ -350,7 +446,7 @@ export function computeSierraContractClassHash(sierra: CompiledSierra) {
/**
* Compute ClassHash (sierra or legacy) based on provided contract
* @param contract CompiledContract | CompiledSierra | string
* @returns HexString ClassHash
* @returns hex-string ClassHash
*/
export function computeContractClassHash(contract: CompiledContract | string) {
const compiledContract = typeof contract === 'string' ? parse(contract) : contract;
Expand Down
33 changes: 29 additions & 4 deletions src/utils/json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,44 @@
// @ts-ignore
import * as json from 'lossless-json';

/**
* Convert string to number or bigint based on size
* @param x string
* @returns number | bigint
*/
const parseIntAsNumberOrBigInt = (x: string) => {
if (!json.isInteger(x)) return parseFloat(x);
const v = parseInt(x, 10);
return Number.isSafeInteger(v) ? v : BigInt(x);
};
// NOTE: the String() wrapping is used so the behaviour conforms to JSON.parse()
// which can accept simple data types but is not represented in the default typing

/**
* Convert json-string to json-object
* NOTE: the String() wrapping is used so the behavior conforms to JSON.parse()
* which can accept simple data types but is not represented in the default typing
* @param x json-string
* @returns json-object
*/
export const parse = (x: string): any => json.parse(String(x), undefined, parseIntAsNumberOrBigInt);

/**
* Convert json-string to json-object with all numbers as bigint
* @param x json-string
* @returns json-object
*/
export const parseAlwaysAsBig = (x: string): any =>
json.parse(String(x), undefined, json.parseNumberAndBigInt);

// NOTE: the not-null assertion is used so the return type conforms to JSON.stringify()
// which can also return undefined but is not represented in the default typing
/**
* Convert json-object to json-string
* NOTE: the not-null assertion is used so the return type conforms to JSON.stringify()
* which can also return undefined but is not represented in the default typing
* @param value JavaScriptValue
* @param replacer any
* @param space string | number | undefined
* @param numberStringifiers json.NumberStringifier[] | undefined
* @returns json-string
*/
export const stringify = (
value: json.JavaScriptValue,
replacer?: any,
Expand Down
25 changes: 25 additions & 0 deletions src/utils/merkle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export class MerkleTree {
this.root = this.build(leafHashes);
}

/**
* Create Merkle three
* @param leaves hex-string[]
* @returns hex-string - root
*/
private build(leaves: string[]): string {
if (leaves.length === 1) {
return leaves[0];
Expand All @@ -31,11 +36,24 @@ export class MerkleTree {
return this.build(newLeaves);
}

/**
* Create pedersen hash from a and b
* @param a string
* @param b string
* @returns hex-string
*/
static hash(a: string, b: string) {
const [aSorted, bSorted] = [toBigInt(a), toBigInt(b)].sort((x, y) => (x >= y ? 1 : -1));
return starkCurve.pedersen(aSorted, bSorted);
}

/**
* Return path to leaf
* @param leaf hex-string
* @param branch hex-string[]
* @param hashPath hex-string[]
* @returns hex-string[]
*/
public getProof(leaf: string, branch = this.leaves, hashPath: string[] = []): string[] {
const index = branch.indexOf(leaf);
if (index === -1) {
Expand All @@ -60,6 +78,13 @@ export class MerkleTree {
}
}

/**
* Test Merkle tree path
* @param root hex-string
* @param leaf hex-string
* @param path hex-string[]
* @returns boolean
*/
export function proofMerklePath(root: string, leaf: string, path: string[]): boolean {
if (path.length === 0) {
return root === leaf;
Expand Down
Loading

0 comments on commit 08bd45f

Please sign in to comment.