Skip to content

feat: Investigate and Explore Support for New Wallet API from JSON RPC Specification #515

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

redDwarf03
Copy link
Contributor

@redDwarf03 redDwarf03 commented Apr 29, 2025

This PR suggests to manage issue #490

Notes on Starknet Wallet API Implementation for starknet.dart

1. Objective

The goal was to study the Starknet Wallet API specification (based on wallet_rpc.json) and propose an implementation as a distinct Dart package (wallet_provider), usable within the starknet.dart ecosystem. This package should allow Dart applications to interact with a compatible Starknet wallet.

2. Implementation Approach

  • Dedicated Package: A new package, wallet_provider, was created by duplicating then modifying starknet_provider to isolate the logic specific to the Wallet API.
  • Data Models: Data structures (requests, responses) defined in wallet_rpc.json were implemented in Dart using the freezed package to generate immutable and serializable classes (files in lib/src/model/).
  • Provider Class: A WalletProvider class (lib/src/provider.dart) was created. It exposes typed methods corresponding to the Wallet API RPC calls (wallet_supportedWalletApi, wallet_addInvokeTransaction, etc.).
  • RPC Client: A simple JsonRpcClient was implemented in provider.dart to handle sending JSON-RPC POST requests and basic deserialization of responses and errors.
  • Dependencies: The package depends on package:starknet for fundamental types (Felt) and some shared complex types (EntryPointsByType). It also uses package:http for network calls.
  • Cleanup: Models, providers, and tests related to the standard Starknet JSON-RPC API were removed from the wallet_provider package to focus it solely on the Wallet API.

3. Discoveries and Key Points

  • Wallet API vs. Standard RPC API Distinction: The Wallet API is a distinct set of JSON-RPC methods that does not replace the standard RPC API but complements it for interactions requiring user wallet action or information.
  • Model Generation: The OpenRPC specification (wallet_rpc.json) is structured enough to allow for the generation (here, manually assisted) of type-safe Dart data models using freezed.
  • Dependency on External Types: The implementation heavily relies on types defined in package:starknet (Felt, EntryPointsByType, etc.). Version compatibility and the clarity of exports from this package are crucial.
  • RPC Parameter Ambiguity: The exact expected structure for parameters (params in the JSON-RPC request) is not always explicitly defined in the spec as being a positional list or a single object. The current implementation makes assumptions based on the order and apparent structure in wallet_rpc.json, but this might require adjustments based on actual wallet implementations.
  • signTypedData Complexity: Signing typed data requires careful construction of the TypedData object, especially converting all message and domain values into their corresponding Felt type (short string encoding, integer/hex conversion, etc.) to match the types defined in the types structure.

4. Challenges Encountered

  • Identifying Required Types (ContractClass): There was initial confusion about the origin and correct definition of ContractClass, requiring determination of whether to use a local definition (from the old starknet_provider) or the one from the starknet package. Ultimately, a local definition based on the schema was created.

5. Recommendations

  • Spec Clarification: If possible, encourage clarification in the Wallet API specification regarding the expected structure of params for each method (positional list vs. object).
  • TypedData Utilities: Consider adding utility functions (potentially in package:starknet or wallet_provider) to facilitate the correct construction of TypedData objects, especially for String -> Felt conversion according to EIP-712/Starknet rules.

Summary by CodeRabbit

  • New Features

    • Introduced the wallet_provider Dart package for interacting with Starknet wallets via the Wallet API.
    • Provides a strongly typed Dart client supporting wallet actions such as account access, transaction signing and submission, network management, and asset watching.
    • Includes comprehensive data models for transactions, assets, permissions, errors, and typed data.
    • Offers example usage and detailed documentation.
  • Documentation

    • Added README, changelog, implementation notes, and license files for clear guidance and transparency.
  • Tests

    • Added unit and integration tests to verify provider functionality and ensure robust error handling.
  • Chores

    • Added configuration files for analysis, build, tool versions, and package management.

Copy link

docs-page bot commented Apr 29, 2025

To view this pull requests documentation preview, visit the following URL:

docs.page/focustree/starknet.dart~515

Documentation is deployed and generated using docs.page.

Copy link
Contributor

coderabbitai bot commented Apr 29, 2025

"""

Walkthrough

This change introduces a new Dart package, wallet_provider, designed for interacting with Starknet wallets via the Starknet Wallet API JSON-RPC specification. The package includes all necessary configuration files, core provider/client implementations, comprehensive data models for wallet operations, and extensive generated code for immutability and serialization using the freezed package. Documentation and example usage are provided, along with initial tests for provider methods. The package is structured for strong type safety, clear separation from standard Starknet JSON-RPC APIs, and follows Dart's recommended practices for dependencies and code generation.

Changes

File(s) / Path(s) Change Summary
.gitignore, .tool-versions, CHANGELOG.md, LICENSE, README.md, analysis_options.yaml, build.yaml, dart_test.yaml, pubspec.yaml Added standard configuration, documentation, and metadata files for the Dart package, including versioning, linting, build options, license, and changelog.
Implementation_notes.md Added design and development notes explaining the package's architecture, use of code generation, API distinctions, and recommendations for future improvements.
example/wallet_provider_example.dart Added a comprehensive example demonstrating how to use the WalletProvider to interact with a Starknet wallet, including account requests, transaction submission, and typed data signing.
test/melos_test.dart, test/provider_test.dart Added initial test files: one placeholder to satisfy tool requirements, and one that tests provider methods against a Starknet node, checking for correct error handling and expected responses.
lib/wallet_provider.dart, lib/src/index.dart, lib/src/model/index.dart Introduced main library entry points and consolidated exports for the provider and all data models, allowing for organized and simple imports.
lib/src/provider.dart Implemented the WalletProvider class and a supporting JsonRpcClient, providing typed, asynchronous methods for all wallet API operations, with error handling and resource management.
lib/src/model/account_deployment_data.dart, add_declare_transaction_result.dart, add_invoke_transaction_result.dart, api_version.dart, asset.dart, contract_class.dart, declare_txn_wallet.dart, deployment_version.dart, invoke_call.dart, permission.dart, starknet_chain.dart, typed_data.dart, wallet_error.dart Defined all core data models for the wallet API, including account deployment, transaction results, asset and contract representations, permissions, chain info, typed data for signing, and structured wallet error handling.
lib/src/model/.freezed.dart, lib/src/model/.g.dart Generated code for all models using the freezed and json_serializable packages, providing immutability, value equality, copy-with, and JSON serialization/deserialization for all data structures.

Sequence Diagram(s)

sequenceDiagram
    participant App as Dapp/Client
    participant Provider as WalletProvider
    participant RPC as JsonRpcClient
    participant Wallet as Starknet Wallet (via HTTP)

    App->>Provider: Call wallet method (e.g., requestAccounts)
    Provider->>RPC: call(method, params)
    RPC->>Wallet: HTTP POST (JSON-RPC)
    Wallet-->>RPC: JSON-RPC response
    RPC-->>Provider: Parse result or throw WalletError
    Provider-->>App: Return typed result or error
Loading

Possibly related issues

Suggested reviewers

  • ptisserand

Poem

In the warren of code, a wallet appears,
With models and types, it conquers our fears.
JSON-RPC hopping, requests sent with care,
Dart and Freezed magic are floating in air.
Now Starknet is open, with safety and pride—
The rabbit approves, with a binky and glide!
🐇✨
"""


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c8dfdac and eab5e28.

📒 Files selected for processing (2)
  • packages/wallet_provider/example/wallet_provider_example.dart (1 hunks)
  • packages/wallet_provider/lib/wallet_provider.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/wallet_provider/lib/wallet_provider.dart
  • packages/wallet_provider/example/wallet_provider_example.dart
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: test-integration

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🔭 Outside diff range comments (2)
packages/wallet_provider/dart_test.yaml (1)

1-3: ⚠️ Potential issue

Critical: Define test file patterns for unit tag
Currently the unit tag has no associated file patterns, so tests won’t be discovered or executed under this tag. Add patterns to specify which files are considered unit tests.

Apply this diff to fix the configuration:

-tags:
-  unit:
+tags:
+  unit:
+    - 'test/**_test.dart'
packages/wallet_provider/Implementation_notes.md (1)

30-32: 🛠️ Refactor suggestion

Expand recommendations with security considerations

The recommendations section should include security considerations for using the Wallet API, especially regarding transaction signing and user interactions.

## 5. Recommendations

*   **Spec Clarification:** If possible, encourage clarification in the Wallet API specification regarding the expected structure of `params` for each method (positional list vs. object).
*   **`TypedData` Utilities:** Consider adding utility functions (potentially in `package:starknet` or `wallet_provider`) to facilitate the correct construction of `TypedData` objects, especially for String -> Felt conversion according to EIP-712/Starknet rules.
+*   **Security Guidelines:** Provide security guidelines for dApp developers using this package, including:
+    - Proper validation of transaction parameters before sending to wallets
+    - User confirmation UI/UX best practices
+    - Handling of sensitive data (e.g., avoiding logging of transaction details)
+    - HTTPS enforcement for all wallet API communications
+*   **Error Handling Patterns:** Document recommended error handling patterns for common failure scenarios:
+    - User rejected transactions
+    - Network failures
+    - Wallet disconnection
+    - Unsupported methods
+*   **Rate Limiting:** Consider implementing rate limiting for wallet API requests to prevent abuse and excessive prompts to users.
🧹 Nitpick comments (24)
packages/wallet_provider/.gitignore (1)

1-4: Dart ignore configuration is correct
The header comments reference Dart’s private-files guidelines, and excluding .dart_tool/ prevents committing transient tool state.

Consider also ignoring other generated artifacts such as the .packages file, the build/ directory, and any IDE-specific folders (e.g., .idea/, *.iml) to keep the repository clean.

packages/wallet_provider/.tool-versions (1)

1-1: Ensure Tool Versions Are Consistent Across the Project
Pinning starknet-devnet 0.1.2 here guarantees a stable devnet environment, but it’s unclear whether your Dart SDK (and potential Flutter SDK) versions are managed in a parent .tool-versions. Without a specified Dart version, contributors might end up on incompatible SDKs.

  • Verify that the Dart (and Flutter, if applicable) SDK versions are defined elsewhere (e.g., the repo root).
  • Optionally, add them here or include a comment header explaining this file’s scope.
packages/wallet_provider/lib/src/model/permission.dart (1)

1-5: Annotate enum for JSON serialization
To ensure Permission values are correctly serialized/deserialized in snake_case (per build.yaml), add the json_annotation decorator before the enum. For example:

import 'package:json_annotation/json_annotation.dart';

@JsonEnum(fieldRename: FieldRename.snake)
enum Permission {
  accounts,
}
packages/wallet_provider/lib/src/model/invoke_call.dart (1)

14-16: Implement default for optional calldata
The TODO suggests defaulting calldata to an empty list, but the field is currently nullable. Consider using Freezed’s @Default(<Felt>[]) or @JsonKey(defaultValue: []) to enforce a non-null default and simplify downstream usage.

packages/wallet_provider/lib/src/model/contract_class.g.dart (1)

9-26: Duplication observed between contract class implementations.

The ContractClassImpl and SierraContractClassImpl serialization methods (lines 9-26 and 28-47) are identical. This suggests either:

  1. They're meant to be distinct but currently share the same structure
  2. One class should be a type alias of the other

If these are meant to be the same structure with different names for semantic purposes, consider using a type alias or inheritance to reduce code duplication:

// In contract_class.dart:
typedef SierraContractClass = ContractClass;

This would simplify maintenance and reduce the generated code size.

packages/wallet_provider/lib/src/model/typed_data.dart (1)

11-24: Consider adding example usage for TypedData construction.

This is a complex data structure that developers might struggle to construct correctly, especially with the dynamic typing in StarknetType.

Add documentation with an example or create a builder pattern to simplify construction:

// Example method to add to TypedData class
static TypedData example() {
  return TypedData(
    types: {
      'Person': [
        {'name': 'name', 'type': 'felt'},
        {'name': 'wallet', 'type': 'felt'},
      ],
    },
    primaryType: 'Person',
    domain: StarknetDomain(name: Felt.fromHex('0x01')),
    message: {'name': Felt.fromHex('0x01'), 'wallet': Felt.fromHex('0x02')},
  );
}
packages/wallet_provider/lib/src/model/starknet_chain.dart (2)

18-23: Implement URL fields using Uri instead of String.

As noted in your TODOs, using Uri would provide better validation and functionality for URL handling.

Consider implementing this improvement:

-    @JsonKey(name: 'rpc_urls')
-    List<String>? rpcUrls, // TODO: Should be List<Uri>?
+    @JsonKey(name: 'rpc_urls', fromJson: _uriListFromJson, toJson: _uriListToJson)
+    List<Uri>? rpcUrls,
-    @JsonKey(name: 'block_explorer_url')
-    List<String>? blockExplorerUrl, // TODO: Should be List<Uri>?
+    @JsonKey(name: 'block_explorer_url', fromJson: _uriListFromJson, toJson: _uriListToJson)
+    List<Uri>? blockExplorerUrl,
-    @JsonKey(name: 'icon_urls')
-    List<String>? iconUrls, // TODO: Should be List<Uri>?
+    @JsonKey(name: 'icon_urls', fromJson: _uriListFromJson, toJson: _uriListToJson)
+    List<Uri>? iconUrls,

And add these utility methods:

List<Uri>? _uriListFromJson(List<dynamic>? list) =>
    list?.map((e) => Uri.parse(e.toString())).toList();

List<String>? _uriListToJson(List<Uri>? list) =>
    list?.map((e) => e.toString()).toList();

10-28: Add helper methods for common Starknet chains.

Creating method for common chains would improve developer experience and reduce errors.

Consider adding factory constructors:

// Add to StarknetChain class
factory StarknetChain.mainnet() {
  return StarknetChain(
    id: 'SN_MAIN',
    chainId: Felt.fromHex('0x534e5f4d41494e'),
    chainName: 'Starknet Mainnet',
    rpcUrls: ['https://alpha-mainnet.starknet.io'],
    blockExplorerUrl: ['https://voyager.online'],
    // Add other fields as needed
  );
}

factory StarknetChain.testnet() {
  // Similar implementation for testnet
}
packages/wallet_provider/lib/src/model/account_deployment_data.dart (3)

8-10: Fix typo in class documentation.

The description contains a grammatical error.

-/// Description: Data required to deploy an account at and address
+/// Description: Data required to deploy an account at an address

11-23: Add documentation for individual fields.

The class has several fields that would benefit from more detailed explanations, especially for developers unfamiliar with Starknet account deployment.

Consider adding field-level documentation:

const factory AccountDeploymentData({
  /// The Starknet address where the account will be deployed
  required Felt address,
  
  /// Hash of the account contract class to deploy
  @JsonKey(name: 'class_hash') required Felt classHash,
  
  /// Random value used to derive the account address
  required Felt salt,
  
  /// Constructor arguments for the account contract
  required List<Felt> calldata,
  
  /// Optional signature data for verification
  List<Felt>? sigdata,
  
  /// Indicates the Cairo version of the contract
  required DeploymentVersion version,
}) = _AccountDeploymentData;

11-23: Consider adding validation for account deployment data.

Account deployment is a critical operation, and ensuring data correctness is important.

Consider adding a validation method:

// Add to the AccountDeploymentData class
bool validate() {
  // Check if address is non-zero
  if (address == Felt.zero) {
    return false;
  }
  
  // Check if classHash is non-zero
  if (classHash == Felt.zero) {
    return false;
  }
  
  // Add more validation as needed
  return true;
}
packages/wallet_provider/example/wallet_provider_example.dart (3)

63-67: Consider adding more robust chain switching logic.

The chain ID validation is good, but consider extending this with actual chain switching functionality.

if (chainId != sepoliaChainId) {
  print('Warning: Connected to an unexpected chain ID!');
  // Potentially try to switch chain using provider.switchStarknetChain(sepoliaChainId)
+  // Example chain switching logic:
+  try {
+    await provider.switchStarknetChain(sepoliaChainId);
+    print('Successfully switched to Sepolia');
+  } catch (e) {
+    print('Failed to switch chains: $e');
+    print('Please switch to Sepolia manually in your wallet');
+  }
}

84-97: Consider extracting complex parameter objects to variables.

The InvokeCall construction with nested parameters could be more readable if the parameters were extracted to variables.

try {
+  // Define recipient address
+  final recipientAddress = felt(
+      '0x01234567890abcdef1234567890abcdef1234567890abcdef1234567890abcde');
+      
+  // Define token amount (1 token with 18 decimals)
+  final amountLowPart = felt('0xDE0B6B3A7640000'); // 1 * 10^18
+  final amountHighPart = felt('0x0'); // High part is 0
+  
  final calls = [
    InvokeCall(
        // Replace with a known contract address on Sepolia (e.g., an ERC20 contract)
        contractAddress: felt(
            '0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7'),
        entryPoint: 'transfer', // Assuming ERC20 transfer
-        calldata: [
-          // Replace with a valid recipient address on Sepolia
-          felt(
-              '0x01234567890abcdef1234567890abcdef1234567890abcdef1234567890abcde'),
-          // Replace with actual amount low/high parts (e.g., 1 token with 18 decimals)
-          felt('0xDE0B6B3A7640000'), // 1 * 10^18
-          felt('0x0'), // High part is 0
-        ])
+        calldata: [recipientAddress, amountLowPart, amountHighPart])
  ];

114-148: Consider extracting the TypedData example to a separate helper function.

The TypedData construction is complex and could be extracted to improve readability.

try {
  print('Preparing typed data...');
-  final typedData = TypedData(
-      types: {
-        "StarknetDomain": [
-          {"name": "name", "type": "shortstring"},
-          {"name": "version", "type": "felt"},
-          {"name": "chainId", "type": "felt"},
-        ],
-        "Person": [
-          {"name": "name", "type": "shortstring"},
-          {"name": "wallet", "type": "felt"}
-        ],
-        "Mail": [
-          {"name": "from", "type": "Person"},
-          {"name": "to", "type": "Person"},
-          {"name": "contents", "type": "shortstring"}
-        ]
-      },
-      primaryType: "Mail",
-      domain: StarknetDomain(
-          name: Felt.fromString("Example DApp"),
-          version: Felt.fromInt(1),
-          chainId: sepoliaChainId),
-      message: {
-        "from": {
-          "name": Felt.fromString("Alice"),
-          "wallet": felt(
-              "0x0111111111111111111111111111111111111111111111111111111111111111")
-        },
-        "to": {
-          "name": Felt.fromString("Bob"),
-          "wallet": felt(
-              "0x0222222222222222222222222222222222222222222222222222222222222222")
-        },
-        "contents": Felt.fromString("Hello Bob!")
-      });
+  final typedData = createExampleTypedData(sepoliaChainId);

  print('Requesting signature...');
  final signature = await provider.signTypedData(typedData);
  print('Data signed. Signature: $signature');
} catch (e) {
  print('Error signing typed data: $e');
}

// Add this helper function at the end of the file
+ TypedData createExampleTypedData(Felt chainId) {
+   return TypedData(
+     types: {
+       "StarknetDomain": [
+         {"name": "name", "type": "shortstring"},
+         {"name": "version", "type": "felt"},
+         {"name": "chainId", "type": "felt"},
+       ],
+       "Person": [
+         {"name": "name", "type": "shortstring"},
+         {"name": "wallet", "type": "felt"}
+       ],
+       "Mail": [
+         {"name": "from", "type": "Person"},
+         {"name": "to", "type": "Person"},
+         {"name": "contents", "type": "shortstring"}
+       ]
+     },
+     primaryType: "Mail",
+     domain: StarknetDomain(
+       name: Felt.fromString("Example DApp"),
+       version: Felt.fromInt(1),
+       chainId: chainId),
+     message: {
+       "from": {
+         "name": Felt.fromString("Alice"),
+         "wallet": felt(
+             "0x0111111111111111111111111111111111111111111111111111111111111111")
+       },
+       "to": {
+         "name": Felt.fromString("Bob"),
+         "wallet": felt(
+             "0x0222222222222222222222222222222222222222222222222222222222222222")
+       },
+       "contents": Felt.fromString("Hello Bob!")
+     }
+   );
+ }
packages/wallet_provider/lib/src/model/asset.dart (1)

23-25: Add validation for TOKEN_SYMBOL constraints

The comment indicates that TOKEN_SYMBOL constraints aren't enforced by the type system. Consider adding validation logic to ensure symbols follow standard conventions.

// Example validation method that could be added:
factory AssetOptions.validated({
  required Felt address,
  String? symbol,
  num? decimals,
  String? image,
  String? name,
}) {
  if (symbol != null) {
    // Validate symbol (e.g., length, allowed characters)
    if (symbol.length > 11 || !RegExp(r'^[A-Z0-9.]+$').hasMatch(symbol)) {
      throw ArgumentError('Invalid TOKEN_SYMBOL format');
    }
  }
  return AssetOptions(
    address: address,
    symbol: symbol,
    decimals: decimals,
    image: image != null ? Uri.parse(image) : null,
    name: name,
  );
}
packages/wallet_provider/test/provider_test.dart (1)

6-9: Improve test environment configuration

The test setup uses a hardcoded fallback endpoint. Consider adding a more explicit configuration mechanism.

- final testUri = Uri.parse(Platform.environment['STARKNET_RPC'] ??
-    'https://free-rpc.nethermind.io/sepolia-juno');
+ // Define supported networks and their endpoints
+ const supportedNetworks = {
+   'sepolia': 'https://free-rpc.nethermind.io/sepolia-juno',
+   'mainnet': 'https://rpc.starknet.rs/mainnet',
+ };
+ 
+ // Default to sepolia test network if not specified
+ final network = Platform.environment['STARKNET_NETWORK'] ?? 'sepolia';
+ final testUri = Uri.parse(Platform.environment['STARKNET_RPC'] ?? 
+    supportedNetworks[network] ?? supportedNetworks['sepolia']!);
packages/wallet_provider/Implementation_notes.md (1)

18-23: Add examples to clarify key points

The key points section would benefit from concrete examples, especially for the more complex topics like parameter ambiguity and TypedData construction.

## 3. Discoveries and Key Points

*   **Wallet API vs. Standard RPC API Distinction:** The Wallet API is a distinct set of JSON-RPC methods that does not replace the standard RPC API but complements it for interactions requiring user wallet action or information.
*   **Model Generation:** The OpenRPC specification (`wallet_rpc.json`) is structured enough to allow for the generation (here, manually assisted) of type-safe Dart data models using `freezed`.
*   **Dependency on External Types:** The implementation heavily relies on types defined in `package:starknet` (`Felt`, `EntryPointsByType`, etc.). Version compatibility and the clarity of exports from this package are crucial.
*   **RPC Parameter Ambiguity:** The exact expected structure for parameters (`params` in the JSON-RPC request) is not always explicitly defined in the spec as being a positional list or a single object. The current implementation makes assumptions based on the order and apparent structure in `wallet_rpc.json`, but this might require adjustments based on actual wallet implementations.
+    **Example:**
+    ```dart
+    // Option 1: Parameters as positional list
+    final params = [accountAddress, calls, maxFee];
+    
+    // Option 2: Parameters as named object
+    final params = {
+      'account_address': accountAddress,
+      'calls': calls,
+      'max_fee': maxFee,
+    };
+    ```
*   **`signTypedData` Complexity:** Signing typed data requires careful construction of the `TypedData` object, especially converting all message and domain values into their corresponding `Felt` type (short string encoding, integer/hex conversion, etc.) to match the types defined in the `types` structure.
+    **Example:**
+    ```dart
+    final typedData = TypedData(
+      types: {
+        'StarkNetDomain': [
+          TypeMember(name: 'name', type: 'string'),
+          TypeMember(name: 'version', type: 'felt'),
+          TypeMember(name: 'chainId', type: 'felt'),
+        ],
+        'Message': [
+          TypeMember(name: 'sender', type: 'felt'),
+          TypeMember(name: 'amount', type: 'felt'),
+        ],
+      },
+      primaryType: 'Message',
+      domain: {
+        'name': shortStringFelt('My dApp'),
+        'version': Felt.fromInt(1),
+        'chainId': Felt.fromHexString('0x534e5f474f45524c49'),
+      },
+      message: {
+        'sender': Felt.fromHexString('0x123...'),
+        'amount': Felt.fromInt(1000),
+      },
+    );
+    ```
packages/wallet_provider/lib/src/model/contract_class.dart (1)

18-37: Duplicate data classes risk divergence

ContractClass and SierraContractClass contain the exact same fields. Maintaining both guarantees future drift (e.g. when you later add an abiHash field and forget one side). Prefer a single canonical representation to keep the public surface small and coherent.

If you really need two aliases, let one extend the other or use a typedef, but avoid duplicating Freezed classes.

packages/wallet_provider/lib/src/model/wallet_error.dart (2)

19-25: Optimize the knownErrorCode getter implementation.

The current implementation uses a try-catch block to handle the potential exception when no matching error code is found. This approach is less efficient than using a direct lookup or a more functional approach.

Consider refactoring to use a more efficient lookup:

WalletErrorCode? get knownErrorCode {
-  try {
-    return WalletErrorCode.values.firstWhere((e) => e.code == code);
-  } catch (_) {
-    return null; // Not found
-  }
+  return WalletErrorCode.values.cast<WalletErrorCode?>().firstWhere(
+    (e) => e?.code == code,
+    orElse: () => null,
+  );
}

Or even more concisely:

WalletErrorCode? get knownErrorCode =>
    WalletErrorCode.values.where((e) => e.code == code).firstOrNull;

73-99: Simplify the code getter in WalletErrorCode.

The code getter implementation is verbose with a switch statement mapping each enum value to its integer code. Since you're already using @JsonValue annotations, you could potentially leverage them directly.

If possible, consider a more concise implementation:

// Option 1: Create a static map for lookup
static final Map<WalletErrorCode, int> _codes = {
  WalletErrorCode.notERC20: 111,
  WalletErrorCode.unlistedNetwork: 112,
  // ... and so on
};

int get code => _codes[this]!;

// Option 2: If working with Dart 3.0+, you could consider using enhanced enums
// with fields for the code value

The comments in the code suggest that directly accessing the JsonValue annotation would be ideal but might not be possible, so one of these alternatives could be cleaner.

packages/wallet_provider/README.md (2)

1-5: Convert bare URL to Markdown link

A bare URL can break automatic link detection and violates MD034.
Replace with bracketed Markdown syntax:

-This package is based on the official JSON-RPC specification available at: https://github.com/starkware-libs/starknet-specs/tree/master/wallet-api
+This package is based on the official JSON-RPC specification available at:  
+[Starknet Wallet-API specification](https://github.com/starkware-libs/starknet-specs/tree/master/wallet-api)
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

3-3: Bare URL used
null

(MD034, no-bare-urls)


11-27: Fix unordered-list indentation

The list is indented with four spaces instead of two, tripping MD007.
Indent by two spaces to restore standard Markdown rendering.

-*   **Information & Permissions:**
-    *   `supportedWalletApi()`: …
+* **Information & Permissions:**
+  * `supportedWalletApi()`: …

(and similarly for the rest of the nested items)

🧰 Tools
🪛 LanguageTool

[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...API versions. * supportedSpecs(): Get supported Starknet JSON-RPC spec ve...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~14-~14: Loose punctuation mark.
Context: ...pec versions. * getPermissions(): Get existing permissions for the Dapp. ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...or the Dapp. * requestAccounts(): Request wallet account addresses. *...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nt addresses. * requestChainId(): Request the current chain ID from the w...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...account. * switchStarknetChain(): Request to switch the wallet's active S...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...et network. * addStarknetChain(): Request to add a new Starknet network c...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~21-~21: Loose punctuation mark.
Context: ...on to the wallet. * watchAsset(): Request to add an ERC20 token to the wa...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...ction. * addDeclareTransaction(): Request the wallet to sign and submit a...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

12-12: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


13-13: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


14-14: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


15-15: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


18-18: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


19-19: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


21-21: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


23-23: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


24-24: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


26-26: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

packages/wallet_provider/lib/src/provider.dart (2)

85-100: Avoid print in library code – use logger or propagate the error

Using print inside a package leaks to stdout in production apps and is hard to intercept in tests. Consider:

-            print('Warning: Unknown permission received: $p');
+            // Replace with your preferred logging mechanism
+            // log.warning('Unknown permission received from wallet: $p');

(or throw if strictness is required)


142-153: Parameter packing for wallet_switchStarknetChain is brittle

Relying on positional placeholders (null) can break if the spec adds or re-orders parameters. The spec examples also allow passing a single object.

Simpler & safer approach:

-    // Sticking to pure positional: [chainId, silent_mode?, api_version?]
-    final List<dynamic> methodParams = [chainId.toHexString()];
-    // Only add subsequent parameters if they are provided
-    if (silentMode != null) {
-      methodParams.add(silentMode);
-      if (apiVersion != null) {
-        methodParams.add(apiVersion);
-      }
-    } else if (apiVersion != null) {
-      methodParams.add(null); // Add placeholder for silent_mode
-      methodParams.add(apiVersion);
-    }
+    final methodParams = [
+      {
+        'chain_id': chainId.toHexString(),
+        if (silentMode != null) 'silent_mode': silentMode,
+        if (apiVersion != null) 'api_version': apiVersion,
+      }
+    ];

This follows the “single object” style used by many Wallet-API examples and avoids positional confusion. Confirm with the spec & wallet implementation before merging.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f2457b5 and 1100a33.

📒 Files selected for processing (50)
  • packages/wallet_provider/.gitignore (1 hunks)
  • packages/wallet_provider/.tool-versions (1 hunks)
  • packages/wallet_provider/CHANGELOG.md (1 hunks)
  • packages/wallet_provider/Implementation_notes.md (1 hunks)
  • packages/wallet_provider/LICENSE (1 hunks)
  • packages/wallet_provider/README.md (1 hunks)
  • packages/wallet_provider/analysis_options.yaml (1 hunks)
  • packages/wallet_provider/build.yaml (1 hunks)
  • packages/wallet_provider/dart_test.yaml (1 hunks)
  • packages/wallet_provider/example/wallet_provider_example.dart (1 hunks)
  • packages/wallet_provider/lib/src/index.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/api_version.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/deployment_version.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/index.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/permission.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/provider.dart (1 hunks)
  • packages/wallet_provider/lib/wallet_provider.dart (1 hunks)
  • packages/wallet_provider/pubspec.yaml (1 hunks)
  • packages/wallet_provider/test/melos_test.dart (1 hunks)
  • packages/wallet_provider/test/provider_test.dart (1 hunks)
🧰 Additional context used
🪛 LanguageTool
packages/wallet_provider/README.md

[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...API versions. * supportedSpecs(): Get supported Starknet JSON-RPC spec ve...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~14-~14: Loose punctuation mark.
Context: ...pec versions. * getPermissions(): Get existing permissions for the Dapp. ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...or the Dapp. * requestAccounts(): Request wallet account addresses. *...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nt addresses. * requestChainId(): Request the current chain ID from the w...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...account. * switchStarknetChain(): Request to switch the wallet's active S...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...et network. * addStarknetChain(): Request to add a new Starknet network c...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~21-~21: Loose punctuation mark.
Context: ...on to the wallet. * watchAsset(): Request to add an ERC20 token to the wa...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...ction. * addDeclareTransaction(): Request the wallet to sign and submit a...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~88-~88: Although a hyphen is possible, it is not necessary in a compound modifier in which the first word is an adverb that ends in ‘ly’.
Context: ...he WalletProvider methods have clear, strongly-typed signatures for both input parameters an...

(HYPHENATED_LY_ADVERB_ADJECTIVE)

🪛 markdownlint-cli2 (0.17.2)
packages/wallet_provider/README.md

3-3: Bare URL used
null

(MD034, no-bare-urls)


12-12: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


13-13: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


14-14: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


15-15: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


18-18: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


19-19: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


21-21: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


23-23: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


24-24: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


26-26: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (64)
packages/wallet_provider/.gitignore (1)

5-7: Exclude pubspec.lock for library packages
Omitting pubspec.lock in library packages aligns with Dart’s recommendation to let consumers manage their own dependency resolutions.

packages/wallet_provider/LICENSE (1)

1-21: Approve MIT license file
The MIT license text is correctly applied, and all required clauses are present.

packages/wallet_provider/CHANGELOG.md (1)

1-3: Initial changelog entry is present
The CHANGELOG.md correctly documents the first release (0.0.1+1) with an initial entry.

packages/wallet_provider/lib/src/index.dart (1)

1-2: Approve aggregation of exports
Re-exporting model/index.dart and provider.dart provides a clean entry point and simplifies imports for consumers.

packages/wallet_provider/analysis_options.yaml (1)

1-7: Approve analysis options configuration
The file correctly includes the recommended lint rules and suppresses expected analyzer errors (invalid_annotation_target, non_constant_identifier_names) for generated code.

packages/wallet_provider/lib/wallet_provider.dart (1)

5-5: Re-exports look good
The exports for src/provider.dart and src/model/index.dart correctly expose the public API of the package.

Also applies to: 8-8

packages/wallet_provider/build.yaml (1)

1-10: Build configuration for code generation
The build.yaml properly configures the freezed and json_serializable builders with the intended options (union_key, explicit_to_json, field_rename). No issues detected.

packages/wallet_provider/test/melos_test.dart (1)

1-6: Dummy test to satisfy Melos tagging
This empty test ensures Melos finds at least one test tagged as 'unit'. It correctly uses the tags parameter and will always pass.

packages/wallet_provider/lib/src/model/api_version.dart (1)

1-4: Typedef for API version is appropriate
The ApiVersion alias for String clearly documents intent, and the doc comment provides context for future validation. Ready to merge.

packages/wallet_provider/lib/src/model/deployment_version.dart (1)

1-9: DeploymentVersion enum correctly defined with JsonValue annotations.
The enum cleanly represents Cairo versions 0 and 1 and will serialize/deserialize via the provided @JsonValue metadata. No issues detected.

packages/wallet_provider/lib/src/model/index.dart (1)

1-14: Centralized model exports are clear and comprehensive.
This barrel file cleanly re-exports all Wallet API models, simplifying imports for consumers of the package. No issues detected.

packages/wallet_provider/lib/src/model/add_invoke_transaction_result.dart (2)

1-6: Freezed model setup for invoke transaction result is correct.
Imports, part directives, and the @freezed annotation are properly configured for code generation.


7-17: Field mapping and type usage are appropriate.
The transactionHash field uses the proper JSON key and the Felt type from starknet. Serialization via the generated fromJson/toJson methods will work seamlessly.

packages/wallet_provider/lib/src/model/declare_txn_wallet.dart (2)

1-7: Model imports and part directives are well-configured.
The imports for freezed_annotation, starknet, and the local contract_class.dart, along with the part statements, align with standard freezed patterns.


11-20: DeclareTxnWallet fields and JSON mappings align with specification.
Fields compiledClassHash, classHash, and contractClass have the correct types (Felt and ContractClass) and JSON key mappings. No issues detected.

packages/wallet_provider/lib/src/model/add_declare_transaction_result.g.dart (1)

1-22: Generated serialization code appears correct.
This file is auto-generated by json_serializable; no manual edits are required.

packages/wallet_provider/lib/src/model/wallet_error.g.dart (2)

9-14: Generated JSON deserialization is correct. The _$$WalletErrorImplFromJson function properly converts the JSON map into a _WalletErrorImpl instance, parsing code, message, and data as expected.


16-21: Generated JSON serialization is correct. The _$$WalletErrorImplToJson method accurately serializes the _WalletErrorImpl instance back into JSON with the appropriate field names.

packages/wallet_provider/pubspec.yaml (4)

1-4: Validate package metadata. The package name, description, version, and repository fields are correctly set for the new wallet_provider package.


6-8: Review environment SDK constraint. Pinning the Dart SDK to ^3.0.5 aligns with the dependencies (freezed_annotation, json_annotation, etc.) and ensures compatibility.


9-14: Review runtime dependencies. The declared dependencies (starknet, freezed_annotation, http, json_annotation) are appropriate for implementing the Wallet API client, providing core types, JSON serialization, and HTTP communication.


15-20: Review dev_dependencies. The development dependencies (build_runner, freezed, json_serializable, lints, test) cover code generation, linting, and testing requirements.

packages/wallet_provider/lib/src/model/add_declare_transaction_result.dart (2)

1-5: Imports and part directives are correct. The file properly imports freezed_annotation and starknet, and includes the necessary part directives for freezed and JSON generated code.


7-19: Model declaration is accurate. The AddDeclareTransactionResult class uses @freezed and @JsonKey to map JSON fields (transaction_hash, class_hash) to Felt-typed properties, and includes a fromJson factory. This aligns with the Wallet API specification.

packages/wallet_provider/lib/src/model/declare_txn_wallet.g.dart (2)

9-16: Generated JSON deserialization is correct. The _$$DeclareTxnWalletImplFromJson function accurately constructs a DeclareTxnWallet instance by invoking Felt.fromJson and ContractClass.fromJson on the respective JSON fields.


18-24: Generated JSON serialization is correct. The _$$DeclareTxnWalletImplToJson method serializes the DeclareTxnWallet instance back into a JSON map using .toJson() on each field.

packages/wallet_provider/lib/src/model/add_invoke_transaction_result.g.dart (2)

9-13: Generated JSON deserialization is correct. The _$$AddInvokeTransactionResultImplFromJson function cleanly parses the transaction_hash field into a Felt instance using Felt.fromJson.


15-19: Generated JSON serialization is correct. The _$$AddInvokeTransactionResultImplToJson method returns a JSON map with transaction_hash serialized via toJson().

packages/wallet_provider/lib/src/model/starknet_chain.g.dart (2)

9-26: Generated deserialization logic is correct
The _$$StarknetChainImplFromJson function accurately maps JSON fields (id, chain_id, chain_name, rpc_urls, block_explorer_url, native_currency, icon_urls) to the Dart model, including null-safe handling of optional lists and nested Asset.fromJson.


28-37: Generated serialization logic is correct
The _$$StarknetChainImplToJson function serializes the Dart model back to JSON with appropriate keys and uses toJson() for Felt and Asset, matching the Wallet API spec.

packages/wallet_provider/lib/src/model/account_deployment_data.g.dart (2)

9-22: Generated deserialization logic is correct
The _$$AccountDeploymentDataImplFromJson function decodes required fields (address, class_hash, salt, calldata, version) and optional sigdata, correctly invoking Felt.fromJson and enum decoding.


24-33: Generated serialization logic is correct
The _$$AccountDeploymentDataImplToJson function maps the Dart instance to JSON with the expected structure, including converting Felt and encoding the version via _DeploymentVersionEnumMap.

packages/wallet_provider/lib/src/model/invoke_call.dart (2)

1-6: Imports and part directives are correctly configured
Imports of freezed_annotation and starknet plus the part directives follow Freezed conventions.


9-20: Freezed model setup looks good
The InvokeCall factory correctly maps JSON keys contract_address and entry_point to typed properties, and Freezed will generate the appropriate serialization code.

packages/wallet_provider/lib/src/model/typed_data.g.dart (4)

9-21: TypedData deserialization is correct
The _$$TypedDataImplFromJson function transforms types, primary_type, domain, and message fields accurately, preserving nested structures and invoking StarknetDomain.fromJson where needed.


23-30: TypedData serialization is correct
The _$$TypedDataImplToJson function serializes the instance back to JSON with the correct field names and nested structures.


31-42: StarknetDomain deserialization is correct
The _$$StarknetDomainImplFromJson handles optional Felt fields (name, version, chain_id, revision) with null checks, aligning with the null-safe model.


44-52: StarknetDomain serialization is correct
The _$$StarknetDomainImplToJson maps all optional fields using ?.toJson(), matching the JSON schema for the domain object.

packages/wallet_provider/lib/src/model/invoke_call.g.dart (2)

9-16: InvokeCall deserialization is correct
The _$$InvokeCallImplFromJson function properly handles required contract_address and entry_point, and null-safe mapping of optional calldata.


18-23: InvokeCall serialization is correct
The _$$InvokeCallImplToJson function serializes InvokeCall back to JSON with the expected keys, including toJson() on Felt and handling nullable calldata.

packages/wallet_provider/lib/src/model/contract_class.g.dart (1)

50-67: LGTM: Proper handling of deprecated contract class.

The DeprecatedContractClassImpl serialization properly handles the different structure with a string program instead of sierraProgram, different entry points type, and a list of ABI entries rather than a string.

packages/wallet_provider/example/wallet_provider_example.dart (4)

1-10: Well-structured imports with proper hiding of conflicting types.

The imports are well organized, with a clear explanation of why TypedData is hidden from the StarkNet package. The placeholder wallet URI with explanatory comments helps developers understand how to properly configure the connection in a real application.


11-32: Good helper functions for test data creation.

The helper functions and constants provide useful shortcuts for creating test data. The createDummyContractClass method particularly saves repetitive code while demonstrating the expected structure of a contract class.


39-55: Robust account request implementation with proper error handling.

The account request implementation demonstrates proper error handling by:

  1. Using try/catch blocks
  2. Providing informative error messages
  3. Checking for empty accounts before proceeding
  4. Exiting early if accounts cannot be obtained

This is a great pattern for production code.


175-180: Good resource management with provider closing.

The finally block ensures that the provider is properly closed, which is a good practice for resource management. This prevents potential memory leaks or hanging connections.

packages/wallet_provider/lib/src/model/account_deployment_data.freezed.dart (1)

1-300: Generated code follows best practices for immutable data models.

This auto-generated code from Freezed correctly implements an immutable AccountDeploymentData class with appropriate:

  • JSON serialization/deserialization
  • Deep equality checks
  • Immutable collections with EqualUnmodifiableListView
  • Proper handling of nullable fields
  • Clean toString implementation
  • Efficient hashCode implementation

The model structure includes all necessary fields for account deployment on Starknet with appropriate JSON key mapping for classHash to class_hash.

packages/wallet_provider/lib/src/model/asset.g.dart (1)

1-38: Generated serialization code handles complex types correctly.

This auto-generated code correctly implements JSON serialization and deserialization for the ERC20 asset models:

  1. ERC20AssetImpl: Handles the asset type and nested options object
  2. AssetOptionsImpl: Properly transforms the specialized Felt type using its JSON methods

The default type value of "ERC20" and optional fields (symbol, decimals, image, name) are handled appropriately according to the Starknet wallet API specifications.

packages/wallet_provider/lib/src/model/wallet_error.freezed.dart (1)

1-204: Error model follows standard JSON-RPC error structure.

This generated code correctly implements a WalletError class following the standard JSON-RPC error structure with:

  • Error code (integer)
  • Error message (string)
  • Optional additional data

The class extends a base WalletError class, likely with additional error handling capabilities defined in the base class. The implementation includes proper serialization/deserialization, equality checks, and copying methods expected of an immutable error model.

This structure will enable clean error handling and reporting when interacting with StarkNet wallets via JSON-RPC.

packages/wallet_provider/lib/src/model/asset.dart (1)

10-17: LGTM: Well-structured sealed class implementation

The sealed class approach for Asset with a single erc20 variant is well-implemented and follows best practices for extensibility. Future token type variants can be added easily.

packages/wallet_provider/lib/src/model/add_invoke_transaction_result.freezed.dart (1)

1-180: LGTM: Generated code for transaction result model looks correct

This is generated Freezed code that properly implements immutability and serialization for the AddInvokeTransactionResult model. The JSON property mapping using @JsonKey(name: 'transaction_hash') correctly handles snake_case to camelCase conversion.

packages/wallet_provider/Implementation_notes.md (2)

1-5: LGTM: Clear objective statement

The objective statement clearly defines the purpose of the implementation and how it fits into the broader Starknet ecosystem.


7-15: LGTM: Well-structured implementation approach

The implementation approach section provides a clear overview of the package structure, dependencies, and design decisions. This is helpful for maintaining the package in the future.

packages/wallet_provider/lib/src/model/add_declare_transaction_result.freezed.dart (1)

1-32: Generated file – can safely be ignored

This file is 100 % Freezed-generated boilerplate. Unless we observe compilation errors (none spotted) or forbidden patterns, there is no need to review or hand-edit it.

packages/wallet_provider/lib/src/model/typed_data.freezed.dart (1)

1-40: Generated file – no manual action required

Like the previous file this is pure Freezed output; manual edits will be overwritten. Any improvements (e.g. stronger typing for the message map) need to be done in typed_data.dart, not here.

packages/wallet_provider/lib/src/model/contract_class.dart (1)

21-33: Minor spec alignment – consider Uint8List for bytecode

List<Felt> sierraProgram forces every Sierra instruction to be encoded as a Felt.
The upstream JSON-RPC spec represents the Sierra program as an array of field elements after padding/trimming. If raw bytecode is ever required (e.g. for local class-hash computation) the current modelling will make it harder. Evaluate whether Uint8List or a wrapper value object would be more future-proof.

packages/wallet_provider/lib/src/model/contract_class.freezed.dart (1)

1-20: Generated file – no manual review

All logic here is produced by Freezed and mirrors the source file; focus corrections in contract_class.dart instead.

packages/wallet_provider/lib/src/model/starknet_chain.freezed.dart (1)

296-296: Improve equality comparisons for collections.

The equality implementation correctly uses DeepCollectionEquality for comparing lists, which avoids issues with reference equality for collections.

packages/wallet_provider/lib/src/model/wallet_error.dart (2)

32-70: Good use of comprehensive error types and documentation.

The error code enum is well-designed with clear naming, proper documentation, and explicit integer values using @JsonValue. This will make error handling more predictable and maintainable.


102-147: Well-structured error message extension.

The WalletErrorCodeExtension provides a clean way to access standardized error messages and descriptions, following good separation of concerns.

packages/wallet_provider/lib/src/model/declare_txn_wallet.freezed.dart (2)

23-28: Properly structured data model with consistent JSON key naming.

The DeclareTxnWallet model uses snake_case JSON keys that match the API specification, with appropriate @JsonKey annotations.


51-52: Good usage of copyWith interface for contract class.

The implementation correctly handles nested copyWith operations, which is important for complex models containing other class references like ContractClass.

packages/wallet_provider/lib/src/model/asset.freezed.dart (2)

162-164: Good use of default values for type field.

The code correctly implements a default value for the type field in ERC20Asset, which helps ensure consistent data representation.


22-57: Well-structured pattern matching for the Asset union type.

The Asset class properly implements pattern matching methods (when, map, maybeWhen, etc.) which makes handling different asset types both type-safe and expressive.

packages/wallet_provider/lib/src/model/invoke_call.freezed.dart (1)

1-226: Generated file – no manual changes expected

invoke_call.freezed.dart is Freezed–generated boilerplate. Manual edits will be lost the next time code-generation runs, so I’m skipping detailed review here.

String?
symbol, // TOKEN_SYMBOL constraints (pattern/length) not enforced by type system
num? decimals,
String? image, // TODO: Should be Uri?
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address TODO comment for image field type

The TODO comment about whether the image field should be a Uri type deserves resolution. Using Uri would provide type safety and validation for URL formats.

- String? image, // TODO: Should be Uri?
+ Uri? image,

Consider updating related serialization in generated code accordingly:

// In generated _$AssetOptionsFromJson method:
image: json['image'] == null ? null : Uri.parse(json['image'] as String),

// In generated _$AssetOptionsToJson method:
'image': instance.image?.toString(),

Comment on lines +18 to +68
group('WalletProvider Info Calls', () {
test('.supportedWalletApi() fails gracefully on standard node', () async {
try {
await provider.supportedWalletApi();
fail('Should have thrown an error'); // Expecting failure
} catch (e) {
// Expecting a WalletError with code -32601 (Method Not Found)
expect(e, isA<WalletError>());
if (e is WalletError) {
expect(e.code, equals(-32601));
}
print(
"supportedWalletApi failed as expected against non-wallet endpoint: $e");
}
});

test('.supportedSpecs() fails gracefully on standard node', () async {
try {
await provider.supportedSpecs();
fail('Should have thrown an error'); // Expecting failure
} catch (e) {
// Expecting a WalletError with code -32601 (Method Not Found)
expect(e, isA<WalletError>());
if (e is WalletError) {
expect(e.code, equals(-32601));
}
print(
"supportedSpecs failed as expected against non-wallet endpoint: $e");
}
});

// Let's try requestChainId - it might be implemented by some nodes/proxies
test('.requestChainId() returns chainId or fails gracefully', () async {
try {
final chainId = await provider.requestChainId();
expect(chainId, isA<Felt>());
// You could add a check for the specific chain ID if you know the endpoint
// final expectedChainId = Felt.fromHexString('YOUR_EXPECTED_CHAIN_ID_HEX');
// expect(chainId, equals(expectedChainId));
print(
"requestChainId succeeded with chainId: ${chainId.toHexString()}");
} catch (e) {
// Expecting a WalletError with code -32601 (Method Not Found) if node doesn't support it
expect(e, isA<WalletError>());
if (e is WalletError) {
expect(e.code, equals(-32601));
}
print("requestChainId failed as expected for this endpoint: $e");
}
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add positive test cases with mock wallet responses

The current tests only verify error handling against a standard node. Consider adding tests with mocked wallet responses to verify success paths.

Create a mock client that returns predefined responses to test success scenarios:

class MockWalletClient implements JsonRpcClient {
  final Map<String, dynamic> mockResponses;
  
  MockWalletClient(this.mockResponses);
  
  @override
  Future<dynamic> sendJsonRpc(String method, [dynamic params]) async {
    if (mockResponses.containsKey(method)) {
      return mockResponses[method];
    }
    throw WalletError(
      code: -32601,
      message: 'Method not found',
    );
  }
}

// Then in your test:
test('supportedWalletApi returns list of supported methods', () async {
  final mockClient = MockWalletClient({
    'wallet_supportedWalletApi': [
      'wallet_requestAccounts',
      'wallet_requestChainId',
      'wallet_addInvokeTransaction'
    ]
  });
  
  final provider = WalletProvider.fromClient(mockClient);
  final methods = await provider.supportedWalletApi();
  
  expect(methods, isA<List<String>>());
  expect(methods, contains('wallet_requestAccounts'));
  expect(methods, contains('wallet_addInvokeTransaction'));
});

throw _privateConstructorUsedError; // TODO: Should be List<Uri>?
@JsonKey(name: 'block_explorer_url')
List<String>? get blockExplorerUrl =>
throw _privateConstructorUsedError; // TODO: Should be List<Uri>?
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Apply consistent URL handling for block explorer URLs.

Similar to the rpcUrls field, blockExplorerUrl could benefit from using the Uri type instead of String.

In the source model file, update the type to use Uri with a custom JSON converter, similar to the recommendation for rpcUrls.

String get chainName => throw _privateConstructorUsedError;
@JsonKey(name: 'rpc_urls')
List<String>? get rpcUrls =>
throw _privateConstructorUsedError; // TODO: Should be List<Uri>?
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

TODO: Consider using Uri type for improved URL validation and handling.

The TODO comment suggests using List<Uri> instead of List<String> for rpcUrls. This is a good suggestion as the Uri type provides validation and methods specifically for working with URLs.

In the source model file that generates this code, you could update the type to use Uri with a custom JSON converter:

- @JsonKey(name: 'rpc_urls') List<String>? rpcUrls,
+ @JsonKey(name: 'rpc_urls', fromJson: _stringsToUris, toJson: _urisToStrings) List<Uri>? rpcUrls,

Add these converter functions to the source file:

List<Uri>? _stringsToUris(List<dynamic>? strings) {
  return strings?.map((s) => Uri.parse(s as String)).toList();
}

List<String>? _urisToStrings(List<Uri>? uris) {
  return uris?.map((uri) => uri.toString()).toList();
}

Comment on lines 291 to 297
Felt get address => throw _privateConstructorUsedError;
String? get symbol =>
throw _privateConstructorUsedError; // TOKEN_SYMBOL constraints (pattern/length) not enforced by type system
num? get decimals => throw _privateConstructorUsedError;
String? get image =>
throw _privateConstructorUsedError; // TODO: Should be Uri?
String? get name => throw _privateConstructorUsedError;
Copy link
Contributor

@coderabbitai coderabbitai bot Apr 29, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider adding validation for token symbols and better URL handling.

There are two improvements noted in the comments:

  1. The TOKEN_SYMBOL constraints aren't enforced by the type system
  2. The image URL field should be a Uri type

In the source model file:

  1. For token symbols, consider adding a validator or custom constructor that enforces the pattern/length constraints:
factory AssetOptions.validated({
  required Felt address,
  String? symbol,
  num? decimals,
  String? image,
  String? name,
}) {
  // Validate symbol if provided
  if (symbol != null) {
    // Add regex validation or length checks
    if (symbol.length > MAX_SYMBOL_LENGTH) {
      throw ArgumentError('Symbol exceeds maximum length');
    }
    if (!RegExp(r'^[A-Z0-9]+$').hasMatch(symbol)) {
      throw ArgumentError('Symbol must only contain uppercase letters and digits');
    }
  }
  
  return AssetOptions(
    address: address,
    symbol: symbol,
    decimals: decimals,
    image: image,
    name: name,
  );
}
  1. For the image URL, use the Uri type with custom JSON converters as suggested earlier for the chain URLs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TOKEN_SYMBOL constraints fixed based on wallet api

Copy link
Contributor

Choose a reason for hiding this comment

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

@redDwarf03 Thanks for implementing the TOKEN_SYMBOL constraints based on the wallet API specifications! That's great to see.

Do you also have plans to address the image URL field suggestion in a future update, or is there a specific reason to keep it as a String type?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (10)
packages/wallet_provider/README.md (10)

1-3: Use a proper markdown link for the spec URL
Instead of a bare URL (which triggers MD034), wrap it in angle brackets or convert it into a named link. For example:

This package is based on the official JSON-RPC specification available at [Starknet Wallet API spec](https://github.com/starkware-libs/starknet-specs/tree/master/wallet-api).
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

3-3: Bare URL used
null

(MD034, no-bare-urls)


11-16: Normalize nested list formatting under “Information & Permissions”
Current spacing is inconsistent. Consider:

* **Information & Permissions:**
  * `supportedWalletApi()`: Get supported Wallet API versions.
  * `supportedSpecs()`: Get supported Starknet JSON-RPC spec versions.
  * `getPermissions()`: Get existing permissions for the Dapp.
  * `requestAccounts()`: Request wallet account addresses.
  * `requestChainId()`: Request the current chain ID from the wallet.

Use two-space indents for subitems and a single space after the *.

🧰 Tools
🪛 LanguageTool

[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...API versions. * supportedSpecs(): Get supported Starknet JSON-RPC spec ve...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~14-~14: Loose punctuation mark.
Context: ...pec versions. * getPermissions(): Get existing permissions for the Dapp. ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...or the Dapp. * requestAccounts(): Request wallet account addresses. *...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nt addresses. * requestChainId(): Request the current chain ID from the w...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

12-12: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


13-13: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


14-14: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


15-15: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


17-21: Align “Account & Network Management” list indentation
Refactor to:

* **Account & Network Management:**
  * `deploymentData()`: Request data needed to deploy the connected account.
  * `switchStarknetChain()`: Request to switch the wallet’s active Starknet network.
  * `addStarknetChain()`: Request to add a new Starknet network configuration to the wallet.
  * `watchAsset()`: Request to add an ERC20 token to the wallet’s tracked assets.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...account. * switchStarknetChain(): Request to switch the wallet's active S...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...et network. * addStarknetChain(): Request to add a new Starknet network c...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~21-~21: Loose punctuation mark.
Context: ...on to the wallet. * watchAsset(): Request to add an ERC20 token to the wa...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

18-18: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


19-19: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


21-21: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


22-24: Standardize “Transaction Submission” bullets
Use consistent two-space indent:

* **Transaction Submission:**
  * `addInvokeTransaction()`: Request the wallet to sign and submit an invoke transaction.
  * `addDeclareTransaction()`: Request the wallet to sign and submit a declare transaction.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...ction. * addDeclareTransaction(): Request the wallet to sign and submit a...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)

23-23: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


24-24: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


25-27: Format “Signing” section consistently
Update to:

* **Signing:**
  * `signTypedData()`: Request the wallet to sign typed data according to EIP-712 (Starknet variant).
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

26-26: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


76-78: Consider adding a status badge
Enhance visibility by displaying build/test status or package version badge (e.g., from GitHub Actions or pub.dev) at the top of the README.


84-92: Refine hyphenation and list markers in “Type Safety”

  • Remove hyphen in “strongly-typed” (adverbs ending in “-ly” need not be hyphenated).
  • Normalize bullet items with one space after * and two-space indentation:
* Typed Models: ...
* Enums: ...
* Typed Methods: ...
* Controlled `dynamic`: ...
🧰 Tools
🪛 LanguageTool

[uncategorized] ~88-~88: Although a hyphen is possible, it is not necessary in a compound modifier in which the first word is an adverb that ends in ‘ly’.
Context: ...he WalletProvider methods have clear, strongly-typed signatures for both input parameters an...

(HYPHENATED_LY_ADVERB_ADJECTIVE)


96-98: Align bullets under “Interaction with Standard Starknet JSON-RPC”
Use consistent formatting:

* Standard JSON-RPC API: Primarily used by … 
* Wallet API (this provider): Primarily used by …

104-108: Standardize “Error Handling” list formatting
Refactor to:

* Network & RPC Errors: …
* Wallet-Specific Errors: …
* Type Errors: …
* Dapp Responsibility: …

113-118: Normalize “Future Implementation Recommendations” bullets
Ensure consistent two-space indent and a single space after *:

* Wallet Connection/Discovery: …
* Wallet Event Handling: …
* Enhanced Testing Strategies: …
* Higher-Level Abstractions (Potential): …
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1100a33 and 7121204.

📒 Files selected for processing (50)
  • packages/wallet_provider/.gitignore (1 hunks)
  • packages/wallet_provider/.tool-versions (1 hunks)
  • packages/wallet_provider/CHANGELOG.md (1 hunks)
  • packages/wallet_provider/Implementation_notes.md (1 hunks)
  • packages/wallet_provider/LICENSE (1 hunks)
  • packages/wallet_provider/README.md (1 hunks)
  • packages/wallet_provider/analysis_options.yaml (1 hunks)
  • packages/wallet_provider/build.yaml (1 hunks)
  • packages/wallet_provider/dart_test.yaml (1 hunks)
  • packages/wallet_provider/example/wallet_provider_example.dart (1 hunks)
  • packages/wallet_provider/lib/src/index.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/account_deployment_data.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/api_version.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/asset.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/deployment_version.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/index.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/invoke_call.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/permission.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/starknet_chain.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.freezed.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/wallet_error.g.dart (1 hunks)
  • packages/wallet_provider/lib/src/provider.dart (1 hunks)
  • packages/wallet_provider/lib/wallet_provider.dart (1 hunks)
  • packages/wallet_provider/pubspec.yaml (1 hunks)
  • packages/wallet_provider/test/melos_test.dart (1 hunks)
  • packages/wallet_provider/test/provider_test.dart (1 hunks)
✅ Files skipped from review due to trivial changes (7)
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.g.dart
  • packages/wallet_provider/lib/src/model/deployment_version.dart
  • packages/wallet_provider/lib/src/index.dart
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.g.dart
  • packages/wallet_provider/lib/src/model/typed_data.dart
  • packages/wallet_provider/lib/src/model/contract_class.g.dart
  • packages/wallet_provider/lib/src/model/account_deployment_data.g.dart
🚧 Files skipped from review as they are similar to previous changes (42)
  • packages/wallet_provider/CHANGELOG.md
  • packages/wallet_provider/dart_test.yaml
  • packages/wallet_provider/.tool-versions
  • packages/wallet_provider/lib/wallet_provider.dart
  • packages/wallet_provider/LICENSE
  • packages/wallet_provider/lib/src/model/permission.dart
  • packages/wallet_provider/lib/src/model/api_version.dart
  • packages/wallet_provider/build.yaml
  • packages/wallet_provider/lib/src/model/index.dart
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.dart
  • packages/wallet_provider/lib/src/model/wallet_error.g.dart
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.dart
  • packages/wallet_provider/analysis_options.yaml
  • packages/wallet_provider/lib/src/model/typed_data.g.dart
  • packages/wallet_provider/test/melos_test.dart
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.g.dart
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.dart
  • packages/wallet_provider/pubspec.yaml
  • packages/wallet_provider/.gitignore
  • packages/wallet_provider/lib/src/model/invoke_call.g.dart
  • packages/wallet_provider/lib/src/model/invoke_call.dart
  • packages/wallet_provider/lib/src/model/asset.g.dart
  • packages/wallet_provider/lib/src/model/asset.dart
  • packages/wallet_provider/lib/src/model/account_deployment_data.dart
  • packages/wallet_provider/lib/src/model/account_deployment_data.freezed.dart
  • packages/wallet_provider/example/wallet_provider_example.dart
  • packages/wallet_provider/lib/src/model/starknet_chain.dart
  • packages/wallet_provider/Implementation_notes.md
  • packages/wallet_provider/lib/src/model/starknet_chain.g.dart
  • packages/wallet_provider/lib/src/model/wallet_error.dart
  • packages/wallet_provider/lib/src/model/contract_class.dart
  • packages/wallet_provider/lib/src/model/declare_txn_wallet.freezed.dart
  • packages/wallet_provider/test/provider_test.dart
  • packages/wallet_provider/lib/src/model/contract_class.freezed.dart
  • packages/wallet_provider/lib/src/model/wallet_error.freezed.dart
  • packages/wallet_provider/lib/src/model/add_invoke_transaction_result.freezed.dart
  • packages/wallet_provider/lib/src/model/invoke_call.freezed.dart
  • packages/wallet_provider/lib/src/model/asset.freezed.dart
  • packages/wallet_provider/lib/src/model/starknet_chain.freezed.dart
  • packages/wallet_provider/lib/src/model/typed_data.freezed.dart
  • packages/wallet_provider/lib/src/model/add_declare_transaction_result.freezed.dart
  • packages/wallet_provider/lib/src/provider.dart
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: rukafe0x
PR: focustree/starknet.dart#417
File: packages/starknet_provider/lib/src/model/json_rpc_api_error.freezed.dart:26-31
Timestamp: 2024-11-21T18:01:50.217Z
Learning: The file `packages/starknet_provider/lib/src/model/json_rpc_api_error.freezed.dart` is auto-generated and should not be manually modified. Documentation changes should be made in the source file used to generate this code to ensure they persist upon regeneration.
Learnt from: rukafe0x
PR: focustree/starknet.dart#412
File: packages/starknet_provider/lib/src/model/invoke_transaction.freezed.dart:26-31
Timestamp: 2024-10-26T15:39:54.600Z
Learning: In the `starknet_provider/lib/src/model/invoke_transaction.freezed.dart` file and other files with the `.freezed.dart` extension, the code is automatically generated by the `freezed` package and should not be manually modified.
🪛 LanguageTool
packages/wallet_provider/README.md

[uncategorized] ~13-~13: Loose punctuation mark.
Context: ...API versions. * supportedSpecs(): Get supported Starknet JSON-RPC spec ve...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~14-~14: Loose punctuation mark.
Context: ...pec versions. * getPermissions(): Get existing permissions for the Dapp. ...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~15-~15: Loose punctuation mark.
Context: ...or the Dapp. * requestAccounts(): Request wallet account addresses. *...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~16-~16: Loose punctuation mark.
Context: ...nt addresses. * requestChainId(): Request the current chain ID from the w...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~19-~19: Loose punctuation mark.
Context: ...account. * switchStarknetChain(): Request to switch the wallet's active S...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~20-~20: Loose punctuation mark.
Context: ...et network. * addStarknetChain(): Request to add a new Starknet network c...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~21-~21: Loose punctuation mark.
Context: ...on to the wallet. * watchAsset(): Request to add an ERC20 token to the wa...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~24-~24: Loose punctuation mark.
Context: ...ction. * addDeclareTransaction(): Request the wallet to sign and submit a...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~88-~88: Although a hyphen is possible, it is not necessary in a compound modifier in which the first word is an adverb that ends in ‘ly’.
Context: ...he WalletProvider methods have clear, strongly-typed signatures for both input parameters an...

(HYPHENATED_LY_ADVERB_ADJECTIVE)

🪛 markdownlint-cli2 (0.17.2)
packages/wallet_provider/README.md

3-3: Bare URL used
null

(MD034, no-bare-urls)


12-12: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


13-13: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


14-14: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


15-15: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


16-16: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


18-18: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


19-19: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


20-20: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


21-21: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


23-23: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


24-24: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)


26-26: Unordered list indentation
Expected: 2; Actual: 4

(MD007, ul-indent)

🔇 Additional comments (9)
packages/wallet_provider/README.md (9)

5-6: The package description is clear and concise.


7-10: The “Features” heading and introductory line are well-structured.


28-31: The “Usage” intro lines effectively lead into the example.


32-72: The Dart example is comprehensive and illustrative; no markup issues detected within the fenced code block.


73-74: The advisory note is clear and informative.


80-83: The “Technical Considerations” and “Type Safety” headings are appropriately placed.


93-95: The “Interaction with Standard Starknet JSON-RPC” heading clearly sets context.


100-101: The “Error Handling” heading is concise.


109-111: The “Future Implementation Recommendations” heading introduces upcoming enhancements effectively.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/wallet_provider/lib/src/model/typed_data.dart (1)

25-36: Prioritize implementing a proper type-safe structure for the message field

The message field is still using Map<String, dynamic>, which reduces type safety for blockchain operations and could lead to subtle bugs.

Consider implementing this as a proper class with defined fields based on the Starknet specification rather than using a dynamic map. Alternatively, you could create a generic type parameter that enforces proper structure:

- required Map<String, dynamic> message,
+ required Map<String, Object> message, // At minimum, avoid 'dynamic'

For a more type-safe approach, consider creating a generic type parameter:

@freezed
class TypedData<T> with _$TypedData<T> {
  const factory TypedData({
    required Map<String, List<StarknetTypeDescriptor>> types,
    required String primaryType,
    required StarknetDomain domain,
    required T message,
  }) = _TypedData<T>;
  
  // JSON conversion would need to be adjusted
}
🧹 Nitpick comments (1)
packages/wallet_provider/lib/src/model/typed_data.dart (1)

23-36: Consider adding utility constructors for common TypedData patterns

Creating TypedData objects can be complex due to the nested structure. Adding utility constructors would improve developer experience.

// Example utility constructor
factory TypedData.simple({
  required String primaryType,
  required List<StarknetTypeDescriptor> typeDescriptors,
  required StarknetDomain domain,
  required Map<String, Object> message,
}) {
  return TypedData(
    types: {primaryType: typeDescriptors},
    primaryType: primaryType,
    domain: domain,
    message: message,
  );
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7121204 and 4a78b09.

📒 Files selected for processing (5)
  • packages/wallet_provider/lib/src/model/asset.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/contract_class.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/provider.dart (1 hunks)
  • packages/wallet_provider/lib/wallet_provider.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/wallet_provider/lib/wallet_provider.dart
  • packages/wallet_provider/lib/src/model/asset.dart
  • packages/wallet_provider/lib/src/model/contract_class.dart
  • packages/wallet_provider/lib/src/provider.dart
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: rukafe0x
PR: focustree/starknet.dart#417
File: packages/starknet_provider/lib/src/model/json_rpc_api_error.freezed.dart:26-31
Timestamp: 2024-11-21T18:01:50.217Z
Learning: The file `packages/starknet_provider/lib/src/model/json_rpc_api_error.freezed.dart` is auto-generated and should not be manually modified. Documentation changes should be made in the source file used to generate this code to ensure they persist upon regeneration.
Learnt from: rukafe0x
PR: focustree/starknet.dart#412
File: packages/starknet_provider/lib/src/model/invoke_transaction.freezed.dart:26-31
Timestamp: 2024-10-26T15:39:54.600Z
Learning: In the `starknet_provider/lib/src/model/invoke_transaction.freezed.dart` file and other files with the `.freezed.dart` extension, the code is automatically generated by the `freezed` package and should not be manually modified.
packages/wallet_provider/lib/src/model/typed_data.dart (1)
Learnt from: rukafe0x
PR: focustree/starknet.dart#412
File: packages/starknet_provider/lib/src/model/invoke_transaction.freezed.dart:26-31
Timestamp: 2024-10-26T15:39:54.600Z
Learning: In the `starknet_provider/lib/src/model/invoke_transaction.freezed.dart` file and other files with the `.freezed.dart` extension, the code is automatically generated by the `freezed` package and should not be manually modified.
🪛 GitHub Actions: CI
packages/wallet_provider/lib/src/model/typed_data.dart

[error] 10-10: Type '_$StarknetTypeDescriptor' not found. The class StarknetTypeDescriptor with _$StarknetTypeDescriptor mixin cannot be resolved.


[error] 10-10: The type '_$StarknetTypeDescriptor' can't be mixed in.


[error] 14-14: Couldn't find constructor '_StarknetTypeDescriptor'. Redirection constructor target not found.


[error] 17-17: Method not found: '_$StarknetTypeDescriptorFromJson'.

🪛 GitHub Actions: code_health
packages/wallet_provider/lib/src/model/typed_data.dart

[error] 10-10: Dart analyze error: Classes can only mix in mixins and classes. (mixin_of_non_class)


[error] 14-14: Dart analyze error: The name '_StarknetTypeDescriptor' isn't a type and can't be used in a redirected constructor. Possibly a typo or missing type definition. (non_type_as_type_argument)

🔇 Additional comments (1)
packages/wallet_provider/lib/src/model/typed_data.dart (1)

47-49: Great job implementing domain validation

You've successfully addressed the previous review comment by adding validation to ensure at least one field in the StarknetDomain is non-null.

Comment on lines +1 to +6
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:starknet/starknet.dart'; // Import Felt

part 'typed_data.freezed.dart';
part 'typed_data.g.dart';

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Run code generation for Freezed models

The CI pipeline is failing because the generated files referenced in the part directives don't exist or are outdated. You need to run the code generation command after making changes to this file.

Execute the following command in your terminal from the project root:

dart run build_runner build --delete-conflicting-outputs

Comment on lines 25 to 31
const factory TypedData({
/// Defines the custom types used in the message. Maps struct names to their field descriptors.
/// Example: { "Mail": [ { "name": "from", "type": "felt" }, ... ], "Person": [...] }
required Map<String, List<StarknetTypeDescriptor>> types,
/// The primary struct type to hash and sign (e.g., "Mail"). Must exist as a key in `types`.
required String primaryType,
/// Domain separator parameters to ensure signature uniqueness across different applications/chains.
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for primaryType to ensure it exists in types map

The primaryType field must exist as a key in the types map, but this constraint isn't enforced in the code.

Add an assertion to validate this relationship:

@freezed
class TypedData with _$TypedData {
+ @Assert('types.containsKey(primaryType)', 'primaryType must exist in types map')
  const factory TypedData({
    /// Defines the custom types used in the message. Maps struct names to their field descriptors.
    /// Example: { "Mail": [ { "name": "from", "type": "felt" }, ... ], "Person": [...] }
    required Map<String, List<StarknetTypeDescriptor>> types,
    /// The primary struct type to hash and sign (e.g., "Mail"). Must exist as a key in `types`.
    required String primaryType,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const factory TypedData({
/// Defines the custom types used in the message. Maps struct names to their field descriptors.
/// Example: { "Mail": [ { "name": "from", "type": "felt" }, ... ], "Person": [...] }
required Map<String, List<StarknetTypeDescriptor>> types,
/// The primary struct type to hash and sign (e.g., "Mail"). Must exist as a key in `types`.
required String primaryType,
/// Domain separator parameters to ensure signature uniqueness across different applications/chains.
@Assert('types.containsKey(primaryType)', 'primaryType must exist in types map')
const factory TypedData({
/// Defines the custom types used in the message. Maps struct names to their field descriptors.
/// Example: { "Mail": [ { "name": "from", "type": "felt" }, ... ], "Person": [...] }
required Map<String, List<StarknetTypeDescriptor>> types,
/// The primary struct type to hash and sign (e.g., "Mail"). Must exist as a key in `types`.
required String primaryType,
/// Domain separator parameters to ensure signature uniqueness across different applications/chains.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
packages/wallet_provider/lib/src/provider.dart (3)

106-112: Avoid using print statements in library code

Using print for logging warnings isn't ideal for library code since it forces a specific logging behavior on all applications using the library.

Consider implementing a more flexible logging approach:

-          try {
-            return Permission.values.byName(p);
-          } catch (e) {
-            // Handle cases where the permission string is not in the enum
-            print('Warning: Unknown permission received: $p');
-            return null; // Or throw an error, depending on desired strictness
-          }
+          try {
+            return Permission.values.byName(p);
+          } catch (e) {
+            // Handle cases where the permission string is not in the enum
+            // Silently return null to be filtered out later
+            // Consider exposing an optional logger or callback for unknown permissions
+            return null;
+          }

155-173: Complex positional parameter handling in switchStarknetChain

The logic for handling positional parameters with potential nulls is complex but correct. Consider adding more documentation explaining this pattern.

Add more documentation explaining why positional parameters are handled differently in this method compared to others:

 /// Change the current network of the wallet.
+/// 
+/// Note: This method uses positional parameters according to the Wallet API spec:
+/// [chainId, silent_mode?, api_version?]
 Future<bool> switchStarknetChain(Felt chainId,
     {bool? silentMode, ApiVersion? apiVersion}) async {
   // Sticking to pure positional: [chainId, silent_mode?, api_version?]

80-235: Consider defensive type checking for JSON-RPC responses

While you do cast results to expected types, consider adding more defensive checks before these casts to handle unexpected response formats gracefully.

For example, in a method like signTypedData, you could add a check:

 final result = await _client.call('wallet_signTypedData', params);
 // Result is SIGNATURE (List<String> or List<dynamic>)
+if (result is! List) {
+  throw FormatException('Expected array signature result, got: ${result.runtimeType}');
+}
 final signature = List<String>.from(result as List);
 return signature.map((s) => Felt.fromHexString(s)).toList();

This approach would provide clearer error messages if the wallet implementation returns unexpected data structures.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ba619a7 and c8dfdac.

📒 Files selected for processing (3)
  • packages/wallet_provider/lib/src/model/asset.dart (1 hunks)
  • packages/wallet_provider/lib/src/model/typed_data.dart (1 hunks)
  • packages/wallet_provider/lib/src/provider.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/wallet_provider/lib/src/model/asset.dart
  • packages/wallet_provider/lib/src/model/typed_data.dart
🔇 Additional comments (7)
packages/wallet_provider/lib/src/provider.dart (7)

1-5: Correct import organization with explicit TypedData hiding

The imports are well-organized, with explicit hiding of the TypedData from starknet.dart to avoid conflicts with your own implementation. This demonstrates good awareness of potential name collisions.


8-22: Well-implemented JsonRpcClient with monotonically increasing IDs

The implementation follows JSON-RPC 2.0 specification and incorporates previous review feedback by using a monotonically increasing request ID counter instead of hard-coded values. This prevents potential response mismatches during concurrent requests.


24-31: Good HTTP headers implementation with Accept header

Your code now includes both proper Content-Type and Accept headers as recommended in previous reviews, which follows HTTP best practices for JSON-RPC requests.


33-73: Robust error handling with multiple validation layers

Your implementation properly handles different error scenarios:

  1. JSON parsing errors
  2. JSON-RPC protocol errors
  3. HTTP status code errors
  4. Malformed responses

The structured approach to error handling will provide clear, actionable error messages to developers.


118-137: Thorough parameter handling for requestAccounts

The implementation carefully handles the optional parameters for requestAccounts according to the specification, conditionally constructing the parameter object only when needed. The conversion from hex strings to Felt objects is also properly implemented.


219-229: Consistent TypedData signing implementation

The signing implementation properly converts the typed data to JSON and transforms the response signature from hex strings to Felt values, maintaining consistency with other wallet operations.


1-235: Overall excellent Wallet API provider implementation

The implementation is well-structured, thoroughly documented, and properly implements the Starknet Wallet API JSON-RPC specification. The code demonstrates good error handling, proper type conversion, and attention to edge cases. The use of typed methods with clear parameters and return types makes this package easy to use for Dart developers working with Starknet wallets.

@redDwarf03
Copy link
Contributor Author

i did some updates from coderabbit recommandations
@ptisserand i let you for the moment review this PR. I will work on some updates if necessary but for the moment i think this PR could be challenged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant