Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

✨ Feat: Add anvil_deal #1492

Merged
merged 3 commits into from
Nov 1, 2024
Merged

Conversation

roninjin10
Copy link
Collaborator

@roninjin10 roninjin10 commented Nov 1, 2024

Description

Concise description of proposed changes

Testing

Explain the quality checks that have been done on the code changes

Additional Information

Your ENS/address:

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced the anvil_deal JSON-RPC request for handling ERC20 token transactions.
    • Added the eth_createAccessList JSON-RPC request to create access lists for Ethereum transactions.
    • Implemented a new deal method in the TevmActionsApi for ERC20 token distribution.
  • Bug Fixes

    • Enhanced error handling in transaction procedures to ensure robust responses.
  • Tests

    • Added unit tests for the new anvil_deal and eth_createAccessList procedures to validate functionality.

Copy link

vercel bot commented Nov 1, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Updated (UTC)
tevm-monorepo-tevm ⬜️ Ignored (Inspect) Nov 1, 2024 4:21am

Copy link

changeset-bot bot commented Nov 1, 2024

🦋 Changeset detected

Latest commit: 0522e0e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 10 packages
Name Type
@tevm/memory-client Major
@tevm/decorators Major
@tevm/actions Major
@tevm/cli Major
@tevm/viem Major
@tevm/http-client Major
@tevm/server Major
tevm Major
@tevm/ethers Major
tevm-run Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

coderabbitai bot commented Nov 1, 2024

Walkthrough

The changes in this pull request introduce new JSON-RPC functionalities, specifically the eth_createAccessList and anvil_deal requests. Additionally, a new action MemoryClient.deal is added. The modifications include the creation of new types and procedures to support these functionalities, enhancing the overall capabilities of the system to handle ERC20 token transactions and memory operations. The updates span across various files, ensuring integration within the existing framework without altering existing logic.

Changes

File Path Change Summary
.changeset/little-coats-float.md Added eth_createAccessList and anvil_deal methods in JSON-RPC interface; introduced MemoryClient.deal.
packages/actions/src/anvil/AnvilHandler.ts Added types AnvilDealParams, AnvilDealResult, and AnvilDealHandler.
packages/actions/src/anvil/AnvilJsonRpcRequest.ts Introduced AnvilDealJsonRpcRequest type; updated AnvilJsonRpcRequest union type.
packages/actions/src/anvil/AnvilJsonRpcResponse.ts Added AnvilDealJsonRpcResponse type; imported AnvilDealResult.
packages/actions/src/anvil/AnvilParams.ts Defined AnvilDealParams type for token dealings.
packages/actions/src/anvil/AnvilProcedure.ts Added AnvilDealProcedure type; updated AnvilProcedure union type.
packages/actions/src/anvil/AnvilResult.ts Introduced AnvilDealResult type for error handling.
packages/actions/src/anvil/anvilDealHandler.js Created dealHandler function for ERC20 token transactions.
packages/actions/src/anvil/anvilDealProcedure.js Introduced anvilDealJsonRpcProcedure for handling ERC20 token dealings.
packages/actions/src/anvil/anvilDealProcedure.spec.ts Added unit tests for anvilDealJsonRpcProcedure.
packages/actions/src/anvil/index.ts Added exports for anvilDealHandler.js and anvilDealProcedure.js.
packages/actions/src/createHandlers.js Integrated anvilDealJsonRpcProcedure into anvilHandlers; updated ethHandlers for eth_createAccessList.
packages/actions/src/eth/EthJsonRpcRequest.ts Modified JsonRpcTransaction type; added EthCreateAccessListJsonRpcRequest type.
packages/actions/src/eth/EthJsonRpcResponse.ts Added EthCreateAccessListJsonRpcResponse type.
packages/actions/src/eth/EthProcedure.ts Introduced EthCreateAccessListJsonRpcProcedure.
packages/actions/src/eth/ethCreateAccessListProcedure.js Created procedure for creating Ethereum access lists.
packages/actions/src/eth/ethCreateAccessListProcedure.spec.ts Added tests for ethCreateAccessListProcedure.
packages/actions/src/eth/ethSendTransactionProcedure.js Updated transaction parameter handling for robustness.
packages/actions/src/eth/index.ts Added export for ethCreateAccessListProcedure.
packages/actions/src/tevm-request-handler/AnvilRequestType.ts Added AnvilDealJsonRpcRequest to request type mapping.
packages/actions/src/tevm-request-handler/AnvilReturnType.ts Updated AnvilReturnType to include anvil_deal.
packages/actions/src/tevm-request-handler/EthReturnType.ts Added EthCreateAccessListJsonRpcResponse to return type mapping.
packages/actions/src/tevm-request-handler/TevmJsonRpcRequestHandler.ts Documented eth_createAccessList method.
packages/decorators/src/actions/TevmActionsApi.ts Added deal method to TevmActionsApi.
packages/decorators/src/actions/tevmActions.js Introduced dealAction for extending TevmActionsApi.
packages/memory-client/src/test/requests.spec.ts Added test case for eth_createAccessList.

Possibly related PRs

🐰 In a world of code and requests so bright,
New tokens and access lists take flight.
With anvil_deal and createAccessList in tow,
Our JSON-RPC magic continues to grow!
Hopping through functions, with joy we shall sing,
For every new feature, our hearts dance and spring! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ 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.

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 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
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @roninjin10 and the rest of your teammates on Graphite Graphite

@roninjin10 roninjin10 force-pushed the 10-31-_sparkles_feat_add_anvil_deal branch from 25336ce to 0522e0e Compare November 1, 2024 04:21
@roninjin10 roninjin10 marked this pull request as ready for review November 1, 2024 04:24
@roninjin10 roninjin10 merged commit b99de65 into main Nov 1, 2024
9 checks passed
@roninjin10 roninjin10 deleted the 10-31-_sparkles_feat_add_anvil_deal branch November 1, 2024 04:27
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: 15

🧹 Outside diff range and nitpick comments (24)
packages/actions/src/anvil/AnvilResult.ts (1)

34-37: Add JSDoc documentation for the new type.

The type definition looks good, but could benefit from JSDoc documentation explaining its purpose and usage.

Consider adding documentation like this:

 // anvil_deal
+/**
+ * Result type for the anvil_deal JSON-RPC method.
+ * @property {Error[]} [errors] - Optional array of errors that occurred during the deal operation
+ */
 export type AnvilDealResult = {
   errors?: Error[]
 }
packages/actions/src/eth/ethSendTransactionProcedure.js (3)

Line range hint 15-20: Consider handling zero values explicitly.

The current implementation might incorrectly exclude zero values since value && {...} would evaluate 0 as falsy. Consider using explicit existence checks.

Here's a more robust implementation:

-      ...(request.params[0].from ? { from: request.params[0].from } : {}),
-      ...(request.params[0].data ? { data: request.params[0].data } : {}),
-      ...(request.params[0].to ? { to: request.params[0].to } : {}),
-      ...(request.params[0].gas ? { gas: hexToBigInt(request.params[0].gas) } : {}),
-      ...(request.params[0].gasPrice ? { gasPrice: hexToBigInt(request.params[0].gasPrice) } : {}),
-      ...(request.params[0].value ? { value: hexToBigInt(request.params[0].value) } : {}),
+      ...('from' in request.params[0] ? { from: request.params[0].from } : {}),
+      ...('data' in request.params[0] ? { data: request.params[0].data } : {}),
+      ...('to' in request.params[0] ? { to: request.params[0].to } : {}),
+      ...('gas' in request.params[0] ? { gas: hexToBigInt(request.params[0].gas) } : {}),
+      ...('gasPrice' in request.params[0] ? { gasPrice: hexToBigInt(request.params[0].gasPrice) } : {}),
+      ...('value' in request.params[0] ? { value: hexToBigInt(request.params[0].value) } : {}),

Line range hint 15-20: Consider adding gas estimation fallback.

When gas is not provided, consider adding automatic gas estimation to improve user experience.

This could be implemented by:

  1. Checking if gas is missing
  2. Using eth_estimateGas RPC call to calculate it
  3. Falling back to a safe default if estimation fails

Would you like me to provide a detailed implementation for this enhancement?


Based on the code inspection, I can now provide a final response:

Parameter validation is needed for transaction fields

The current implementation lacks essential validation for Ethereum transaction parameters. While the code uses hexToBigInt for numeric conversions, there's no validation for:

  • Ethereum address format for to and from fields
  • Hex string format validation before conversion
  • Value range checks for numeric fields

Key findings from the codebase:

  • The BaseCallParams type defines the expected types but there's no runtime validation
  • The ethSendTransactionHandler processes the transaction without validating inputs
  • No evidence of address or hex format validation in the current flow
🔗 Analysis chain

Line range hint 15-20: Consider adding parameter validation.

The current implementation might benefit from additional validation:

  1. Hex string format validation before conversion
  2. Address format validation for to and from fields
  3. Value range checks for gas, gasPrice, and value

Let's check if there's existing validation elsewhere:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for validation related to eth_sendTransaction
rg -A 5 "eth_sendTransaction.*valid" 
# Check for potential error handling
ast-grep --pattern 'try {
  $$$
  hexToBigInt($_)
  $$$
} catch'

Length of output: 105


Script:

#!/bin/bash
# Let's check for any validation in the ethSendTransactionProcedure file
rg -A 10 "validate|check|verify" packages/actions/src/eth/ethSendTransactionProcedure.js

# Look for any validation utilities that might be imported
rg "import.*validate|check|verify" packages/actions/src/eth/ethSendTransactionProcedure.js

# Check implementation of hexToBigInt for error handling
rg -l "hexToBigInt" packages/actions/src/
fd hexToBigInt.js packages/actions/src/ -x cat {}

# Search for any ethereum address validation utilities
rg -l "isAddress|validateAddress|checkAddress" packages/actions/src/

Length of output: 1423


Script:

#!/bin/bash
# Let's check the implementation of hexToBigInt in the utils
cat packages/actions/src/utils/parseBlockTag.js

# Check if there's any error handling or validation in the ethSendTransactionProcedure
cat packages/actions/src/eth/ethSendTransactionProcedure.js

# Look for any ethereum-specific validation utilities in the project
rg -l "0x[a-fA-F0-9]|isHex|isValidHex" packages/actions/src/
fd validator.js packages/actions/src/ -x cat {}

Length of output: 10033


Script:

#!/bin/bash
# Let's check if there's validation in the imported @tevm/utils package's hexToBigInt
cat packages/actions/src/eth/ethSendTransactionHandler.js

# Check for any validation in BaseCallParams since it might contain common validation
cat packages/actions/src/BaseCall/validateBaseCallParams.spec.ts
cat packages/actions/src/BaseCall/BaseCallParams.ts

# Look for any Ethereum address validation
rg -A 5 "validateAddress|isValidAddress|checkAddress" packages/actions/src/

Length of output: 16725

packages/actions/src/anvil/anvilDealProcedure.spec.ts (1)

8-62: Consider adding test cases for edge scenarios.

The current test suite covers the happy path for both ERC20 and native tokens. Consider adding tests for:

  1. Invalid addresses
  2. Zero amounts
  3. Invalid ERC20 contracts (non-compliant or non-existent)
  4. Overflow amounts
  5. Reentrant calls

Would you like me to help generate these additional test cases?

packages/actions/src/eth/ethCreateAccessListProcedure.spec.ts (1)

9-9: Document the significance of the magic number.

Consider adding a comment explaining why the specific value 420420 was chosen for the contract address, or consider using a more meaningful constant.

+// Using an arbitrary but consistent address for testing
const erc20 = TestERC20.withAddress(createAddress(420420).toString())
packages/actions/src/eth/ethCreateAccessListProcedure.js (2)

1-8: Consider enhancing documentation with examples

The documentation clearly describes the purpose, but adding an @example section would help developers understand the expected input and output format.

Add example usage:

 /**
  * Creates an access list for a transaction.
  * Returns list of addresses and storage keys that the transaction plans to access.
  * @param {import('@tevm/node').TevmNode} client
  * @returns {import('./EthProcedure.js').EthCreateAccessListJsonRpcProcedure}
+ * @example
+ * const accessList = await ethCreateAccessListProcedure(client)({
+ *   jsonrpc: '2.0',
+ *   method: 'eth_createAccessList',
+ *   params: [{
+ *     from: '0x...',
+ *     to: '0x...',
+ *     data: '0x...'
+ *   }]
+ * })
  */

12-28: Consider explicit blockTag validation and default

The blockTag parameter is passed through without validation or default value. Consider adding explicit handling for different block tag formats (latest, pending, earliest, or block number).

Consider adding validation:

 const response = await callProcedure(client)({
   ...(req.id !== undefined ? { id: req.id } : {}),
   jsonrpc: req.jsonrpc,
   method: 'tevm_call',
   params: [
     {
       ...(gasPrice !== undefined ? { gasPrice } : {}),
       ...(data !== undefined ? { data } : {}),
       ...(gas !== undefined ? { gas } : {}),
       ...(value !== undefined ? { value } : {}),
       ...(to !== undefined ? { to } : {}),
       ...(from !== undefined ? { from } : {}),
-      ...(blockTag !== undefined ? { blockTag } : {}),
+      blockTag: blockTag ?? 'latest', // Provide default
       createAccessList: true,
     },
   ],
 })
packages/decorators/src/actions/tevmActions.js (1)

85-93: Consider enhancing JSDoc documentation

While the implementation is correct and follows the established pattern, consider adding a description to the JSDoc comment explaining the purpose of the deal action, similar to other handlers in the codebase.

 /**
  * @internal
+ * Creates a deal action that allows setting token balances
+ * @see dealHandler
  * @returns {import('@tevm/node').Extension<Pick<import('./TevmActionsApi.js').TevmActionsApi, 'deal'>>}
  */
packages/actions/src/anvil/AnvilHandler.ts (1)

69-70: LGTM! The new AnvilDealHandler type follows the established pattern.

The type definition is consistent with other handlers in the file and properly typed with the corresponding params and result types.

Consider adding a JSDoc comment to document the purpose and usage of this handler, similar to how other handlers have inline comments. Example:

// anvil_deal - Handler for setting ERC20 token balances
export type AnvilDealHandler = (params: AnvilDealParams) => Promise<AnvilDealResult>
packages/actions/src/tevm-request-handler/TevmJsonRpcRequestHandler.ts (1)

82-100: Documentation looks good, but example could be more comprehensive.

The documentation follows the established pattern and clearly describes the purpose of eth_createAccessList. However, the example could be enhanced to be more educational.

Consider expanding the example to include:

  1. More realistic parameter values
  2. Common use cases
  3. Example response structure
 const response = await tevm.request({
   method: 'eth_createAccessList',
   params: [{
-    to: '0x...',
-    data: '0x...'
+    from: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
+    to: '0x1234567890123456789012345678901234567890',
+    data: '0xa9059cbb000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef0000000000000000000000000000000000000000000000056bc75e2d63100000',
+    gas: '0x7530',
+    gasPrice: '0x1e8480',
+    value: '0x0'
   }],
   id: 1,
   jsonrpc: '2.0'
 })
+// Example response:
+// {
+//   accessList: [{
+//     address: '0x1234567890123456789012345678901234567890',
+//     storageKeys: [
+//       '0x0000000000000000000000000000000000000000000000000000000000000001'
+//     ]
+//   }],
+//   gasUsed: '0x7530'
+// }
packages/actions/src/anvil/AnvilParams.ts (2)

Line range hint 1-3: Address the TODO comment about JSDoc documentation.

The comment indicates that JSDoc documentation needs to be updated. Consider reviewing and updating the documentation for all type definitions to ensure accuracy and completeness.


167-174: Consider adding validation constraints and clarifying native token behavior.

The type definition looks good overall, but consider the following improvements:

  1. Add documentation about native token behavior when erc20 is undefined
  2. Consider adding a minimum amount constraint or documentation about valid amount ranges
  3. Add an example usage in the JSDoc comment

Here's a suggested improvement with enhanced documentation:

 export type AnvilDealParams = {
+  /**
+   * The address of the ERC20 token to deal.
+   * If undefined, deals native tokens instead of ERC20
+   */
   erc20?: Address
+  /**
+   * The owner of the dealt tokens.
+   * This address will receive the specified amount of tokens
+   */
   account: Address
+  /**
+   * The amount of tokens to deal.
+   * For ERC20 tokens, this is in the token's smallest unit (e.g., wei for ETH)
+   * Must be a non-negative value
+   */
   amount: bigint
 }
packages/actions/src/anvil/AnvilJsonRpcResponse.ts (1)

148-152: Consider enhancing JSDoc documentation

The type definition is well-structured and follows the established pattern. Consider enhancing the JSDoc comment to include:

  • Purpose of the anvil_deal procedure
  • Expected response format
  • Potential error scenarios

Example:

/**
 * JSON-RPC response for `anvil_deal` procedure
 * Represents the response when setting an account's balance for testing purposes
 * @see AnvilDealResult for the success response format
 * @see AnvilError for possible error cases
 */
packages/actions/src/anvil/AnvilJsonRpcRequest.ts (2)

115-119: Consider enhancing the JSDoc documentation

While the type definition is correct, consider enhancing the JSDoc comment to match the documentation level of other request types in the file. Include details about the purpose of the anvil_deal method and its parameters.

Example enhancement:

 /**
  * JSON-RPC request for `anvil_deal` method
+ * Allows setting up token balances for testing purposes
+ * @see AnvilDealParams for parameter details
  */

Missing implementation for anvil_deal handler

The type definitions for the anvil_deal feature are complete:

  • AnvilDealJsonRpcRequest and AnvilDealJsonRpcResponse types are defined
  • AnvilDealParams and AnvilDealResult types exist
  • AnvilDealProcedure and AnvilDealHandler types are present

However, the actual implementation of the handler is missing. The codebase needs:

  • Implementation of the deal handler function
  • Registration of the handler in the Anvil handler map
🔗 Analysis chain

Line range hint 115-136: Verify complete implementation of anvil_deal feature

Let's ensure all necessary companion types and procedures are in place for the anvil_deal functionality.


Let me gather more information about the AnvilDealResult type and check the actual implementation of the handler.


Let me check one final thing - the actual implementation of the handler in a different pattern since the first attempt didn't find it.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for related implementations and types

echo "Checking for AnvilDealParams definition..."
rg -p "export.*AnvilDealParams.*=" packages/actions/src/anvil/

echo "Checking for anvil_deal procedure implementation..."
rg -p "export.*AnvilDealProcedure" packages/actions/src/anvil/

echo "Checking for response type definition..."
rg -p "export.*AnvilDealJsonRpcResponse" packages/actions/src/anvil/

Length of output: 1188


Script:

#!/bin/bash
# Check for AnvilDealResult and actual implementation

echo "Checking for AnvilDealResult definition..."
rg -p "export.*AnvilDealResult.*=" packages/actions/src/anvil/

echo "Checking for actual handler implementation..."
ast-grep --pattern 'export const deal: AnvilDealHandler = async'

Length of output: 404


Script:

#!/bin/bash
# Check for deal implementation with broader pattern
echo "Checking for deal implementation..."
rg -p "deal.*=.*async.*AnvilDealParams" packages/actions/src/anvil/

echo "Checking handler registration..."
rg -p "deal.*:.*AnvilDealHandler" packages/actions/src/anvil/

Length of output: 289

packages/actions/src/anvil/AnvilProcedure.ts (1)

125-129: Consider enhancing the JSDoc documentation

While the type definition is correct, the JSDoc comment could be more descriptive about the purpose and behavior of the anvil_deal operation. Consider adding details about:

  • What the procedure does
  • Expected parameters
  • Potential use cases

Example enhancement:

/**
 * JSON-RPC procedure for `anvil_deal`
 * Sets the balance of an account to a specific amount.
 * Useful for testing scenarios that require specific account balances.
 * @see AnvilDealJsonRpcRequest for parameter details
 */
packages/actions/src/eth/EthJsonRpcResponse.ts (1)

327-341: LGTM! Consider enhancing the documentation.

The new EthCreateAccessListJsonRpcResponse type is well-structured and follows the established patterns. The type definition is correct and properly uses the Address and Hex types from @tevm/utils.

Consider enhancing the JSDoc comment to include:

  • Purpose of the access list
  • Description of the response fields
  • Example usage
 /**
  * JSON-RPC response for `eth_createAccessList` procedure
+ * 
+ * Returns an access list and gas used for the transaction.
+ * This can be used to include in the `accessList` field of a transaction 
+ * to avoid dynamic gas costs for state access during execution.
+ * 
+ * @property accessList - List of addresses and storage keys that the transaction plans to access
+ * @property accessList[].address - The address of the contract to access
+ * @property accessList[].storageKeys - Array of storage keys to access
+ * @property gasUsed - The amount of gas used for this operation
  */
packages/actions/src/eth/EthProcedure.ts (1)

212-215: Consider adding detailed JSDoc documentation

While the procedure follows the established pattern, consider adding a detailed JSDoc comment explaining the purpose and behavior of the eth_createAccessList procedure, similar to other procedures in the codebase.

Example:

/**
 * JSON-RPC procedure for eth_createAccessList
 * Creates an access list for a transaction.
 * @see https://eips.ethereum.org/EIPS/eip-2930
 */
export type EthCreateAccessListJsonRpcProcedure = (
  request: EthCreateAccessListJsonRpcRequest,
) => Promise<EthCreateAccessListJsonRpcResponse>
packages/memory-client/src/test/requests.spec.ts (2)

243-263: Test case needs additional assertions and error scenarios.

While the basic happy path is covered, consider enhancing the test coverage:

  1. Add error scenarios:
    • Invalid from address
    • Invalid to address
    • Invalid contract data
  2. Add assertions for the complete response object structure
  3. Verify the gas estimation is reasonable for the operation

Here's a suggested enhancement:

 it('should execute eth_createAccessList request', async () => {
   const tevm = createMemoryClient()
+  // Happy path
   const req = {
     method: 'eth_createAccessList',
     params: [
       {
         from: '0x1f420000000000000000000000000000000000ff',
         to: contractAddress,
         data: encodeFunctionData(ERC20.read.balanceOf('0xf0d4c12a5768d806021f80a262b4d39d26c58b8d')),
       },
     ],
     id: 1,
     jsonrpc: '2.0',
   }
   // @ts-expect-error todo doesn't exist in viem yet https://github.com/wevm/viem/discussions/1060
   const res = await tevm.request(req)
   expect(res).toMatchObject({
     accessList: [],
     gasUsed: '0x53b8',
+    error: undefined,
   })
+
+  // Error scenario - Invalid to address
+  const invalidReq = {
+    ...req,
+    params: [{
+      ...req.params[0],
+      to: '0xinvalid'
+    }]
+  }
+  // @ts-expect-error
+  const invalidRes = await tevm.request(invalidReq)
+  expect(invalidRes.error).toBeDefined()
 })

242-243: Maintain consistent test organization.

Consider grouping related test cases together. Since this test involves ERC20 contract interaction, it could be grouped with other ERC20-related tests.

Consider reorganizing the tests using describe blocks:

+  describe('ERC20 operations', () => {
+    // Move existing ERC20-related tests here
     it('should execute eth_createAccessList request', async () => {
       // ... existing test case
     })
+  })
packages/actions/src/eth/EthJsonRpcRequest.ts (2)

296-303: Enhance documentation for eth_createAccessList.

The type definition looks correct, but the documentation could be more descriptive about the purpose and usage of this RPC method.

Consider expanding the documentation to explain:

  • The purpose of access lists
  • When to use this method
  • What the response contains

Line range hint 305-345: Remove duplicate EthAccountsJsonRpcRequest from union type.

There's a duplicate entry for EthAccountsJsonRpcRequest in the EthJsonRpcRequest union type.

Apply this fix:

 export type EthJsonRpcRequest =
 	| EthAccountsJsonRpcRequest
-	| EthAccountsJsonRpcRequest
 	| EthBlockNumberJsonRpcRequest
packages/actions/src/anvil/anvilDealHandler.js (1)

25-41: Consider a more reliable method to identify balance storage slots

Using the access list from eth_createAccessList might not reliably identify the exact storage slots for the balanceOf mapping. Contracts may have different storage layouts due to inheritance patterns or storage optimization techniques.

Consider retrieving the contract's storage layout via Solidity metadata or using EIPs like EIP-717 for standardized storage layouts. Alternatively, if interacting with standard ERC20 contracts, you might assume that the balance mapping is at slot 0 and calculate the storage slot using the account address:

import { keccak256, toHex } from 'viem'

// Compute the storage slot for balances mapping
const slot = keccak256(
  encodeAbiParameters(
    [{ type: 'address' }, { type: 'uint256' }],
    [account, '0'] // '0' is the slot number for the balances mapping
  )
)

This method provides a deterministic way to find the balance storage slot for standard ERC20 tokens.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 1a03258 and 0522e0e.

📒 Files selected for processing (26)
  • .changeset/little-coats-float.md (1 hunks)
  • packages/actions/src/anvil/AnvilHandler.ts (3 hunks)
  • packages/actions/src/anvil/AnvilJsonRpcRequest.ts (3 hunks)
  • packages/actions/src/anvil/AnvilJsonRpcResponse.ts (2 hunks)
  • packages/actions/src/anvil/AnvilParams.ts (1 hunks)
  • packages/actions/src/anvil/AnvilProcedure.ts (3 hunks)
  • packages/actions/src/anvil/AnvilResult.ts (1 hunks)
  • packages/actions/src/anvil/anvilDealHandler.js (1 hunks)
  • packages/actions/src/anvil/anvilDealProcedure.js (1 hunks)
  • packages/actions/src/anvil/anvilDealProcedure.spec.ts (1 hunks)
  • packages/actions/src/anvil/index.ts (1 hunks)
  • packages/actions/src/createHandlers.js (4 hunks)
  • packages/actions/src/eth/EthJsonRpcRequest.ts (3 hunks)
  • packages/actions/src/eth/EthJsonRpcResponse.ts (1 hunks)
  • packages/actions/src/eth/EthProcedure.ts (3 hunks)
  • packages/actions/src/eth/ethCreateAccessListProcedure.js (1 hunks)
  • packages/actions/src/eth/ethCreateAccessListProcedure.spec.ts (1 hunks)
  • packages/actions/src/eth/ethSendTransactionProcedure.js (1 hunks)
  • packages/actions/src/eth/index.ts (1 hunks)
  • packages/actions/src/tevm-request-handler/AnvilRequestType.ts (2 hunks)
  • packages/actions/src/tevm-request-handler/AnvilReturnType.ts (2 hunks)
  • packages/actions/src/tevm-request-handler/EthReturnType.ts (2 hunks)
  • packages/actions/src/tevm-request-handler/TevmJsonRpcRequestHandler.ts (1 hunks)
  • packages/decorators/src/actions/TevmActionsApi.ts (2 hunks)
  • packages/decorators/src/actions/tevmActions.js (3 hunks)
  • packages/memory-client/src/test/requests.spec.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • packages/actions/src/anvil/index.ts
🔇 Additional comments (41)
.changeset/little-coats-float.md (1)

1-8: LGTM! Version bumps are appropriate for the new features.

The changeset correctly documents minor version bumps for all affected packages and provides a clear description of the new features.

Let's verify if all affected packages are included in the version bumps:

✅ Verification successful

The previous results showed the new RPC methods are implemented in @tevm/actions, but we need to verify the changes in memory-client and decorators packages to ensure the version bumps are justified.


The previous results show some references in the decorators package that we need to investigate further, and we need to verify the actual implementation details in memory-client since LICENSE matches aren't relevant.


Version bumps are correctly specified for all affected packages

The verification confirms that all three packages with version bumps are indeed affected by the new features:

  1. @tevm/actions: Contains the core implementation of eth_createAccessList and anvil_deal handlers
  2. @tevm/memory-client: Integrates the new RPC methods (verified in TevmActions.ts and tests)
  3. @tevm/decorators: Provides the deal action API and decorators (verified in TevmActionsApi.ts and tevmActions.js)

The minor version bumps are appropriate as these are new feature additions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential missing package bumps by searching for new RPC methods and actions

# Test 1: Search for new RPC method implementations
# Expect: References only in bumped packages
rg -l "eth_createAccessList|anvil_deal"

# Test 2: Search for new action implementations
# Expect: References only in bumped packages
rg -l "MemoryClient\.deal"

Length of output: 1045


Script:

#!/bin/bash
# Let's search for deal-related implementations in a more comprehensive way
# since the exact "MemoryClient.deal" pattern didn't yield results

# Search for deal method/function definitions
ast-grep --pattern 'deal($$$) { $$$ }'

# Search for deal-related code with context
rg -A 3 '\bdeal\b' packages/memory-client/

# Check if decorators package is actually affected
rg -l '\bdeal\b' packages/decorators/

Length of output: 647


Script:

#!/bin/bash
# Let's check the actual implementation details in decorators package
rg -A 5 '\bdeal\b' packages/decorators/src/actions/

# Check memory-client implementation details
rg -l 'anvil_deal|createAccessList' packages/memory-client/src/

# Look for any deal-related type definitions or interfaces
ast-grep --pattern 'interface $_ { $$$ deal $$$ }'

Length of output: 1682

packages/actions/src/anvil/AnvilResult.ts (1)

34-37: Verify the consistent usage of AnvilDealResult.

Let's verify that this type is properly integrated with related components.

✅ Verification successful

Based on the results, I can generate the final response as we have comprehensive information about the usage of AnvilDealResult across the codebase.

AnvilDealResult type is properly integrated across the codebase

The type is consistently used in all relevant components:

  • Handler implementation (AnvilHandler.ts)
  • JSON-RPC request/response types (AnvilJsonRpcRequest.ts, AnvilJsonRpcResponse.ts)
  • Request/Response type mappings (AnvilRequestType.ts, AnvilReturnType.ts)
  • Test files (anvilDealProcedure.spec.ts)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check the usage of AnvilDealResult type across the codebase
# Expected: Should find references in handler and JSON-RPC related files

echo "Checking for AnvilDealResult usage:"
rg "AnvilDealResult" --type ts

echo -e "\nChecking for anvil_deal method implementations:"
rg "anvil_deal" --type ts

Length of output: 2157

packages/actions/src/eth/ethSendTransactionProcedure.js (1)

Line range hint 15-20: LGTM: Improved transaction parameter handling.

The conditional spreading of parameters is a good approach to prevent undefined values in the transaction object.

packages/actions/src/tevm-request-handler/AnvilRequestType.ts (2)

2-2: LGTM: Import statement follows existing conventions

The new import is correctly placed and follows the established pattern for Anvil request types.


35-35: LGTM: Verify handler implementation

The new mapping is correctly added to the AnvilRequestType. Let's verify the corresponding handler implementation exists.

✅ Verification successful

Handler implementation is complete and well-integrated

The verification shows the anvil_deal handler is properly implemented:

  • Type definition in packages/actions/src/anvil/AnvilHandler.ts
  • Handler implementation in packages/actions/src/anvil/anvilDealHandler.js
  • Test coverage in packages/actions/src/anvil/anvilDealProcedure.spec.ts
  • Integration in the API surface via TevmActionsApi.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the handler implementation for anvil_deal exists
# Expected: Find the handler implementation in the codebase

# Search for AnvilDealHandler type definition
echo "Searching for handler type definition..."
ast-grep --pattern 'type AnvilDealHandler = $_'

# Search for anvil_deal handler implementation
echo "Searching for handler implementation..."
rg -l 'anvil_deal.*handler'

Length of output: 390


Script:

#!/bin/bash
# Let's search for the actual implementation of anvil_deal handler
# First, let's look for files containing 'anvil_deal'
echo "Files containing anvil_deal:"
rg -l "anvil_deal"

# Then, let's look for the actual handler implementation with more context
echo -e "\nHandler implementation context:"
rg -A 5 "anvil_deal.*handler|createAnvilDeal|AnvilDealHandler"

# Let's also check if there's a test file for this handler
echo -e "\nTest files:"
fd "deal.*test|deal.*spec"

Length of output: 1958

packages/actions/src/tevm-request-handler/AnvilReturnType.ts (1)

2-2: LGTM! Clean implementation of the anvil_deal type mapping.

The changes correctly implement the type system for the new anvil_deal JSON-RPC method, following the established patterns in the codebase. The import is properly organized, and the type mapping maintains consistency with other anvil methods.

Also applies to: 38-38

packages/actions/src/anvil/anvilDealProcedure.spec.ts (2)

1-7: LGTM! Imports are well-organized and necessary.

All imports are being utilized and follow a logical organization pattern.


9-38: 🛠️ Refactor suggestion

Enhance test coverage and documentation for ERC20 dealing.

The test case could be improved in several ways:

  1. Add balance verification after dealing tokens
  2. Document the hexadecimal amounts clearly
  3. Verify successful contract deployment
  4. Consider a more meaningful response structure

Consider refactoring the test to include these improvements:

 it('should deal ERC20 tokens', async () => {
   const client = createTevmNode()
   const erc20 = TestERC20.withAddress(createAddress('0x66a44').toString())
+  const account = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
+  const amount = '0xf4240' // 1,000,000 (1M) tokens with 6 decimals

   // Deploy contract
-  await setAccountHandler(client)({
+  const deployResult = await setAccountHandler(client)({
     address: erc20.address,
     deployedBytecode: erc20.deployedBytecode,
   })
+  expect(deployResult.deployed).toBe(true)

   const result = await anvilDealJsonRpcProcedure(client)({
     method: 'anvil_deal',
     params: [
       {
         erc20: erc20.address,
-        account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
-        amount: '0xf4240', // 1M (6 decimals)
+        account,
+        amount,
       },
     ],
     id: 1,
     jsonrpc: '2.0',
   })

+  // Verify token balance
+  const balance = await client.contract({
+    address: erc20.address,
+    abi: erc20.abi,
+  }).read.balanceOf([account])
+  expect(balance.toString()).toBe(amount)

   expect(result).toEqual({
     jsonrpc: '2.0',
     id: 1,
     method: 'anvil_deal',
-    result: {},
+    result: {
+      success: true,
+      balance: amount,
+    },
   })
 })
packages/actions/src/eth/ethCreateAccessListProcedure.spec.ts (1)

1-60: Verify JSON-RPC interface integration.

The test covers the procedure implementation well, but consider adding integration tests to verify:

  • The procedure is correctly registered with the JSON-RPC interface
  • The method name 'eth_createAccessList' is properly mapped
  • The response format adheres to the JSON-RPC spec
packages/actions/src/eth/ethCreateAccessListProcedure.js (3)

30-41: LGTM! Error handling follows JSON-RPC spec

The error handling is well-structured and follows the JSON-RPC 2.0 specification. Good use of TypeScript type assertions for the response object.


49-58: LGTM! Response construction is well-structured

The response format correctly follows the JSON-RPC 2.0 specification and includes appropriate fallback for gasUsed.


9-11: Verify parameter validation

The code extracts transaction parameters but doesn't validate required fields. Some parameters might be required according to the Ethereum JSON-RPC spec.

Let's check the spec and other implementations:

packages/actions/src/eth/index.ts (1)

54-54: LGTM! The new export follows established patterns.

The addition of ethCreateAccessListProcedure export maintains consistency with existing exports in terms of naming convention, file extension, and alphabetical ordering.

Let's verify the existence of the exported file:

✅ Verification successful

The exported file exists and follows the established patterns

The verification confirms that ethCreateAccessListProcedure.js exists at the expected location in packages/actions/src/eth/, making this a valid export statement.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the exported file exists
# Expected: File should exist in the same directory

fd --type f "ethCreateAccessListProcedure.js" packages/actions/src/eth/

Length of output: 128

packages/decorators/src/actions/tevmActions.js (3)

4-4: LGTM: Clean import addition

The dealHandler import is properly integrated into the existing import structure.


108-108: LGTM: Clean integration of dealAction

The dealAction is properly integrated into the tevmActions chain.


4-4: Verify related components for the deal functionality

Let's ensure all required components for the deal functionality are properly set up.

Also applies to: 85-93, 108-108

✅ Verification successful

Let me verify the implementation details of the dealHandler to ensure it's properly set up.


All deal functionality components are properly integrated

The verification confirms that all required components are in place and properly connected:

  • The dealHandler is implemented in packages/actions/src/anvil/anvilDealHandler.js with proper parameter handling
  • The handler is correctly imported and used in anvilDealProcedure.js
  • TevmActionsApi interface includes the deal method type
  • AnvilDealParams type is properly defined with all required fields
  • JSON-RPC request type for anvil_deal is properly set up
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and setup of related deal components

# Check if dealHandler is properly exported from @tevm/actions
echo "Checking dealHandler export..."
rg -l "export.*dealHandler" -g "packages/actions/**/*"

# Check if TevmActionsApi includes deal method type
echo "Checking TevmActionsApi interface..."
rg "deal.*:.*" -g "packages/decorators/src/actions/TevmActionsApi.ts"

# Check for anvil_deal JSON-RPC related files
echo "Checking anvil_deal JSON-RPC components..."
fd -g "**/Anvil*Request.ts" -x rg "anvil_deal" {}

Length of output: 709


Script:

#!/bin/bash
# Check the implementation of dealHandler
echo "Checking dealHandler implementation..."
rg -A 10 "export.*dealHandler" packages/actions/src/anvil/anvilDealHandler.js

# Check if the handler is properly imported and used
echo "Checking handler usage..."
rg "import.*dealHandler" 

# Check for AnvilDealParams type definition
echo "Checking AnvilDealParams type..."
rg -A 5 "type AnvilDealParams"

Length of output: 1143

packages/actions/src/anvil/AnvilHandler.ts (1)

2-2: LGTM! New type imports are properly organized.

The imports are correctly placed within their respective import groups and follow the established pattern.

Also applies to: 18-18

packages/actions/src/tevm-request-handler/TevmJsonRpcRequestHandler.ts (1)

81-100: Verify the referenced types exist.

The documentation references EthCreateAccessListJsonRpcRequest and EthCreateAccessListJsonRpcResponse types.

Let's verify these types are properly defined:

✅ Verification successful

Both types are properly defined and used in the codebase

The search results confirm that both types are well-defined:

  • EthCreateAccessListJsonRpcRequest is defined in packages/actions/src/eth/EthJsonRpcRequest.ts as a JSON-RPC request type for the 'eth_createAccessList' method
  • EthCreateAccessListJsonRpcResponse is defined in packages/actions/src/eth/EthJsonRpcResponse.ts with a proper response structure including accessList field
  • Both types are properly imported and used throughout the codebase, including in the procedure definitions and request handler
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and implementation of the referenced types

# Test 1: Search for EthCreateAccessListJsonRpcRequest type definition
echo "Searching for EthCreateAccessListJsonRpcRequest..."
rg "EthCreateAccessListJsonRpcRequest" -A 5

# Test 2: Search for EthCreateAccessListJsonRpcResponse type definition
echo "Searching for EthCreateAccessListJsonRpcResponse..."
rg "EthCreateAccessListJsonRpcResponse" -A 5

Length of output: 5035

packages/actions/src/anvil/AnvilParams.ts (1)

167-174: Verify the integration with related files.

The type looks well-structured, but let's verify its integration with other components.

✅ Verification successful

Let me gather more specific information about the integration by checking the actual implementation and type usage.


Let me check one final aspect to ensure complete verification of the integration.


Integration is properly implemented and consistent

The verification shows that AnvilDealParams is well integrated across the codebase:

  • Properly imported and used in AnvilHandler.ts, AnvilJsonRpcRequest.ts
  • Correctly typed in JSON-RPC request/response chain
  • Well-tested with both ERC20 and native token scenarios in anvilDealProcedure.spec.ts
  • Has a proper result type definition in AnvilResult.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration of AnvilDealParams with related files

# Test 1: Check if AnvilDealParams is properly imported and used
echo "Checking imports and usage of AnvilDealParams..."
rg -l "AnvilDealParams" --type ts

# Test 2: Verify the consistency of anvil_deal method implementation
echo "Checking anvil_deal method implementation..."
rg "anvil_deal" --type ts

Length of output: 1811


Script:

#!/bin/bash
# Check the actual implementation and type usage in AnvilHandler.ts
echo "Checking AnvilHandler.ts implementation..."
rg -A 5 "AnvilDealParams" packages/actions/src/anvil/AnvilHandler.ts

# Check the JSON-RPC request/response type definitions
echo "Checking JSON-RPC type definitions..."
cat packages/actions/src/anvil/AnvilJsonRpcRequest.ts | grep -A 5 "AnvilDealJsonRpcRequest"

# Check test implementation
echo "Checking test implementation..."
cat packages/actions/src/anvil/anvilDealProcedure.spec.ts

Length of output: 2521


Script:

#!/bin/bash
# Check the actual procedure implementation
echo "Checking anvil deal procedure implementation..."
cat packages/actions/src/anvil/anvilDealProcedure.ts

# Check the result type definition
echo "Checking result type definition..."
cat packages/actions/src/anvil/AnvilResult.ts | grep -A 5 "AnvilDealResult"

Length of output: 447

packages/decorators/src/actions/TevmActionsApi.ts (2)

2-2: LGTM: Import follows existing patterns

The addition of AnvilDealHandler to the imports is consistent with the existing handler types and follows the established pattern.


123-134: Enhance documentation for security and usage clarity

While the implementation looks good, consider the following improvements to the documentation:

  1. Add a warning that this is for testing purposes only
  2. Document how decimals are handled for different tokens
  3. Use a generic address in the example instead of the actual USDC address
  4. Add a note about potential security implications of balance manipulation

Here's a suggested documentation improvement:

 /**
  * Deals ERC20 tokens to an account by overriding the storage of balanceOf(account)
+ * @notice This is a testing utility and should not be used in production
+ * @notice Token amounts should account for the token's decimals (e.g., 6 for USDC, 18 for most tokens)
  * @example
  * ```typescript
  * await tevm.deal({
- *   erc20: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', // Optional: USDC address
+ *   erc20: '0x1234...', // The ERC20 token address
  *   account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
- *   amount: 1000000n // 1 USDC (6 decimals)
+ *   amount: 1000000n // Amount in smallest unit (consider token decimals)
  * })
  * ```
+ * @warning This method directly manipulates storage slots and bypasses normal token transfer mechanics
  */

Let's verify if this functionality is properly gated in the implementation:

packages/actions/src/tevm-request-handler/EthReturnType.ts (2)

7-7: LGTM! Import follows established patterns.

The new import is correctly placed and follows the existing alphabetical ordering.


85-85: LGTM! Type mapping is properly integrated.

The new eth_createAccessList mapping follows the established pattern and enhances type safety for the new RPC method.

packages/actions/src/anvil/AnvilJsonRpcResponse.ts (2)

7-7: LGTM: Import follows established patterns

The addition of AnvilDealResult to the imports maintains consistency with existing patterns and proper ESM import syntax.


Line range hint 1-152: Verify state handling implications

The file contains TODOs about aligning dump/load state functionality. Since anvil_deal modifies account state, verify if these state handling improvements should be addressed first:

// Relevant TODOs in file:
// TODO make this the same as our dump state
// TODO make this the same as our load state

Let's check for state handling dependencies:

packages/actions/src/anvil/AnvilJsonRpcRequest.ts (2)

4-4: LGTM: Import statement follows project conventions

The import statement is properly placed and follows the existing patterns in the file.


136-136: LGTM: Union type properly updated

The AnvilDealJsonRpcRequest is correctly added to the union type, maintaining consistency with the existing pattern.

packages/actions/src/anvil/AnvilProcedure.ts (4)

Line range hint 2-18: LGTM: Import declarations are well-structured

The new AnvilDealJsonRpcRequest import is correctly added and follows the established pattern.


Line range hint 19-35: LGTM: Response type imports are properly organized

The new AnvilDealJsonRpcResponse import is correctly added and maintains consistency with existing response types.


131-146: LGTM: Union type correctly updated

The AnvilDealProcedure is properly added to the AnvilProcedure union type, maintaining type safety and consistency.


Line range hint 1-146: Verify integration with related components

The type definitions look good, but let's verify the integration with related components.

✅ Verification successful

Integration looks complete and well-tested

The verification shows proper integration:

  • Comprehensive test coverage in anvilDealProcedure.spec.ts covering both ERC20 and native token scenarios
  • Complete implementation with proper handler, procedure, request/response types, and results
  • Well-documented procedure with JSDoc examples
  • Proper error handling in place

The only missing elements (client/transport directories) appear to be due to a different repository structure, which is expected as these are likely handled at a higher level.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify proper integration of anvil_deal procedure
# Check for corresponding handler implementation
echo "Checking for AnvilDealHandler implementation..."
rg "class.*AnvilDealHandler|interface.*AnvilDealHandler" -t ts

# Check for corresponding test files
echo "Checking for related test files..."
fd -e test.ts -e spec.ts . | rg -i "anvildeal"

# Check for documentation updates
echo "Checking for documentation updates..."
fd "README.md" | xargs rg -l "anvil_deal"

Length of output: 474


Script:

#!/bin/bash
# Let's check the test file content and handler implementation
echo "Checking test file content..."
cat packages/actions/src/anvil/anvilDealProcedure.spec.ts

echo -e "\nChecking for handler implementation..."
rg "anvil_deal" -A 5 -B 5 packages/actions/src/anvil/

echo -e "\nChecking for usage in client/transport..."
rg "AnvilDealProcedure|anvil_deal" packages/actions/src/client/ packages/actions/src/transport/

Length of output: 12596

packages/actions/src/eth/EthProcedure.ts (3)

7-7: LGTM: Import addition follows conventions

The new import maintains alphabetical order and follows the established pattern.


48-48: LGTM: Response type import follows conventions

The new response type import maintains alphabetical order and follows the established pattern.


212-215: Verify procedure integration and implementation

Let's ensure the new procedure is properly integrated:

✅ Verification successful

Let me gather more specific information about the implementation and test coverage.


Let me check for the actual implementation file since we've seen the tests and integration but not the core implementation.


Procedure is properly integrated and implemented

The verification shows a complete and proper integration:

  • Implementation exists in ethCreateAccessListProcedure.js with proper error handling and type safety
  • Comprehensive test coverage with contract deployment and RPC call testing
  • Correctly registered in TevmJsonRpcRequestHandler.ts with proper documentation
  • Types properly defined in request/response interfaces
  • Properly exported through the package index

The procedure is well-integrated into the codebase with all necessary components in place.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration and implementation of eth_createAccessList

# Test 1: Check if the procedure is registered in handlers
echo "Checking procedure registration..."
rg -l "eth_createAccessList" --type ts

# Test 2: Look for implementation file
echo "Looking for implementation..."
fd -e ts -e js createAccessList

# Test 3: Check for test coverage
echo "Checking test coverage..."
fd -e spec.ts -e test.ts createAccessList

Length of output: 700


Script:

#!/bin/bash
# Check the actual implementation and test details

# Look at the test file content
echo "=== Test Implementation ==="
cat packages/actions/src/eth/ethCreateAccessListProcedure.spec.ts

# Check how it's integrated in the request handler
echo -e "\n=== Handler Integration ==="
rg -A 5 -B 5 "eth_createAccessList" packages/actions/src/tevm-request-handler/TevmJsonRpcRequestHandler.ts

# Check the request/response type definitions
echo -e "\n=== Type Definitions ==="
rg -A 3 "EthCreateAccessList" packages/actions/src/eth/EthJsonRpcRequest.ts
rg -A 3 "EthCreateAccessList" packages/actions/src/eth/EthJsonRpcResponse.ts

Length of output: 3046


Script:

#!/bin/bash
# Check the implementation file
echo "=== Implementation ==="
cat packages/actions/src/eth/ethCreateAccessListProcedure.js || cat packages/actions/src/eth/ethCreateAccessListProcedure.ts

# Check if it's exported properly
echo -e "\n=== Exports Check ==="
rg -A 2 "export.*ethCreateAccessListProcedure" packages/actions/src/eth/

Length of output: 2598

packages/actions/src/createHandlers.js (3)

8-8: LGTM: New imports follow established patterns.

The new imports for anvilDealJsonRpcProcedure and ethCreateAccessListProcedure maintain consistency with the existing import structure and naming conventions.

Also applies to: 29-29


97-97: LGTM: New eth handler follows established patterns.

The addition of eth_createAccessList handler maintains consistency with existing handler patterns and is correctly placed in alphabetical order.


151-151: Verify namespace mappings for the new anvil_deal handler.

The anvil_deal handler addition looks good. Let's verify that the namespace mappings are correctly generated.

✅ Verification successful

Let me gather more information about the namespace mappings implementation to verify this thoroughly.


Namespace mappings for anvil_deal are correctly implemented

The codebase shows that all anvil handlers, including the new anvil_deal, are automatically mapped to other namespaces through Object.fromEntries transformations:

  • tevm_deal via key.replace('anvil', 'tevm')
  • ganache_deal via key.replace('anvil', 'ganache')
  • hardhat_deal via key.replace('anvil', 'hardhat')
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the new anvil_deal handler is correctly mapped across all namespaces

# Test: Search for all deal-related handlers. Expect: anvil_deal, tevm_deal, ganache_deal, hardhat_deal
rg --type js "(?:anvil|tevm|ganache|hardhat)_deal.*?:" -A 1

Length of output: 243


Script:

#!/bin/bash
# Check the implementation of namespace mappings
rg --type js "const \w+Handlers = Object\.fromEntries" -A 5 -B 5

Length of output: 1661

packages/actions/src/eth/EthJsonRpcRequest.ts (1)

14-14: Verify the impact of making from optional.

Making the from field optional is technically correct per Ethereum JSON-RPC spec, but this is a breaking change that could affect existing code.

Let's verify the usage:

✅ Verification successful

Let me gather more information to verify the impact comprehensively.


Based on the search results, I can now generate the final response:

Making from optional is safe and aligns with Ethereum JSON-RPC spec

The change to make from optional in JsonRpcTransaction is safe because:

  • No code in the codebase assumes from is required through destructuring or direct access
  • The type is used consistently in RPC method parameters (eth_call, eth_estimateGas, eth_sendTransaction, eth_createAccessList) where from is indeed optional per Ethereum spec
  • No interfaces extend JsonRpcTransaction that might be affected by this change
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for code that assumes `from` is required
# Look for destructuring or direct access without optional chaining
rg -g '*.{ts,js}' 'const.*\{.*from.*\}.*:.*JsonRpcTransaction|\.from\s+=' -A 2

Length of output: 1208


Script:

#!/bin/bash
# Search for all usages of JsonRpcTransaction type and from field
rg -g '*.{ts,js}' 'JsonRpcTransaction' -B 2 -A 2

# Also search for any code that might be validating the from field
rg -g '*.{ts,js}' 'from.*required|required.*from' -B 2 -A 2

# Look for type extensions or implementations
ast-grep --pattern 'interface $_ extends JsonRpcTransaction'

Length of output: 2463

packages/actions/src/anvil/anvilDealHandler.js (3)

16-21: Logic appropriately handles non-ERC20 balances

The code correctly delegates to setAccountHandler to set the account's balance directly when erc20 is not provided. This ensures that non-ERC20 balances are handled properly.


23-23: Conversion of amount to 32-byte hex string is correct

Using numberToHex(amount, { size: 32 }) accurately converts the amount into a 32-byte hexadecimal string, which is suitable for storage operations.


46-56: ⚠️ Potential issue

Verify that modified storage slots correspond to the balance mapping

Relying solely on the access list from eth_createAccessList may not guarantee that the storage slots correspond to the ERC20 balanceOf mapping, especially if the contract uses a non-standard storage layout or proxy patterns. It's important to ensure that you're modifying the correct storage slots to prevent unintended side effects.

To confirm that the storage slots correspond to the balanceOf mapping, you can analyze the contract's storage layout. Here's a script to help verify the correct storage slot:

Ensure that the storage slot you're modifying matches the balanceOf mapping slot in the ERC20 contract.

✅ Verification successful

Based on the gathered information, I can now provide the final response:

The storage slot determination is secure through eth_createAccessList

The implementation correctly identifies the storage slots by simulating a balanceOf call through eth_createAccessList. This is a secure approach because:

  1. It uses the actual contract's storage layout by simulating the exact balanceOf function call
  2. The access list returned contains only the storage slots that are actually accessed during the balanceOf execution
  3. The implementation doesn't make assumptions about the storage layout but rather lets the EVM identify the correct slots

The review comment's concern about non-standard storage layouts or proxy patterns is addressed because eth_createAccessList will return the correct storage slots regardless of the contract's implementation details.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the storage slot for the balance mapping in the ERC20 contract.

# Test: Retrieve the storage layout of the contract to identify the balance mapping slot.
# Expected result: The slot used corresponds to the standard ERC20 balance mapping slot (usually slot 0).

# Fetch the contract's ABI and storage layout using `cast` (if available) or other tools.
# Note: Replace `<YOUR_ETH_NODE_URL>` with your Ethereum node URL.

# Fetch the contract's source code and storage layout (requires source verification)
curl -X POST -H "Content-Type: application/json" --data '{
  "jsonrpc":"2.0",
  "method":"eth_getCode",
  "params":["'"$erc20"'", "latest"],
  "id":1
}' <YOUR_ETH_NODE_URL>

# Analyze the storage layout to find the slot for `balanceOf`
# Since this script requires interaction with an Ethereum node and possibly Etherscan API, please ensure you have access and replace placeholders accordingly.

Length of output: 167


Script:

#!/bin/bash
# Let's analyze the code to understand how the storage slots are obtained and used

# First, let's find where accessListResponse is generated
rg -A 5 "accessListResponse" --type js

# Then check for any tests or documentation about storage slots
rg -l "storage.*slot|slot.*storage" --type js

# Look for any related anvil storage manipulation code
rg -A 5 "anvil_setStorageAt" --type js

# Check for any documentation about storage slot handling
fd README.md | xargs rg "storage"

Length of output: 5635


Script:

#!/bin/bash
# Let's examine how the storage slots are determined through eth_createAccessList

# Check the context around eth_createAccessList usage
rg -B 10 -A 10 "eth_createAccessList" --type js

# Look for any test files that might provide insights
fd test -t f | xargs rg "eth_createAccessList|anvil_setStorageAt"

# Check for any ERC20-related code that might show how balances are handled
rg -A 5 "balanceOf" --type js

Length of output: 18637

Comment on lines +40 to +61
it('should deal native tokens when no erc20 address provided', async () => {
const client = createTevmNode()

const result = await anvilDealJsonRpcProcedure(client)({
method: 'anvil_deal',
params: [
{
account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
amount: '0xde0b6b3a7640000', // 1 ETH
},
],
id: 1,
jsonrpc: '2.0',
})

expect(result).toEqual({
jsonrpc: '2.0',
id: 1,
method: 'anvil_deal',
result: {},
})
})
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

Enhance test coverage for native token dealing.

Similar to the ERC20 test case, this test could benefit from additional verifications and documentation.

Consider applying these improvements:

 it('should deal native tokens when no erc20 address provided', async () => {
   const client = createTevmNode()
+  const account = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
+  const amount = '0xde0b6b3a7640000' // 1 ETH (1e18 wei)

+  // Get initial balance
+  const initialBalance = await client.getBalance({
+    address: account,
+  })

   const result = await anvilDealJsonRpcProcedure(client)({
     method: 'anvil_deal',
     params: [
       {
-        account: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
-        amount: '0xde0b6b3a7640000', // 1 ETH
+        account,
+        amount,
       },
     ],
     id: 1,
     jsonrpc: '2.0',
   })

+  // Verify balance increase
+  const finalBalance = await client.getBalance({
+    address: account,
+  })
+  expect(finalBalance - initialBalance).toBe(BigInt(amount))

   expect(result).toEqual({
     jsonrpc: '2.0',
     id: 1,
     method: 'anvil_deal',
-    result: {},
+    result: {
+      success: true,
+      balance: amount,
+    },
   })
 })

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +24 to +39
// test createAccessList with JSON-RPC format
const result = await ethCreateAccessListProcedure(client)({
method: 'eth_createAccessList',
params: [
{
data: encodeFunctionData({
abi: erc20.abi,
functionName: 'balanceOf',
args: [erc20.address],
}),
to: erc20.address,
},
],
id: 1,
jsonrpc: '2.0',
})
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 test cases for edge cases and error scenarios.

Consider adding test cases for:

  • Invalid contract addresses
  • Invalid function signatures
  • Empty or malformed parameters
  • Gas estimation edge cases

Would you like me to help generate additional test cases for these scenarios?

Comment on lines +15 to +22
expect(
(
await setAccountHandler(client)({
address: erc20.address,
deployedBytecode: erc20.deployedBytecode,
})
).errors,
).toBeUndefined()
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

Enhance contract deployment assertions.

While checking for undefined errors is good, consider adding positive assertions to verify the contract was deployed successfully, such as checking the contract code at the deployed address.

 expect(
   (
     await setAccountHandler(client)({
       address: erc20.address,
       deployedBytecode: erc20.deployedBytecode,
     })
   ).errors,
 ).toBeUndefined()
+// Add verification of successful deployment
+const code = await client.request({
+  method: 'eth_getCode',
+  params: [erc20.address, 'latest']
+})
+expect(code).toBe(erc20.deployedBytecode)
📝 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
expect(
(
await setAccountHandler(client)({
address: erc20.address,
deployedBytecode: erc20.deployedBytecode,
})
).errors,
).toBeUndefined()
expect(
(
await setAccountHandler(client)({
address: erc20.address,
deployedBytecode: erc20.deployedBytecode,
})
).errors,
).toBeUndefined()
// Add verification of successful deployment
const code = await client.request({
method: 'eth_getCode',
params: [erc20.address, 'latest']
})
expect(code).toBe(erc20.deployedBytecode)

Comment on lines +41 to +58
expect(result).toMatchInlineSnapshot(`
{
"id": 1,
"jsonrpc": "2.0",
"method": "eth_createAccessList",
"result": {
"accessList": [
{
"address": "0x0000000000000000000000000000000000066a44",
"storageKeys": [
"0xf1accc61b11ca39f2c1d4ba4a393d616196b642a5f638560763cb25d022dff56",
],
},
],
"gasUsed": "0x5e0f",
},
}
`)
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 explicit assertions alongside the snapshot.

While snapshots are useful, consider adding explicit assertions to make the test's expectations clearer and more maintainable.

+// Add explicit assertions before the snapshot
+expect(result.result.accessList).toHaveLength(1)
+expect(result.result.accessList[0].address).toBe(erc20.address)
+expect(result.result.accessList[0].storageKeys).toHaveLength(1)
+expect(result.result.gasUsed).toBeTruthy()
+
 expect(result).toMatchInlineSnapshot(/* ... */)

Comment on lines +43 to +47
// Convert the accessList from Record<Address, Set<Hex>> to the expected format
const formattedAccessList = Object.entries(response.result.accessList).map(([address, storageKeys]) => ({
address: /** @type {import('abitype').Address}*/ (address),
storageKeys: Array.from(storageKeys),
}))
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

Consider adding address format validation

While the type assertion ensures TypeScript compatibility, runtime validation of the address format would improve reliability.

Consider adding validation:

+const isValidAddress = (addr) => /^0x[0-9a-fA-F]{40}$/.test(addr)
+
 const formattedAccessList = Object.entries(response.result.accessList).map(([address, storageKeys]) => ({
+  if (!isValidAddress(address)) {
+    throw new Error(`Invalid address format: ${address}`)
+  }
   address: /** @type {import('abitype').Address}*/ (address),
   storageKeys: Array.from(storageKeys),
 }))

Committable suggestion skipped: line range outside the PR's diff.

...(request.id !== undefined ? { id: request.id } : {}),
method: 'anvil_deal',
error: {
// @ts-expect-error being lazy here
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

Resolve TypeScript errors instead of suppressing them

The comment // @ts-expect-error being lazy here indicates suppression of a TypeScript error without proper resolution. It's better to address the underlying type issue to improve code quality and maintainability.

Apply this diff to fix the TypeScript error:

-				// @ts-expect-error being lazy here
 				code: (result.errors[0]?.code ?? -32000).toString(),
+				// Ensure 'code' is of the correct type
+				code: result.errors[0]?.code ?? -32000,

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +24 to +25
const [{ erc20, account, amount }] = request.params

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

Add validation for request parameters to prevent runtime errors

The code assumes that request.params is an array with at least one object. If request.params is undefined, empty, or not structured as expected, this could cause a runtime error. Adding validation for request.params will improve robustness.

Apply this diff to add parameter validation:

 export const anvilDealJsonRpcProcedure = (client) => async (request) => {
+	if (!Array.isArray(request.params) || request.params.length === 0 || typeof request.params[0] !== 'object') {
+		return {
+			jsonrpc: request.jsonrpc,
+			...(request.id !== undefined ? { id: request.id } : {}),
+			error: {
+				code: -32602,
+				message: 'Invalid params: Expected an array with at least one object.',
+			},
+		}
+	}
 	const [{ erc20, account, amount }] = request.params

Committable suggestion skipped: line range outside the PR's diff.

const result = await dealHandler(client)({
...(erc20 !== undefined ? { erc20 } : {}),
account,
amount: hexToBigInt(amount),
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

Handle potential errors when converting 'amount' with 'hexToBigInt'

If amount is not a valid hex string, hexToBigInt(amount) may throw an error. To prevent runtime exceptions, add error handling or input validation for amount.

Apply this diff to include error handling:

+	let parsedAmount
+	try {
+		parsedAmount = hexToBigInt(amount)
+	} catch (error) {
+		return {
+			jsonrpc: request.jsonrpc,
+			...(request.id !== undefined ? { id: request.id } : {}),
+			error: {
+				code: -32602,
+				message: 'Invalid amount parameter: must be a valid hex string.',
+			},
+		}
+	}

And update the amount assignment:

-		amount: hexToBigInt(amount),
+		amount: parsedAmount,

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +26 to +47
const result = await dealHandler(client)({
...(erc20 !== undefined ? { erc20 } : {}),
account,
amount: hexToBigInt(amount),
})

if ('errors' in result && result.errors) {
/**
* @type {import('./AnvilJsonRpcResponse.js').AnvilDealJsonRpcResponse}
*/
const out = {
jsonrpc: request.jsonrpc,
...(request.id !== undefined ? { id: request.id } : {}),
method: 'anvil_deal',
error: {
// @ts-expect-error being lazy here
code: (result.errors[0]?.code ?? -32000).toString(),
message: result.errors[0]?.message ?? result.errors[0]?.name ?? 'An unknown error occured',
},
}
return out
}
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

Add error handling for exceptions thrown by 'dealHandler'

If dealHandler throws an exception, the current code does not catch it, which may lead to unhandled promise rejections. Wrapping the dealHandler call in a try-catch block will ensure proper error handling and return a valid JSON-RPC error response.

Apply this diff to add error handling:

 export const anvilDealJsonRpcProcedure = (client) => async (request) => {
 	const [{ erc20, account, amount }] = request.params

+	try {
 		const result = await dealHandler(client)({
 			...(erc20 !== undefined ? { erc20 } : {}),
 			account,
 			amount: hexToBigInt(amount),
 		})

 		if ('errors' in result && result.errors) {
 			const out = {
 				jsonrpc: request.jsonrpc,
 				...(request.id !== undefined ? { id: request.id } : {}),
-				method: 'anvil_deal',
 				error: {
 					code: result.errors[0]?.code ?? -32000,
 					message: result.errors[0]?.message ?? result.errors[0]?.name ?? 'An unknown error occurred',
 				},
 			}
 			return out
 		}

 		return {
 			jsonrpc: request.jsonrpc,
 			...(request.id !== undefined ? { id: request.id } : {}),
-			method: 'anvil_deal',
 			result: {},
 		}
+	} catch (error) {
+		return {
+			jsonrpc: request.jsonrpc,
+			...(request.id !== undefined ? { id: request.id } : {}),
+			error: {
+				code: -32603,
+				message: error.message || 'Internal error',
+			},
+		}
+	}
 }
📝 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 result = await dealHandler(client)({
...(erc20 !== undefined ? { erc20 } : {}),
account,
amount: hexToBigInt(amount),
})
if ('errors' in result && result.errors) {
/**
* @type {import('./AnvilJsonRpcResponse.js').AnvilDealJsonRpcResponse}
*/
const out = {
jsonrpc: request.jsonrpc,
...(request.id !== undefined ? { id: request.id } : {}),
method: 'anvil_deal',
error: {
// @ts-expect-error being lazy here
code: (result.errors[0]?.code ?? -32000).toString(),
message: result.errors[0]?.message ?? result.errors[0]?.name ?? 'An unknown error occured',
},
}
return out
}
try {
const result = await dealHandler(client)({
...(erc20 !== undefined ? { erc20 } : {}),
account,
amount: hexToBigInt(amount),
})
if ('errors' in result && result.errors) {
/**
* @type {import('./AnvilJsonRpcResponse.js').AnvilDealJsonRpcResponse}
*/
const out = {
jsonrpc: request.jsonrpc,
...(request.id !== undefined ? { id: request.id } : {}),
error: {
// @ts-expect-error being lazy here
code: (result.errors[0]?.code ?? -32000).toString(),
message: result.errors[0]?.message ?? result.errors[0]?.name ?? 'An unknown error occured',
},
}
return out
}
return {
jsonrpc: request.jsonrpc,
...(request.id !== undefined ? { id: request.id } : {}),
result: {},
}
} catch (error) {
return {
jsonrpc: request.jsonrpc,
...(request.id !== undefined ? { id: request.id } : {}),
error: {
code: -32603,
message: error.message || 'Internal error',
},
}
}

Comment on lines +42 to +44
if (!accessListResponse.result?.accessList) {
throw new Error('Failed to get access list')
}
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

Enhance error handling for access list retrieval failure

The current error message might not provide sufficient context for debugging. Consider including additional details about the failure to aid in troubleshooting.

Apply this diff to improve the error message:

-if (!accessListResponse.result?.accessList) {
-	throw new Error('Failed to get access list')
+if (!accessListResponse.result?.accessList) {
+	throw new Error(`Failed to retrieve access list for ERC20 contract at address ${erc20}`)
}

Committable suggestion skipped: line range outside the PR's diff.

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