Skip to content

2025 07 15 allowance op - #360

Merged
thedavidmeister merged 8 commits into
mainfrom
2025-07-15-allowance-op
Jul 15, 2025
Merged

thedavidmeister merged 8 commits into
mainfrom
2025-07-15-allowance-op

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jul 15, 2025 •

Copy link
Copy Markdown
Contributor

Motivation

Solution

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • New Features

    • Enabled the ERC20 allowance operation, allowing users to access and use the new "erc20-allowance" opcode.
    • Allowance values are now provided as floating-point numbers, reflecting token decimals for more accurate calculations.
  • Bug Fixes

    • Updated tests to support the new floating-point representation for ERC20 allowances.

@coderabbitai

coderabbitai Bot commented Jul 15, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

The changes activate and integrate the erc20-allowance opcode into the standard operations library. This includes updating type signatures to use OperandV2, converting allowance results to floating-point representations, and enabling related tests. The opcode is now fully functional, with parsing, integrity, and execution logic included.

Changes

File(s) Change Summary
src/lib/op/LibAllStandardOps.sol Enabled erc20-allowance opcode: imported module, updated opcode count, metadata, handlers, and function pointers.
src/lib/op/erc20/LibOpERC20Allowance.sol Updated to use OperandV2, added floating-point conversion for allowance, updated function signatures.
src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.sol Updated referenceFn to use StackItem arrays instead of uint256 arrays for inputs and outputs.
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol Reactivated and updated test contract and functions to use OperandV2 and floating-point allowance handling.
test/src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.t.sol Reactivated and updated test contract and functions to use OperandV2 and StackItem abstractions.
.gas-snapshot Updated gas snapshot to reflect new tests and minor changes in gas usage and execution times.

Sequence Diagram(s)

sequenceDiagram
    participant Interpreter as Interpreter
    participant LibAllStandardOps as LibAllStandardOps
    participant LibOpERC20Allowance as LibOpERC20Allowance
    participant ERC20 as ERC20 (IERC20Metadata)

    Interpreter->>LibAllStandardOps: Execute opcode "erc20-allowance"
    LibAllStandardOps->>LibOpERC20Allowance: run(state, operandV2, stackTop)
    LibOpERC20Allowance->>ERC20: allowance(owner, spender)
    ERC20-->>LibOpERC20Allowance: allowanceValue (uint256)
    LibOpERC20Allowance->>ERC20: decimals()
    ERC20-->>LibOpERC20Allowance: decimals (uint8)
    LibOpERC20Allowance->>LibOpERC20Allowance: Convert allowanceValue to Float using decimals
    LibOpERC20Allowance-->>LibAllStandardOps: Return Float result
    LibAllStandardOps-->>Interpreter: Result on stack
Loading

📜 Recent review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 98b558d and a0236f1.

📒 Files selected for processing (2)
  • .gas-snapshot (18 hunks)
  • src/lib/op/erc20/LibOpERC20Allowance.sol (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: thedavidmeister
PR: rainlanguage/rain.interpreter#360
File: src/lib/op/erc20/LibOpERC20Allowance.sol:0-0
Timestamp: 2025-07-15T11:31:27.986Z
Learning: In the rainlanguage/rain.interpreter project, forge (Foundry's formatting tool) handles code formatting automatically, so formatting-related suggestions are not actionable.
src/lib/op/erc20/LibOpERC20Allowance.sol (6)
Learnt from: thedavidmeister
PR: rainlanguage/rain.interpreter#360
File: src/lib/op/erc20/LibOpERC20Allowance.sol:35-36
Timestamp: 2025-07-15T11:31:10.064Z
Learning: In the rain.interpreter codebase, when working with ERC20 tokens that may not implement the optional decimals() function, the preference is to let the call fail explicitly rather than catching errors and defaulting to 18 decimals. This ensures correctness by avoiding potentially incorrect calculations with assumed decimal values.
Learnt from: thedavidmeister
PR: rainlanguage/rain.interpreter#360
File: src/lib/op/erc20/LibOpERC20Allowance.sol:0-0
Timestamp: 2025-07-15T11:31:27.986Z
Learning: In the rainlanguage/rain.interpreter project, forge (Foundry's formatting tool) handles code formatting automatically, so formatting-related suggestions are not actionable.
Learnt from: thedavidmeister
PR: rainlanguage/rain.interpreter#360
File: src/lib/op/erc20/LibOpERC20Allowance.sol:0-0
Timestamp: 2025-07-15T11:31:35.609Z
Learning: In the rain.interpreter codebase, the team uses forge for automatic code formatting, so manual formatting suggestions are not needed as the tool will handle formatting automatically.
Learnt from: thedavidmeister
PR: rainlanguage/rain.interpreter#360
File: src/lib/op/erc20/LibOpERC20Allowance.sol:35-36
Timestamp: 2025-07-15T11:39:30.175Z
Learning: When providing code review feedback in the rain.interpreter codebase, always check and apply existing learnings consistently. Do not suggest approaches that contradict established preferences already documented in the learnings, such as suggesting error handling with default values when the preference is to let calls fail explicitly.
Learnt from: 0xgleb
PR: rainlanguage/rain.interpreter#334
File: crates/eval/src/fork.rs:489-494
Timestamp: 2025-06-17T10:56:40.904Z
Learning: When analyzing error handling in Rust codebases that use external crates like foundry-evm, verify actual compilation behavior rather than assuming missing trait implementations. The `?` operator often works due to comprehensive error conversion implementations provided by the crate ecosystem.
Learnt from: 0xgleb
PR: rainlanguage/rain.interpreter#334
File: crates/eval/src/fork.rs:489-494
Timestamp: 2025-06-17T10:56:40.904Z
Learning: The foundry-evm backend methods like `replay_until` return error types that are properly convertible to `ForkCallError`, so using the `?` operator works without requiring explicit error mapping. The codebase has comprehensive error handling conversions in place.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-test)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-static)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
  • GitHub Check: rainix (macos-latest, rainix-rs-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
  • GitHub Check: git-clean
🔇 Additional comments (3)
src/lib/op/erc20/LibOpERC20Allowance.sol (3)

16-20: Integrity function correctly declares inputs and outputs.

The function properly specifies 3 inputs (token, owner, spender) and 1 output (allowance), which aligns with the ERC20 allowance functionality.


22-48: Run function implementation is correct and well-documented.

The function properly:

  • Reads the required 3 inputs from the stack
  • Retrieves the ERC20 allowance
  • Converts to floating-point representation with appropriate decimal handling
  • Documents the design decision to ignore the lossless flag with a slither comment

The comment about decimals() being optional correctly notes the potential failure point, which aligns with the codebase's preference to let such calls fail explicitly.


50-68: Reference function correctly implements the same logic with StackItem abstraction.

The function properly:

  • Unwraps StackItem inputs to extract addresses
  • Implements the same allowance retrieval and float conversion logic as the run function
  • Maintains consistency in ignoring the lossless flag with appropriate documentation
  • Returns properly wrapped StackItem output

This consistency between run and reference implementations ensures correct behavior across different execution contexts.


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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🔭 Outside diff range comments (1)
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol (1)

24-98: Remove dead commented-out tests in LibOpERC20Allowance.t.sol

There’s a large block of fully commented test functions (e.g. testOpERC20AllowanceNPRun, testOpERC20AllowanceNPEvalHappy, and the subsequent testOpERC20AllowanceNPEval* cases) between approximately lines 24–98. These stale comments are triggering formatting failures.

• File: test/src/lib/op/erc20/LibOpERC20Allowance.t.sol
– Remove (or, if still needed, uncomment and reformat) the entire commented-out functions block.
– After cleanup, run your formatter (e.g. forge fmt) to verify no lint/format errors remain.
– Commit the deletion of all lines beginning with // function testOpERC20Allowance… and accompanying commented code.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6148b3d and 42f210d.

⛔ Files ignored due to path filters (3)
  • src/generated/Rainterpreter.pointers.sol is excluded by !**/generated/**
  • src/generated/RainterpreterExpressionDeployer.pointers.sol is excluded by !**/generated/**
  • src/generated/RainterpreterParser.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (3)
  • src/lib/op/LibAllStandardOps.sol (6 hunks)
  • src/lib/op/erc20/LibOpERC20Allowance.sol (1 hunks)
  • test/src/lib/op/erc20/LibOpERC20Allowance.t.sol (2 hunks)
🧰 Additional context used
🪛 GitHub Actions: Git is clean
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol

[error] 21-98: Git diff detected changes in the file indicating uncommitted or unexpected modifications (commented/uncommented code changes).

src/lib/op/erc20/LibOpERC20Allowance.sol

[error] 35-55: Git diff detected changes in the file indicating uncommitted or unexpected modifications.

🪛 GitHub Actions: Rainix CI
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol

[error] 24-97: Foundry fmt check failed: commented-out code lines differ in formatting style. Consider consistent comment formatting.

src/lib/op/erc20/LibOpERC20Allowance.sol

[error] 38-41: Foundry fmt check failed: multiline formatting differs. Suggested fix: combine multiple lines into a single line for 'Float tokenAllowanceFloat = LibDecimalFloat.fromFixedDecimalLosslessPacked(...)'.


[error] 58-64: Foundry fmt check failed: multiline formatting differs. Suggested fix: combine multiple lines into a single line for 'Float tokenAllowanceFloat = LibDecimalFloat.fromFixedDecimalLosslessPacked(...)'.

🔇 Additional comments (12)
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol (2)

4-7: LGTM - Import statements activated correctly.

The import statements have been properly uncommented and are consistent with the updated library implementation.


14-23: Test contract activated with correct signature updates.

The test contract has been properly activated with the function signature updated to use OperandV2. The test correctly verifies the opcode expects 3 inputs and 1 output.

src/lib/op/LibAllStandardOps.sol (6)

35-35: Import statement properly activated.

The import for LibOpERC20Allowance has been correctly uncommented and positioned appropriately in the import section.


108-108: Opcode count updated correctly.

The ALL_STANDARD_OPS_LENGTH has been incremented to 35 to account for the newly activated erc20-allowance opcode.


175-178: Opcode metadata properly defined.

The authoring metadata for the erc20-allowance opcode is comprehensive and includes important information about input parameters and saturation behavior on overflow.


394-395: Operand handler correctly configured.

The operand handler is properly set to handleOperandDisallowed, which is appropriate for this opcode that doesn't accept operands.


560-560: Integrity function pointer properly integrated.

The integrity function pointer for LibOpERC20Allowance.integrity has been correctly added to the function pointer array.


672-672: Runtime function pointer properly integrated.

The runtime function pointer for LibOpERC20Allowance.run has been correctly added to the opcode function pointer array.

src/lib/op/erc20/LibOpERC20Allowance.sol (4)

4-11: Import statements updated correctly.

The import statements have been properly uncommented and updated to include the new dependencies for floating-point operations (LibDecimalFloat, Float) and stack operations (StackItem).


16-20: Function signature updated correctly.

The integrity function signature has been properly updated to use OperandV2 instead of Operand, maintaining the correct input/output counts (3 inputs, 1 output).


22-47: Enhanced implementation with floating-point conversion.

The run function has been significantly improved to convert raw allowance values to floating-point representation using the token's decimal precision. This provides more consistent handling of allowance values across different tokens.


49-69: Reference function updated with new type system.

The reference function has been properly updated to use StackItem arrays and floating-point conversion, maintaining consistency with the runtime implementation.

Comment thread src/lib/op/erc20/LibOpERC20Allowance.sol Outdated
Comment thread src/lib/op/erc20/LibOpERC20Allowance.sol
Comment thread src/lib/op/erc20/LibOpERC20Allowance.sol Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
src/lib/op/erc20/LibOpERC20Allowance.sol (1)

35-36: Handle optional decimals() call gracefully.

The decimals() call can fail since it's optional in the ERC20 standard. This issue was previously identified and should be addressed with proper error handling.

-        // This can fail as `decimals` is an OPTIONAL part of the ERC20 standard.
-        uint8 tokenDecimals = IERC20Metadata(address(uint160(token))).decimals();
+        // This can fail as `decimals` is an OPTIONAL part of the ERC20 standard.
+        uint8 tokenDecimals;
+        try IERC20Metadata(address(uint160(token))).decimals() returns (uint8 decimals) {
+            tokenDecimals = decimals;
+        } catch {
+            tokenDecimals = 18; // Default to 18 decimals if not available
+        }
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 42f210d and 4e1aae6.

⛔ Files ignored due to path filters (3)
  • src/generated/Rainterpreter.pointers.sol is excluded by !**/generated/**
  • src/generated/RainterpreterExpressionDeployer.pointers.sol is excluded by !**/generated/**
  • src/generated/RainterpreterParser.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (6)
  • .gas-snapshot (18 hunks)
  • src/lib/op/LibAllStandardOps.sol (7 hunks)
  • src/lib/op/erc20/LibOpERC20Allowance.sol (1 hunks)
  • src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.sol (2 hunks)
  • test/src/lib/op/erc20/LibOpERC20Allowance.t.sol (1 hunks)
  • test/src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.t.sol (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/lib/op/erc20/LibOpERC20Allowance.sol (1)
Learnt from: 0xgleb
PR: rainlanguage/rain.interpreter#334
File: crates/eval/src/fork.rs:489-494
Timestamp: 2025-06-17T10:56:40.904Z
Learning: When analyzing error handling in Rust codebases that use external crates like foundry-evm, verify actual compilation behavior rather than assuming missing trait implementations. The `?` operator often works due to comprehensive error conversion implementations provided by the crate ecosystem.
🔇 Additional comments (15)
src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.sol (1)

38-50: LGTM! Type safety improvements are well implemented.

The update to use StackItem[] for inputs and outputs enhances type safety while maintaining the correct logic flow. The function properly unwraps inputs, performs the allowance query, and wraps the result appropriately.

.gas-snapshot (1)

131-140: Expected gas snapshot updates from opcode activation.

The addition of new gas metrics for LibOpERC20AllowanceTest and LibOpUint256ERC20AllowanceTest aligns with the activation of ERC20 allowance opcodes in the standard operations set.

src/lib/op/LibAllStandardOps.sol (6)

35-35: LGTM! Proper opcode activation.

The import of LibOpERC20Allowance correctly activates the previously commented-out opcode.


108-108: Opcode count correctly updated.

The ALL_STANDARD_OPS_LENGTH is properly incremented from 34 to 36, reflecting the activation of both uint256-erc20-allowance and erc20-allowance opcodes.


163-178: Well-documented opcode metadata.

The authoring metadata provides clear descriptions for both allowance opcodes, correctly noting the lossy float conversion for the erc20-allowance variant to handle "infinite approve" scenarios.


388-395: Operand handlers correctly configured.

Both allowance opcodes are properly configured to disallow operands, which is appropriate for these parameter-less operations.


557-560: Integrity function pointers properly added.

The integrity function pointers for both allowance opcodes are correctly integrated into the standard operations array.


669-672: Runtime function pointers properly added.

The runtime function pointers for both allowance opcodes are correctly integrated into the standard operations array, completing the opcode activation.

test/src/lib/op/erc20/uint256/LibOpUint256ERC20Allowance.t.sol (4)

16-21: LGTM: Integrity test correctly validates input/output counts

The integrity test properly validates that the ERC20 allowance opcode requires exactly 3 inputs (token, owner, spender) and produces 1 output (allowance value).


23-45: LGTM: Runtime test provides comprehensive coverage

The runtime test properly:

  • Uses assumeEtchable to ensure the token address is valid for mocking
  • Wraps inputs as StackItem values following the updated interface
  • Mocks the ERC20 allowance call with appropriate parameters
  • Verifies the call is made exactly twice (once for reference, once for run)
  • Uses opReferenceCheck to validate consistency between reference and actual implementation

47-59: LGTM: String parsing test validates end-to-end functionality

The test properly validates that the opcode can be parsed from a string expression and produces the expected output when the ERC20 allowance call is mocked.


61-92: LGTM: Comprehensive error condition testing

The test suite properly covers all error conditions:

  • Invalid input counts (0, 1, 2, 4 inputs when 3 are required)
  • Invalid output counts (0, 2 outputs when 1 is required)
  • Operand disallowance validation
test/src/lib/op/erc20/LibOpERC20Allowance.t.sol (3)

18-23: LGTM: Integrity test correctly validates input/output counts

The integrity test properly validates that the ERC20 allowance opcode requires exactly 3 inputs and produces 1 output, consistent with the uint256 variant.


54-68: LGTM: Float conversion test logic is sound

The test properly:

  • Mocks both the allowance call and the decimals call
  • Converts the allowance to floating-point representation using the token's decimals
  • Validates the result matches the expected float value

The float conversion approach is appropriate for this opcode variant.


70-101: LGTM: Comprehensive error condition testing

The test suite properly covers all error conditions with appropriate opcode name (erc20-allowance instead of uint256-erc20-allowance):

  • Invalid input counts (0, 1, 2, 4 inputs when 3 are required)
  • Invalid output counts (0, 2 outputs when 1 is required)
  • Operand disallowance validation

Comment thread src/lib/op/erc20/LibOpERC20Allowance.sol Outdated
Comment thread src/lib/op/erc20/LibOpERC20Allowance.sol Outdated
Comment thread test/src/lib/op/erc20/LibOpERC20Allowance.t.sol Outdated
Comment thread test/src/lib/op/erc20/LibOpERC20Allowance.t.sol Outdated
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