Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Added JS Docs Examples for typedDatadocs #1127

Open
wants to merge 10 commits into
base: develop
Choose a base branch
from
230 changes: 225 additions & 5 deletions src/utils/typedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ function getHex(value: BigNumberish): string {
throw new Error(`Invalid BigNumberish: ${value}`);
}
}

/**
ivpavici marked this conversation as resolved.
Show resolved Hide resolved
* Validates that `data` matches the EIP-712 JSON schema.
*/
Expand All @@ -108,6 +107,19 @@ function validateTypedData(data: unknown): data is TypedData {
*
* @param {string} selector - The selector to be prepared.
* @returns {string} The prepared selector.
*
* @example
* ```typescript
* const result1;
* const preparedSelector1 = prepareSelector('0x1');
* result1 = preparedSelector1;
* // result1 = '0x1'
*
* const result2;
* const preparedSelector2 = prepareSelector('myFunction');
* result2 = preparedSelector2;
* // result2 = '0x8bb83e7e'
* ```
*/
export function prepareSelector(selector: string): string {
return isHex(selector) ? selector : getSelectorFromName(selector);
Expand All @@ -117,16 +129,66 @@ export function prepareSelector(selector: string): string {
* Checks if the given Starknet type is a Merkle tree type.
*
* @param {StarknetType} type - The StarkNet type to check.
* @returns {boolean} True if the type is a Merkle tree type, false otherwise.
*
* @example
* ```typescript
* const result1;
* const merkleType = {
* name: 'MerkleTree',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fishonamos we tested your examples and they are wrong... we cannot merge chatGPT generated comments without properly testing

* fields: [
* { name: 'root', type: 'felt' },
* { name: 'leaves', type: 'felt[]' }
* ]
* };
* const isMerkle1 = isMerkleTreeType(merkleType);
* result1 = isMerkle1;
* // result1 = true
*
* @returns {boolean} - True if the type is a Merkle tree type, false otherwise.
* const result2;
* const nonMerkleType = {
* name: 'RegularStruct',
* fields: [
* { name: 'id', type: 'felt' },
* { name: 'value', type: 'felt' }
* ]
* };
* const isMerkle2 = isMerkleTreeType(nonMerkleType);
* result2 = isMerkle2;
* // result2 = false
* ```
*/
export function isMerkleTreeType(type: StarknetType): type is StarknetMerkleType {
return type.type === 'merkletree';
}

/**
* Get the dependencies of a struct type. If a struct has the same dependency multiple times, it's only included once
* in the resulting array.
* Get the dependencies of a struct type. If a struct has the same dependency multiple times, it's only included once in the resulting array.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to get dependencies for.
* @param {string[]} [dependencies=[]] - The array to store dependencies.
* @param {string} [contains=''] - The type contained within the struct.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {string[]} The array of dependencies.
*
* @example
* ```typescript
* const types = {
* MyStruct: [
* { name: 'field1', type: 'felt' },
* { name: 'field2', type: 'AnotherStruct' }
* ],
* AnotherStruct: [
* { name: 'fieldA', type: 'felt' }
* ]
* };
*
* const result;
* const deps = getDependencies(types, 'MyStruct');
* result = deps;
* // result = ['MyStruct', 'AnotherStruct']
* ```
*/
export function getDependencies(
types: TypedData['types'],
Expand Down Expand Up @@ -185,6 +247,31 @@ function getMerkleTreeType(types: TypedData['types'], ctx: Context) {

/**
* Encode a type to a string. All dependent types are alphabetically sorted.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to encode.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {string} The encoded type string.
*
* @example
* ```typescript
* const typedData = {
* types: {
* MyStruct: [
* { name: 'field1', type: 'felt' },
* { name: 'field2', type: 'AnotherStruct' }
* ],
* AnotherStruct: [
* { name: 'fieldA', type: 'felt' }
* ]
* }
* };
*
* const result;
* const encodedType = encodeType(typedData.types, 'MyStruct');
* result = encodedType;
* // result = 'MyStruct(field1:felt,field2:AnotherStruct)'
* ```
*/
export function encodeType(
types: TypedData['types'],
Expand Down Expand Up @@ -230,6 +317,31 @@ export function encodeType(

/**
* Get a type string as hash.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to hash.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {string} The hash of the type string.
*
* @example
* ```typescript
* const typedData = {
* types: {
* MyStruct: [
* { name: 'field1', type: 'felt' },
* { name: 'field2', type: 'AnotherStruct' }
* ],
* AnotherStruct: [
* { name: 'fieldA', type: 'felt' }
* ]
* }
* };
*
* const result;
* const typeHash = getTypeHash(typedData.types, 'MyStruct');
* result = typeHash;
* // result = '0x5f3cfe24eb9cba5f0e80bcacb8b2d8cdccb1c71f9ff71ec7e02a77c0cbe32e61'
* ```
*/
export function getTypeHash(
types: TypedData['types'],
Expand All @@ -240,8 +352,40 @@ export function getTypeHash(
}

/**
* Encodes a single value to an ABI serialisable string, number or Buffer. Returns the data as tuple, which consists of
* Encodes a single value to an ABI serialisable string, number or Buffer. Returns the data as a tuple, which consists of
* an array of ABI compatible types, and an array of corresponding values.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to encode.
* @param {unknown} data - The data to encode.
* @param {Context} [ctx={}] - The context of the encoding process.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {[string, string]} The ABI compatible type and corresponding value.
*
* @example
* ```typescript
* const typedData = {
* types: {
* MyStruct: [
* { name: 'field1', type: 'felt' },
* { name: 'field2', type: 'AnotherStruct' }
* ],
* AnotherStruct: [
* { name: 'fieldA', type: 'felt' }
* ]
* }
* };
*
* const result1;
* const encodedValue1 = encodeValue(typedData.types, 'u256', '12345');
* result1 = encodedValue1;
* // result1 = ['u256', '0x3039']
*
* const result2;
* const encodedValue2 = encodeValue(typedData.types, 'string', 'Hello');
* result2 = encodedValue2;
* // result2 = ['string', '0x48656c6c6f']
* ```
*/
export function encodeValue(
types: TypedData['types'],
Expand Down Expand Up @@ -373,7 +517,43 @@ export function encodeValue(
/**
* Encode the data to an ABI encoded Buffer. The data should be a key -> value object with all the required values.
* All dependent types are automatically encoded.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to encode.
* @param {TypedData['message']} data - The data to encode.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {[string[], string[]]} The ABI compatible types and corresponding values.
*
* @example
* ```typescript
* const typedData = {
* types: {
* MyStruct: [
* { name: 'field1', type: 'felt' },
* { name: 'field2', type: 'AnotherStruct' }
* ],
* AnotherStruct: [
* { name: 'fieldA', type: 'felt' }
* ]
* },
* message: {
* field1: '0x123',
* field2: { fieldA: '0x456' }
* }
* };
*
* const result1;
* const encodedData1 = encodeData(typedData.types, 'MyStruct', typedData.message);
* result1 = encodedData1;
* // result1 = [['felt', 'AnotherStruct'], ['0x123', '0x456']]
*
* const result2;
* const encodedData2 = encodeData(typedData.types, 'AnotherStruct', { fieldA: '0x789' });
* result2 = encodedData2;
* // result2 = [['felt'], ['0x789']]
* ```
*/

export function encodeData<T extends TypedData>(
types: T['types'],
type: string,
Expand Down Expand Up @@ -408,6 +588,20 @@ export function encodeData<T extends TypedData>(
/**
* Get encoded data as a hash. The data should be a key -> value object with all the required values.
* All dependent types are automatically encoded.
*
* @param {TypedData['types']} types - The types object containing all defined types.
* @param {string} type - The name of the type to hash.
* @param {TypedData['message']} data - The data to hash.
* @param {Revision} [revision=Revision.Legacy] - The revision of the TypedData.
* @returns {string} The hash of the encoded data.
*
* @example
* ```typescript
* const structHash = getStructHash(typedData.types, 'MyStruct', typedData.message);
* const result;
* result = structHash;
* // result = '0xabc123...'
* ```
*/
export function getStructHash<T extends TypedData>(
types: T['types'],
Expand All @@ -420,6 +614,32 @@ export function getStructHash<T extends TypedData>(

/**
* Get the SNIP-12 encoded message to sign, from the typedData object.
*
* @param {TypedData} typedData - The TypedData object.
* @param {BigNumberish} account - The account to sign the message.
* @returns {string} The hash of the message to sign.
* @throws Will throw an error if the typedData does not match the JSON schema.
*
* @example
* ```typescript
* const result1;
* try {
* const messageHash1 = getMessageHash(typedData, '0x123');
* result1 = messageHash1;
* } catch (error) {
* result1 = error.message;
* }
* // result1 = '0xabc123...'
*
* const result2;
* try {
* const messageHash2 = getMessageHash(invalidTypedData, '0x123');
* result2 = messageHash2;
* } catch (error) {
* result2 = error.message;
* }
* // result2 = 'Typed data does not match JSON schema'
* ```
*/
export function getMessageHash(typedData: TypedData, account: BigNumberish): string {
if (!validateTypedData(typedData)) {
Expand Down