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

[BUG] Handling Option and CustomEnum typescript bindings #2715

Closed
starknetdev opened this issue Nov 23, 2024 · 7 comments
Closed

[BUG] Handling Option and CustomEnum typescript bindings #2715

starknetdev opened this issue Nov 23, 2024 · 7 comments
Labels
bug Something isn't working

Comments

@starknetdev
Copy link
Contributor

Describe the bug
The typescript bindings generated by sozo do not handle Option and Enums with nested data structures. I am working with the dojo.js sdk and trying to plug in the types.

To Reproduce

  • Clone tournament_component
  • run, cd tournaments && cd contracts && sozo build --typescript
  • inspect, contracts/bindings/typescript/models.gen.ts

or find the file here: models.gen.ts

Option

Here is the model that I have defined in my contract:

#[dojo::model]
#[derive(Drop, Serde)]
pub struct TournamentModel {
    #[key]
    pub tournament_id: u64,
    pub name: felt252,
    pub description: ByteArray,
    pub creator: ContractAddress,
    pub start_time: u64,
    pub end_time: u64,
    pub submission_period: u64,
    pub winners_count: u8,
    pub gated_type: Option<GatedType>,
    pub entry_premium: Option<Premium>,
}

The typescript binding generated:

// Type definition for `tournament::ls15_components::models::tournament::TournamentModel` struct
export interface TournamentModel {
  fieldOrder: string[];
  tournament_id: number;
  name: number;
  description: string;
  creator: string;
  start_time: number;
  end_time: number;
  submission_period: number;
  winners_count: number;
  gated_type: Option;
  entry_premium: Option;
}

Option is not a defined interface generated by the models.gen.ts. I recommend that we utilise the class and types provided by starknet.js, so the TournamentModel will looks like this:

import { CairoOption } from "starknet";

// Type definition for `tournament::ls15_components::models::tournament::TournamentModel` struct
export interface TournamentModel {
  fieldOrder: string[];
  tournament_id: number;
  name: number;
  description: string;
  creator: string;
  start_time: number;
  end_time: number;
  submission_period: number;
  winners_count: number;
  gated_type: CairoOption<GatedType>;
  entry_premium: CairoOption<Premium>;
}

An instance of the cairo option is created like so:

import { CairoOption, CairoOptionVariant } from "starknet"

let gated_type = new CairoOption(
  CairoOptionVariant.Some,
  GatedType
);          

CairoCustomEnum

Looking further into this GatedType, this is an enum with nested data structures. Here is the cairo interface:

#[derive(Copy, Drop, Serde, PartialEq, Introspect)]
pub enum GatedType {
    token: GatedToken,
    tournament: Span<u64>,
    address: Span<ContractAddress>,
}

The typescript binding generated is:

// Type definition for `tournament::ls15_components::models::tournament::GatedType` enum
export enum GatedType {
  token,
  tournament,
  address,
}

This is just a basic enum missing the data structures nested within it. starknet.js provides CairoCustomEnum that allows a variant object to be passed with any structure. For better type safety, I have also created an extension that allows generics:

import { CairoCustomEnum} from "starknet";

// Create a typed wrapper for CairoCustomEnum
export type TypedCairoEnum<T> = CairoCustomEnum & {
  variant: { [K in keyof T]: T[K] | undefined };
  unwrap(): T[keyof T];
};

Therefore the full implementation could be:

export type GatedTypeEnum = TypedCairoEnum<GatedType>;

export type GatedType = {
  token?: GatedToken;
  tournament?: number[];
  address?: string[];
};

// Type definition for `tournament::ls15_components::models::tournament::TournamentModel` struct
export interface TournamentModel {
  fieldOrder: string[];
  tournament_id: number;
  name: number;
  description: string;
  creator: string;
  start_time: number;
  end_time: number;
  submission_period: number;
  winners_count: number;
  gated_type: CairoOption<GatedTypeEnum>;
  entry_premium: CairoOption<Premium>;
}

An instance of the custom enum is created like so:

  const gatedTypeEnum = new CairoCustomEnum({
    token: {
      token: selectedToken!,
      entry_type: EntryType
    },
    tournament: undefined,
    address: undefined,
  });

Would also require some playing with the torii graphql types, currently when I query a CairoOption I get a string "None" (if option is provided as variant none). This wouldn't work with the CairoOption type as it would expect { Some: undefined, None: true }.

Please let me know thoughts, if we can get the bindings to work with these more advanced structures it would be greatly appreciated.

@starknetdev starknetdev added the bug Something isn't working label Nov 23, 2024
@starknetdev
Copy link
Contributor Author

starknetdev commented Nov 27, 2024

Having now tested a populated CairoOption enum, torii only provides "Some" from the entity model and misses all data within the option. It would be great to look into supporting this ASAP as it is a fundamental requirement for my project.

@glihm
Copy link
Collaborator

glihm commented Nov 27, 2024

Having now tested a populated CairoOption enum, torii only provides "Some" from the entity model and misses all data within the option. It would be great to look into supporting this ASAP as it is a fundamental requirement for my project.

@MartianGreed do you have an idea if this is happening on the bindgen layer or if it's coming from lower layers?

@MartianGreed
Copy link
Contributor

Can definitely add support for those usecases.

But for the torii returning "Some" I'm not familiar with that part of the codebase and I'm not sure how it's indexed

@starknetdev
Copy link
Contributor Author

@Larkooo Would you be able to advise on the torii side?

@glihm
Copy link
Collaborator

glihm commented Dec 5, 2024

@MartianGreed this is only bindgen side it seems right? Torii is correctly indexing the values. Happy to hop in a call to solve this asap. 👍

@MartianGreed
Copy link
Contributor

PR incoming

@glihm
Copy link
Collaborator

glihm commented Dec 6, 2024

Closed by #2773 please don't hesitate to reopen more specific issues if behavior is not as intended. 👍

@glihm glihm closed this as completed Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants