Skip to content

Commit

Permalink
feat: add enums-response as class
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeR26 committed Jul 17, 2023
1 parent 5cb29e7 commit 66b3282
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 41 deletions.
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export * as selector from './utils/selector';
export * from './utils/address';
export * from './utils/url';
export * from './utils/calldata';
export * from './utils/calldata/enum';
export * from './utils/contract';
export * from './utils/events';

Expand Down
3 changes: 3 additions & 0 deletions src/types/cairoEnum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { CairoCustomEnum, CairoOption, CairoResult } from '../utils/calldata/enum';

export type CairoEnum = CairoCustomEnum | CairoOption<Object> | CairoResult<Object, Object>;
19 changes: 1 addition & 18 deletions src/types/contract.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,9 @@
import { CairoEnum } from './cairoEnum';
import { BigNumberish, BlockIdentifier, RawArgsArray, Signature } from './lib';

export type AsyncContractFunction<T = any> = (...args: ArgsOrCalldataWithOptions) => Promise<T>;
export type ContractFunction = (...args: ArgsOrCalldataWithOptions) => any;

export interface CairoCustomEnumInterface {
[key: string]: any;
unwrap: Function;
}
export interface CairoOptionInterface {
[key: string]: any;
unwrap: Function;
isSome: Function;
isNone: Function;
}
export interface CairoResultInterface {
[key: string]: any;
unwrap: Function;
isOK: Function;
isErr: Function;
}
export type CairoEnum = CairoCustomEnumInterface | CairoOptionInterface | CairoResultInterface;

export type Result =
| {
[key: string]: any;
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './typedData';
export * from './api/sequencer';
export * from './api/rpc';
export * from './calldata';
export * from './cairoEnum';
43 changes: 43 additions & 0 deletions src/utils/calldata/enum/CairoCustomEnum.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export type CairoEnumRaw = {
[key: string]: any;
};

/**
* Class to handle Cairo custom Enum
* @param enumContent object containing the variants and its content. Example :
* {Success: 234, Warning: undefined, Error: undefined}.
* Only one variant with a value, object, array.
* @returns an instance representing a Cairo custom Enum.
* @example ```typescript
* const myCairoEnum = new CairoCustomEnum( {Success: undefined, Warning: "0x7f32ea", Error: undefined})
* ```
*/
export class CairoCustomEnum {
/**
* direct readonly access to variants of the Cairo Custom Enum.
* @returns a value of type any
* @example ```typescript
* const successValue = myCairoEnum.variant.Success;
*/
readonly variant: CairoEnumRaw;

constructor(enumContent: CairoEnumRaw) {
// TODO : add checks of validity of enumContent
this.variant = enumContent;
}

/**
*
* @returns the content of the valid variant of a Cairo custom Enum.
*/
public unwrap(): any {
const variants = Object.entries(this.variant);
const activeVariant = variants.find((item) => typeof item[1] !== 'undefined');
if (typeof activeVariant === 'undefined') {
return undefined;
}
return activeVariant[1];
}

// TODO : add function 'activeVariant' -> string
}
59 changes: 59 additions & 0 deletions src/utils/calldata/enum/CairoOption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
export enum CairoOptionVariant {
Some = 0,
None = 1,
}

/**
* Class to handle Cairo Option
* @param variant CairoOptionVariant.Some or CairoOptionVariant.None
* @param someContent value of type T.
* @returns an instance representing a Cairo Option.
* @example ```typescript
* const myOption = new CairoOption<BigNumberish>(CairoOptionVariant.Some, "0x54dda8");
* ```
*/
export class CairoOption<T> {
readonly Some?: T;

readonly None?: boolean;

constructor(variant: CairoOptionVariant, someContent?: T) {
if (variant === CairoOptionVariant.Some) {
if (typeof someContent === 'undefined') {
throw new Error(
'The creation of a Cairo Option with "Some" variant needs a content as input.'
);
}
this.Some = someContent;
}
this.None = true;
}

/**
*
* @returns the content of the valid variant of a Cairo custom Enum.
* If None, returns 'undefined'.
*/
public unwrap(): T | undefined {
if (this.None) {
return undefined;
}
return this.Some;
}

/**
*
* @returns true if the valid variant is 'isSome'.
*/
public isSome(): boolean {
return !(typeof this.Some === 'undefined');
}

/**
*
* @returns true if the valid variant is 'isNone'.
*/
public isNone(): boolean {
return this.None === true;
}
}
56 changes: 56 additions & 0 deletions src/utils/calldata/enum/CairoResult.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export enum CairoResultVariant {
Ok = 0,
Err = 1,
}

/**
* Class to handle Cairo Result
* @param variant CairoResultVariant.Ok or CairoResultVariant.Err
* @param resultContent value of type T or U.
* @returns an instance representing a Cairo Result.
* @example ```typescript
* const myOption = new CairoResult<BigNumberish,CustomError>(CairoResultVariant.Ok, "0x54dda8");
* ```
*/
export class CairoResult<T, U> {
readonly Ok?: T;

readonly Err?: U;

constructor(variant: CairoResultVariant, resultContent: T | U) {
if (variant === CairoResultVariant.Ok) {
this.Ok = resultContent as T;
}
this.Err = resultContent as U;
}

/**
*
* @returns the content of the valid variant of a Cairo Result.
*/
public unwrap(): T | U {
if (typeof this.Ok !== 'undefined') {
return this.Ok;
}
if (typeof this.Err !== 'undefined') {
return this.Err;
}
throw new Error('Both Result.Ok and .Err are undefined. Not authorized.');
}

/**
*
* @returns true if the valid variant is 'Ok'.
*/
public isOk(): boolean {
return !(typeof this.Ok === 'undefined');
}

/**
*
* @returns true if the valid variant is 'isErr'.
*/
public isErr(): boolean {
return !(typeof this.Err === 'undefined');
}
}
3 changes: 3 additions & 0 deletions src/utils/calldata/enum/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './CairoCustomEnum';
export * from './CairoOption';
export * from './CairoResult';
48 changes: 25 additions & 23 deletions src/utils/calldata/responseParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
AbiStructs,
Args,
BigNumberish,
CairoCustomEnum,
CairoEnum,
ParsedStruct,
} from '../../types';
import { uint256ToBN } from '../uint256';
Expand All @@ -19,6 +19,7 @@ import {
isTypeTuple,
isTypeUint256,
} from './cairo';
import { CairoCustomEnum, CairoEnumRaw } from './enum';
import extractTupleMemberTypes from './tuple';

/**
Expand Down Expand Up @@ -56,7 +57,7 @@ function parseResponseValue(
element: { name: string; type: string },
structs: AbiStructs,
enums: AbiEnums
): BigNumberish | ParsedStruct | boolean | any[] {
): BigNumberish | ParsedStruct | boolean | any[] | CairoEnum {
// type uint256 struct (c1v2)
if (isTypeUint256(element.type)) {
const low = responseIterator.next().value;
Expand All @@ -72,9 +73,25 @@ function parseResponseValue(
}, {} as any);
}

// type Enum
// if (element.type in enums && enums[element.type]) {
// }
// type Enum (only CustomEnum)
if (element.type in enums && enums[element.type]) {
const variantNum: number = Number(responseIterator.next().value); // get variant number
const rawEnum = enums[element.type].variants.reduce((acc, variant, num) => {
if (num === variantNum) {
acc[variant.name] = parseResponseValue(
responseIterator,
{ name: '', type: variant.type },
structs,
enums
);
return acc;
}
acc[variant.name] = undefined;
return acc;
}, {} as CairoEnumRaw);
const customEnum = new CairoCustomEnum(rawEnum);
return customEnum;
}

// type tuple
if (isTypeTuple(element.type)) {
Expand All @@ -91,7 +108,7 @@ function parseResponseValue(
// type c1 array
if (isTypeArray(element.type)) {
// eslint-disable-next-line no-case-declarations
const parsedDataArr: (BigNumberish | ParsedStruct | boolean | any[])[] = [];
const parsedDataArr: (BigNumberish | ParsedStruct | boolean | any[] | CairoEnum)[] = [];
const el = { name: '', type: getArrayType(element.type) };
const len = BigInt(responseIterator.next().value); // get length
while (parsedDataArr.length < len) {
Expand Down Expand Up @@ -132,22 +149,7 @@ export default function responseParser(
return parseResponseValue(responseIterator, output, structs, enums);

case isTypeEnum(type, enums):
const variantNum: number = Number(responseIterator.next().value); // get variant number
const myEnum = enums[output.type].variants.reduce((acc, variant, num) => {
if (num === variantNum) {
acc[variant.name] = parseResponseValue(
responseIterator,
{ name: '0', type: variant.type },
structs,
enums
);
return acc;
}
acc[variant.name] = undefined;
return acc;
}, {} as Record<string, any>);
const customEnum: CairoCustomEnum = { ...myEnum, ...unw };
return customEnum;
return parseResponseValue(responseIterator, output, structs, enums);

case isTypeArray(type):
// C1 Array
Expand All @@ -156,7 +158,7 @@ export default function responseParser(
}
// C0 Array
// eslint-disable-next-line no-case-declarations
const parsedDataArr: (BigNumberish | ParsedStruct | boolean | any[])[] = [];
const parsedDataArr: (BigNumberish | ParsedStruct | boolean | any[] | CairoEnum)[] = [];
if (parsedResult && parsedResult[`${name}_len`]) {
const arrLen = parsedResult[`${name}_len`] as number;
while (parsedDataArr.length < arrLen) {
Expand Down

0 comments on commit 66b3282

Please sign in to comment.