Repository navigation
feat: format in genlayer js to convert to an object - #107
Conversation
WalkthroughAdds an optional jsonSafeReturn flag to readContract (runtime) and GenLayerClient types; when true, readContract post-processes decoded results with a new toJsonSafeDeep utility that produces JSON-serializable, cycle-safe representations of calldata-related structures. Changes
Sequence Diagram(s)sequenceDiagram
participant Caller
participant Contracts as contracts.readContract
participant Decoder
participant Jsonifier as toJsonSafeDeep
Caller->>Contracts: readContract(args { ..., jsonSafeReturn? })
Contracts->>Decoder: decode(result)
Decoder-->>Contracts: decodedValue
alt jsonSafeReturn = true
Contracts->>Jsonifier: toJsonSafeDeep(decodedValue)
Jsonifier-->>Contracts: jsonSafeValue
Contracts-->>Caller: jsonSafeValue
else jsonSafeReturn = false
Contracts-->>Caller: decodedValue
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (8)
src/utils/jsonifier.ts (5)
52-59: Fix doc drift: Map conversion comment contradicts implementation. Consider exporting a JsonSafe type.
- The comment says “Map: to Array<[key, value]>”, but the code below converts Maps to plain objects. Please align the comment with the actual behavior to avoid confusion for maintainers.
- Also, consider exporting a
JsonSafetype so downstream APIs can reflect the shape whenjsonSafeReturnis enabled.Apply this doc-only change:
-// - Map: to Array<[key, value]> preserving order +// - Map: to a plain object preserving iteration order (keys coerced to strings)Optionally add a JsonSafe type (see related suggestions in types/clients.ts and actions.ts comments).
68-78: Use Number.MAX_SAFE_INTEGER for readability.Functionally correct, but this small change improves clarity and avoids magic numbers.
- const maxSafe = 9007199254740991n; // Number.MAX_SAFE_INTEGER + const maxSafe = BigInt(Number.MAX_SAFE_INTEGER);
92-95: Prefer Array.isArray overinstanceof Arrayfor cross-realm safety.Minor robustness improvement when values may originate from different realms.
- if (value instanceof Array) { + if (Array.isArray(value)) { return value.map((v) => _toJsonSafeDeep(v as CalldataEncodable, seen)); }
63-87: Cycle handling returnsnull; consider an explicit marker for debugging.Returning
nullis safe, but makes it hard to distinguish between “value was null” and “value replaced due to cycle.” Consider returning a sentinel string like"<cycle>"or augmenting with an optional callback hook to observe cycle drops. Not blocking.
117-118: Fallback can leak unsupported types into consumers.If a non-CalldataEncodable sneaks through, returning it “as-is” may reintroduce non-JSON-safe values. Consider either throwing, or stringifying unknown instances as a conservative fallback.
Example conservative fallback:
- return value as any; + try { + return JSON.parse(JSON.stringify(value)); + } catch { + return String(value); + }src/contracts/actions.ts (2)
45-56: Clarify interaction betweenrawReturnandjsonSafeReturn; consider typing it.
- Behavior: when
rawReturnis true, the method returns the raw hex and ignoresjsonSafeReturn. This is sensible; please document this precedence.- Typing: current signature doesn’t reflect the JSON-safe return shape when
jsonSafeReturnis true; downstream TypeScript users won’t get helpful types.Would you like me to update the public docs/JSDoc to state that
jsonSafeReturnis ignored whenrawReturnis true?Type-level suggestion is provided in a follow-up comment for both this file and
src/types/clients.ts.
82-88: Reflect JSON-safe return type and dropas anycasts.Leverage a conditional type parameter for
jsonSafeReturnso callers get accurate types when opting in.Apply this diff to align the function signature and returns. This matches a complementary change in
src/types/clients.ts.- readContract: async <RawReturn extends boolean | undefined>(args: { + readContract: async < + RawReturn extends boolean | undefined, + JsonSafeFlag extends boolean | undefined = undefined + >(args: { account?: Account; address: Address; functionName: string; args?: CalldataEncodable[]; kwargs?: Map<string, CalldataEncodable> | {[key: string]: CalldataEncodable}; rawReturn?: RawReturn; - jsonSafeReturn?: boolean; + jsonSafeReturn?: JsonSafeFlag; leaderOnly?: boolean; transactionHashVariant?: TransactionHashVariant; - }): Promise<RawReturn extends true ? `0x${string}` : CalldataEncodable> => { + }): Promise< + RawReturn extends true + ? `0x${string}` + : JsonSafeFlag extends true + ? import("@/types/json").JsonSafe + : CalldataEncodable + > => { @@ - const decoded = calldata.decode(resultBinary) as any; + const decoded = calldata.decode(resultBinary) as CalldataEncodable; if (!jsonSafeReturn) { return decoded; } // If jsonSafeReturn is requested, convert to JSON-safe recursively - return toJsonSafeDeep(decoded) as any; + return toJsonSafeDeep(decoded);Note: you’ll need to add a type-only import for
JsonSafe:import type { JsonSafe } from "@/types/json";src/types/clients.ts (1)
49-49: Update thereadContracttype to encode JSON-safe return shape.Right now, the return type is always
CalldataEncodablewhenrawReturnis false, but the value is transformed whenjsonSafeReturnis true. Encode this in the type so consumers get accurate intellisense.Apply this diff to refine the generics and the return type:
- readContract: <RawReturn extends boolean | undefined>(args: { + readContract: < + RawReturn extends boolean | undefined, + JsonSafeFlag extends boolean | undefined = undefined + >(args: { account?: Account; address: Address; functionName: string; args?: CalldataEncodable[]; kwargs?: Map<string, CalldataEncodable> | {[key: string]: CalldataEncodable}; rawReturn?: RawReturn; - jsonSafeReturn?: boolean; + jsonSafeReturn?: JsonSafeFlag; transactionHashVariant?: TransactionHashVariant; - }) => Promise<RawReturn extends true ? `0x${string}` : CalldataEncodable>; + }) => Promise< + RawReturn extends true + ? `0x${string}` + : JsonSafeFlag extends true + ? import("@/types/json").JsonSafe + : CalldataEncodable + >;Additionally, add a type-only import for
JsonSafeand define it in a dedicated types module to avoid creating atypes ↔ utilscircular dependency:// at the top (outside of this diff hunk) import type { JsonSafe } from "@/types/json";Create
src/types/json.tswith:export type JsonSafe = | null | boolean | number | string | { [k: string]: JsonSafe } | JsonSafe[];
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
src/contracts/actions.ts(4 hunks)src/types/clients.ts(1 hunks)src/utils/jsonifier.ts(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/contracts/actions.ts (2)
src/abi/index.ts (1)
calldata(4-4)src/utils/jsonifier.ts (1)
toJsonSafeDeep(59-61)
🔇 Additional comments (4)
src/utils/jsonifier.ts (3)
2-4: Correct runtime import for class used withinstanceof.Importing
CalldataAddressas a value (not type-only) is necessary since it’s used withinstanceof. Looks good.
104-106: LGTM on CalldataAddress handling.Returning 0x-hex from
CalldataAddress.bytesaligns with the JSON-safe intent and is consistent with Uint8Array handling.
96-103: I’ve prepared a quick script to verify the Map‐handling code and see howCalldataEncodableis defined (to confirm whether Map keys can only be strings). Once we have those outputs, we can confirm if prototype-pollution safeguards and key‐coercion are needed or if string-only keys are already enforced.Looking forward to the results.
src/contracts/actions.ts (1)
14-14: Import oftoJsonSafeDeepis correct and scoped.Dependency added only where needed. Good separation of concerns.
What
jsonSafeReturn?: booleanoption toreadContract(default false) to return decoded results as JSON-safe objectsjsonSafeReturninGenLayerClient.readContractsignatureWhy
inspectfor logs; we also need an option to return a JSON-safe object for programmatic consumptionTesting done
get_submissionswizard_of_coinandfootball_prediction_marketcontractsUint8ArrayandCalldataAddressrender as 0x-prefixed hexjsonSafeReturn) remains unchangedDecisions made
Uint8Array) and addresses (CalldataAddress) standardized to 0x-hex stringsWeakSetand returnnullwhen a cycle is detectedjsonSafeReturnwith default false to avoid breaking changesChecks
Reviewing tips
src/contracts/actions.ts: newjsonSafeReturnoption and application post-decodesrc/utils/jsonifier.ts:toJsonSafeDeepimplementation and conversion rulessrc/types/clients.ts: updatedreadContractsignatureUser facing release notes
jsonSafeReturnoption toreadContract. When enabled, decoded contract results are returned as JSON-safe objects:Uint8Array/CalldataAddress→ 0x-hex stringsSummary by CodeRabbit