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

fix(contracts-rfq): add forwardTo to ZapData for Zap Actions that don't forward assets to the user #3451

Merged
merged 12 commits into from
Dec 10, 2024

Conversation

ChiTimesChi
Copy link
Collaborator

@ChiTimesChi ChiTimesChi commented Dec 9, 2024

Description
This PR enhances TokenZapV1 and ZapDataV1 by adding an optional feature to transfer the proceeds of the Zap Action to the specified forwardTo address. This is useful for creating Zap Actions for contracts that send the funds back to msg.sender rather than the specified address, example being IDefaultPool pool contracts that are used as the source of liquidity on some of the chains.

Summary by CodeRabbit

  • New Features

    • Added support for specifying a forwarding address in multiple functions, enhancing token transfer flexibility.
    • Introduced new error types for improved error handling in contracts.
    • Enhanced zap data functions to accommodate additional parameters for final token and forwarding address.
  • Bug Fixes

    • Improved error handling for zero address tokens in various functions.
  • Tests

    • Updated test cases to validate the new forwarding functionality and ensure correct behavior across different scenarios.

Copy link
Contributor

coderabbitai bot commented Dec 9, 2024

Walkthrough

The changes in this pull request primarily involve modifications to several smart contracts and their respective interfaces to introduce a new parameter, forwardTo, which specifies the address for forwarding token proceeds. This update affects the previewIntent function in the ISynapseIntentPreviewer interface, the ZapDataV1 library, and multiple contracts including SynapseIntentPreviewer, TokenZapV1, and their associated test files. Additionally, new error types and methods have been added to enhance functionality and error handling related to token operations.

Changes

File Path Change Summary
packages/contracts-rfq/contracts/interfaces/ISynapseIntentPreviewer.sol Updated previewIntent function to include address forwardTo parameter.
packages/contracts-rfq/contracts/libs/ZapDataV1.sol Renamed target to finalToken and added forwardTo in ZapData struct. Updated encodeV1 function to accept new parameters and added functions to extract finalToken and forwardTo.
packages/contracts-rfq/contracts/router/SynapseIntentPreviewer.sol Introduced error SIP__NoOpForwardNotSupported. Updated previewIntent and several internal methods to include forwardTo.
packages/contracts-rfq/contracts/zaps/TokenZapV1.sol Added errors for zero balances and addresses. Updated zap and encodeZapData functions to include finalToken and forwardTo. Added internal function _forwardToken for handling token forwarding.
packages/contracts-rfq/deployments/arbitrum/SynapseIntentPreviewer.json Updated contract address, transaction receipt, and ABI to include forwardTo in previewIntent.
packages/contracts-rfq/deployments/arbitrum/TokenZapV1.json Updated contract address and ABI to include new parameters in encodeZapData.
packages/contracts-rfq/deployments/optimism/SynapseIntentPreviewer.json Updated contract address, transaction receipt, and ABI to include forwardTo in previewIntent.
packages/contracts-rfq/deployments/optimism/TokenZapV1.json Updated contract address and ABI to include new parameters in encodeZapData.
packages/contracts-rfq/test/harnesses/ZapDataV1Harness.sol Updated encodeV1 to include finalToken_ and forwardTo_. Added public functions to retrieve these values.
packages/contracts-rfq/test/integration/TokenZapV1.t.sol Updated createFixtures to include finalToken and forwardTo in zapData.
packages/contracts-rfq/test/libs/ZapDataV1.t.sol Updated tests to include finalToken and forwardTo in encodeZapData calls and assertions.
packages/contracts-rfq/test/router/SynapseIntentPreviewer.t.sol Updated various test functions to include forwardTo parameter and added tests for forwarding behavior.
packages/contracts-rfq/test/router/SynapseIntentRouter.BalanceChecks.t.sol Added new tests for handling unspent funds during swaps and unwrapping.
packages/contracts-rfq/test/router/SynapseIntentRouter.t.sol Updated functions to include forwardTo parameter for token operations and added new functionality for handling swaps and deposits.
packages/contracts-rfq/test/zaps/TokenZapV1.GasBench.t.sol Updated getZapData to include additional parameters for flexibility in zap data construction.
packages/contracts-rfq/test/zaps/TokenZapV1.t.sol Renamed and updated methods to reflect new parameters for zap data handling, including new methods for WETH deposits and withdrawals.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SynapseIntentPreviewer
    participant TokenZapV1

    User->>SynapseIntentPreviewer: previewIntent(swapQuoter, forwardTo, tokenIn, tokenOut, amountIn)
    SynapseIntentPreviewer->>TokenZapV1: zap(token, amount, zapData)
    TokenZapV1->>TokenZapV1: encodeZapData(target, payload, amountPosition, finalToken, forwardTo)
    TokenZapV1->>User: forwardToken(finalToken, forwardTo)
Loading

Possibly related PRs

Suggested labels

size/l, needs-go-generate-services/rfq

Suggested reviewers

  • aureliusbtc
  • parodime

🐰 In the realm of code, we hop and play,
New paths for tokens, a bright new way!
With forwardTo added, our zaps now gleam,
A dance of addresses, a developer's dream!
So let’s code together, in joy we’ll unite,
For every small change brings a future so bright! 🌟


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 generate docstrings to generate docstrings for this PR. (Experiment)
  • @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.

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.

@github-actions github-actions bot added the size/l label Dec 9, 2024
@ChiTimesChi ChiTimesChi changed the title fix(contracts-rfq): add forrwardTo to ZapData for Zap Actions that don't forward assets to the user fix(contracts-rfq): add forwardTo to ZapData for Zap Actions that don't forward assets to the user Dec 9, 2024
Copy link

Deploying sanguine-fe with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4b925f9
Status: ✅  Deploy successful!
Preview URL: https://f54631c5.sanguine-fe.pages.dev
Branch Preview URL: https://fix-fbv2-zap-data-funds-reci.sanguine-fe.pages.dev

View logs

Comment on lines +92 to +97
function finalToken(bytes calldata encodedZapData) internal pure returns (address finalToken_) {
// Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.
assembly {
finalToken_ := shr(96, calldataload(add(encodedZapData.offset, OFFSET_FINAL_TOKEN)))
}
}

Check warning

Code scanning / Slither

Assembly usage Warning

Comment on lines +100 to +105
function forwardTo(bytes calldata encodedZapData) internal pure returns (address forwardTo_) {
// Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.
assembly {
forwardTo_ := shr(96, calldataload(add(encodedZapData.offset, OFFSET_FORWARD_TO)))
}
}

Check warning

Code scanning / Slither

Assembly usage Warning

Comment on lines +171 to +182
function _forwardToken(address token, address forwardTo) internal {
// Check the token address and its balance to be safely forwarded.
if (token == address(0)) revert TokenZapV1__TokenZeroAddress();
uint256 amount = token == NATIVE_GAS_TOKEN ? address(this).balance : IERC20(token).balanceOf(address(this));
if (amount == 0) revert TokenZapV1__FinalTokenBalanceZero();
// Forward the full balance of the final token to the specified recipient.
if (token == NATIVE_GAS_TOKEN) {
Address.sendValue({recipient: payable(forwardTo), amount: amount});
} else {
IERC20(token).safeTransfer(forwardTo, amount);
}
}

Check warning

Code scanning / Slither

Dangerous strict equalities Medium

TokenZapV1._forwardToken(address,address) uses a dangerous strict equality:
- amount == 0
Copy link

codecov bot commented Dec 9, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.57904%. Comparing base (2e6bce6) to head (4b925f9).
Report is 1 commits behind head on feat/syn-intent-router.

Additional details and impacted files
@@                       Coverage Diff                        @@
##           feat/syn-intent-router       #3451         +/-   ##
================================================================
- Coverage                98.71087%   98.57904%   -0.13183%     
================================================================
  Files                          11          11                 
  Lines                         543         563         +20     
================================================================
+ Hits                          536         555         +19     
- Misses                          7           8          +1     
Flag Coverage Δ
solidity 98.57904% <100.00000%> (-0.13183%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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: 4

🧹 Outside diff range and nitpick comments (11)
packages/contracts-rfq/test/zaps/TokenZapV1.GasBench.t.sol (1)

45-45: Consider adding test cases for non-zero forwardTo address.

While this file focuses on gas benchmarking, it would be valuable to add test cases that verify the gas consumption when forwardTo is set to a non-zero address, as this represents a real-world usage scenario described in the PR objectives.

Example test case:

+    function test_deposit_erc20_with_forward() public {
+        address forwardTo = makeAddr("forwardTo");
+        bytes memory depositPayload = getVaultPayload(address(erc20), AMOUNT);
+        bytes memory zapData = tokenZap.encodeZapData(
+            address(vault),
+            depositPayload,
+            4 + 32,
+            address(0),
+            forwardTo
+        );
+        erc20.transfer(address(tokenZap), AMOUNT);
+        tokenZap.zap(address(erc20), AMOUNT, zapData);
+        // Check that the vault registered the deposit for forwardTo
+        assertEq(vault.balanceOf(forwardTo, address(erc20)), AMOUNT);
+    }
packages/contracts-rfq/test/integration/TokenZapV1.t.sol (1)

Line range hint 166-168: Update helper functions to support forwardTo parameter

The getDepositPayload function currently hardcodes the user address as the recipient. To properly test the forwarding functionality, consider parameterizing the recipient address:

-function getDepositPayload(address token) public view returns (bytes memory) {
-    return abi.encodeCall(dstVault.deposit, (token, abi.encode(token), DST_AMOUNT, user, abi.encode(user)));
+function getDepositPayload(
+    address token,
+    address recipient
+) public view returns (bytes memory) {
+    return abi.encodeCall(
+        dstVault.deposit,
+        (token, abi.encode(token), DST_AMOUNT, recipient, abi.encode(recipient))
+    );
+}
packages/contracts-rfq/contracts/libs/ZapDataV1.sol (1)

91-98: Review the use of inline assembly for address extraction

The functions finalToken and forwardTo correctly use inline assembly to extract address values from the encoded data. However, to enhance readability and maintainability, consider adding comments within the assembly blocks to explain the logic.

Apply this diff to include explanatory comments:

function finalToken(bytes calldata encodedZapData) internal pure returns (address finalToken_) {
    // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.
    assembly {
+       // calldataload reads 32 bytes from the specified position
+       // We shift right by 96 bits (12 bytes) to obtain the address from the lower 20 bytes
        finalToken_ := shr(96, calldataload(add(encodedZapData.offset, OFFSET_FINAL_TOKEN)))
    }
}

function forwardTo(bytes calldata encodedZapData) internal pure returns (address forwardTo_) {
    // Load 32 bytes from the offset and shift it 96 bits to the right to get the highest 160 bits.
    assembly {
+       // Similar to finalToken_, extract the address from the correct position
        forwardTo_ := shr(96, calldataload(add(encodedZapData.offset, OFFSET_FORWARD_TO)))
    }
}

This will make it easier for future developers to understand the purpose of each operation within the assembly blocks.

Also applies to: 99-106

🧰 Tools
🪛 GitHub Check: Slither

[warning] 92-97: Assembly usage
ZapDataV1.finalToken(bytes) (contracts/libs/ZapDataV1.sol#92-97) uses assembly
- INLINE ASM (contracts/libs/ZapDataV1.sol#94-96)

packages/contracts-rfq/contracts/zaps/TokenZapV1.sol (1)

170-182: Address the potential strict equality issue in _forwardToken

The usage of if (amount == 0) in _forwardToken is flagged due to strict equality comparison, which can be problematic if amount can be a small value subject to rounding errors. Ensure that the logic correctly handles scenarios where the amount is negligibly small.

Consider using require(amount > 0, "Amount must be greater than zero") if a zero amount should revert, or handle zero amounts gracefully if appropriate.

🧰 Tools
🪛 GitHub Check: Slither

[warning] 171-182: Dangerous strict equalities
TokenZapV1._forwardToken(address,address) (contracts/zaps/TokenZapV1.sol#171-182) uses a dangerous strict equality:
- amount == 0 (contracts/zaps/TokenZapV1.sol#175)

packages/contracts-rfq/contracts/router/SynapseIntentPreviewer.sol (3)

24-24: Typographical error in error name: SIP__NoOpForwardNotSupported

The error name SIP__NoOpForwardNotSupported may contain a typo in "Hative" in the function _createHandleHativeSteps.

Review and correct the error name or any related comments to ensure consistency and clarity.


31-34: Update interface documentation for previewIntent method

The previewIntent method signature has changed with the addition of the forwardTo parameter. Ensure that the interface and any inherited documentation reflect this change to maintain consistency.

Update the NatSpec comments to include the forwardTo parameter and explain its purpose.


221-232: Typo in function name _createHandleHativeSteps

The function _createHandleHativeSteps appears to have a typo. It likely should be _createHandleNativeSteps.

Apply this diff to correct the function name:

- function _createHandleHativeSteps(
+ function _createHandleNativeSteps(
    address tokenIn,
    address tokenOut,
    uint256 amountIn,
    address forwardTo
)
    internal
    pure
    returns (ISynapseIntentRouter.StepParams[] memory steps)
{
    if (tokenIn == NATIVE_GAS_TOKEN) {
        // tokenOut is Wrapped Native
        return _toStepsArray(
            _createWrapNativeStep({wrappedNative: tokenOut, msgValue: amountIn, forwardTo: forwardTo})
        );
    }
    // Sanity check tokenOut
    if (tokenOut != NATIVE_GAS_TOKEN) revert SIP__TokenNotNative();
    // tokenIn is Wrapped Native
    return _toStepsArray(_createUnwrapNativeStep({wrappedNative: tokenIn, forwardTo: forwardTo}));
}

Update all references to this function throughout the contract to reflect the corrected name.

Also applies to: 237-237

packages/contracts-rfq/test/zaps/TokenZapV1.t.sol (2)

181-208: Add test cases for wrapping and unwrapping with forwarding

New functions getZapDataUnwrap, getZapDataUnwrapAndForward, getZapDataWrap, and getZapDataWrapAndForward have been introduced. However, corresponding test cases that utilize these functions should be added to verify that wrapping and unwrapping operations with forwarding work as intended.

Consider adding test cases that:

  • Verify successful wrapping and forwarding to a recipient.
  • Test unwrapping and forwarding, both to EOAs and contracts.
  • Check for failure scenarios when finalToken or forwardTo are misuse.

This will enhance the test coverage for the new functionality.


Line range hint 426-438: Use bounded values in property-based tests

In the test test_encodeZapData_roundtrip, ensure that the amount parameter is within a reasonable range to prevent potential overflows or unexpected behavior during encoding and decoding.

Consider bounding the amount parameter using bound(amount, minValue, maxValue); to ensure it stays within safe limits during testing.

packages/contracts-rfq/test/libs/ZapDataV1.t.sol (1)

166-175: Consider extracting common test data setup

The test data setup for invalidEncodedZapData is repeated across multiple test cases. Consider extracting it into a helper function to improve maintainability.

+    function createInvalidEncodedZapData(
+        uint16 version,
+        uint16 amountPosition,
+        address finalToken,
+        address forwardTo,
+        address target,
+        bytes memory payload
+    ) internal pure returns (bytes memory) {
+        return encodeZapData(version, amountPosition, finalToken, forwardTo, target, payload);
+    }
packages/contracts-rfq/test/router/SynapseIntentPreviewer.t.sol (1)

593-650: Consider adding test cases for failed intermediate steps

While the test coverage for successful double-step intents is comprehensive, consider adding test cases for scenarios where intermediate steps fail, such as:

  • Failed swap before unwrap
  • Failed wrap before swap
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2e6bce6 and 4b925f9.

📒 Files selected for processing (16)
  • packages/contracts-rfq/contracts/interfaces/ISynapseIntentPreviewer.sol (2 hunks)
  • packages/contracts-rfq/contracts/libs/ZapDataV1.sol (4 hunks)
  • packages/contracts-rfq/contracts/router/SynapseIntentPreviewer.sol (15 hunks)
  • packages/contracts-rfq/contracts/zaps/TokenZapV1.sol (6 hunks)
  • packages/contracts-rfq/deployments/arbitrum/SynapseIntentPreviewer.json (3 hunks)
  • packages/contracts-rfq/deployments/arbitrum/TokenZapV1.json (4 hunks)
  • packages/contracts-rfq/deployments/optimism/SynapseIntentPreviewer.json (3 hunks)
  • packages/contracts-rfq/deployments/optimism/TokenZapV1.json (4 hunks)
  • packages/contracts-rfq/test/harnesses/ZapDataV1Harness.sol (1 hunks)
  • packages/contracts-rfq/test/integration/TokenZapV1.t.sol (2 hunks)
  • packages/contracts-rfq/test/libs/ZapDataV1.t.sol (6 hunks)
  • packages/contracts-rfq/test/router/SynapseIntentPreviewer.t.sol (12 hunks)
  • packages/contracts-rfq/test/router/SynapseIntentRouter.BalanceChecks.t.sol (1 hunks)
  • packages/contracts-rfq/test/router/SynapseIntentRouter.t.sol (5 hunks)
  • packages/contracts-rfq/test/zaps/TokenZapV1.GasBench.t.sol (1 hunks)
  • packages/contracts-rfq/test/zaps/TokenZapV1.t.sol (11 hunks)
🧰 Additional context used
🪛 GitHub Check: Slither
packages/contracts-rfq/contracts/libs/ZapDataV1.sol

[warning] 92-97: Assembly usage
ZapDataV1.finalToken(bytes) (contracts/libs/ZapDataV1.sol#92-97) uses assembly
- INLINE ASM (contracts/libs/ZapDataV1.sol#94-96)


[warning] 100-105: Assembly usage
ZapDataV1.forwardTo(bytes) (contracts/libs/ZapDataV1.sol#100-105) uses assembly
- INLINE ASM (contracts/libs/ZapDataV1.sol#102-104)

packages/contracts-rfq/contracts/zaps/TokenZapV1.sol

[warning] 171-182: Dangerous strict equalities
TokenZapV1._forwardToken(address,address) (contracts/zaps/TokenZapV1.sol#171-182) uses a dangerous strict equality:
- amount == 0 (contracts/zaps/TokenZapV1.sol#175)

🔇 Additional comments (49)
packages/contracts-rfq/test/zaps/TokenZapV1.GasBench.t.sol (1)

45-45: LGTM! The test correctly adapts to the new interface.

The modification properly handles the new encodeZapData parameters by passing address(0) for both finalToken and forwardTo, which represents the baseline case for gas benchmarking.

packages/contracts-rfq/deployments/optimism/TokenZapV1.json (3)

73-82: LGTM! New parameters align with PR objectives.

The addition of finalToken and forwardTo parameters to encodeZapData properly implements the forwarding functionality described in the PR objectives. The parameter types are correctly defined as addresses.


161-165: LGTM! New error types enhance validation.

The added error types improve the contract's error handling:

  • TokenZapV1__FinalTokenBalanceZero: Ensures operations result in non-zero token balance
  • TokenZapV1__TokenZeroAddress: Validates token address input

These follow the existing error naming convention and provide clear error messages.

Also applies to: 176-180


2-2: Verify the new contract deployment on Optimism.

The contract has been redeployed with a new address. Please ensure the deployment was successful and the contract is properly verified on Optimism block explorer.

Also applies to: 5-6

✅ Verification successful

Contract deployment verified successfully on Optimism

The contract at address 0x6327797F149a75D506aFda46D5fCE6E74fC409D5 is:

  • Successfully deployed and verified on Optimism
  • Contains the expected ABI with new parameters and error types
  • Deployed at block 129029951 which is confirmed to exist on the network
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify contract deployment and bytecode on Optimism

# Check if contract exists and is verified on Optimism
curl -s "https://api-optimistic.etherscan.io/api?module=contract&action=getabi&address=0x6327797F149a75D506aFda46D5fCE6E74fC409D5" | jq .

# Verify block number exists
curl -s "https://api-optimistic.etherscan.io/api?module=block&action=getblockreward&blockno=129029951" | jq .

Length of output: 3333

packages/contracts-rfq/deployments/arbitrum/SynapseIntentPreviewer.json (3)

31-35: LGTM: forwardTo parameter addition

The new forwardTo parameter is correctly added to the previewIntent function with proper type definition. This change aligns with the PR objectives to support forwarding assets to specified addresses.


88-92: LGTM: Error handling enhancement

The addition of SIP__NoOpForwardNotSupported error type enhances the contract's error handling capabilities for cases where forwarding is attempted on no-op intents.


2-2: Verify contract deployment on Arbitrum

The contract has been redeployed to a new address with updated transaction details. This is expected due to the interface changes.

Also applies to: 5-6

packages/contracts-rfq/deployments/arbitrum/TokenZapV1.json (3)

2-2: Contract redeployment verified.

The contract has been redeployed to a new address with updated transaction details, which is expected given the functional changes.

Also applies to: 5-6


161-165: New error types enhance input validation.

The addition of two new error types improves the contract's robustness:

  • TokenZapV1__FinalTokenBalanceZero: Ensures there are tokens to forward
  • TokenZapV1__TokenZeroAddress: Validates token addresses

This is a good practice for providing clear error messages.

Also applies to: 176-180


73-82: New parameters align with PR objectives.

The addition of finalToken and forwardTo parameters to encodeZapData properly implements the requirement to support forwarding assets to a specified address.

Let's verify the integration with related contracts:

✅ Verification successful

Parameters are correctly integrated across the codebase

The verification confirms that the finalToken and forwardTo parameters in TokenZapV1.json are properly aligned with the ZapDataV1 library implementation. The library shows these parameters at the correct offsets (OFFSET_FINAL_TOKEN and OFFSET_FORWARD_TO), and the TokenZapV1 contract properly implements the IZapRecipient interface to handle these parameters.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the consistency of ZapData encoding across the codebase

# Check for matching parameter updates in related files
rg -A 10 "encodeZapData|encodeV1" --type sol

Length of output: 74


Script:

#!/bin/bash
# Search for Solidity files with .sol extension and look for encodeZapData or encodeV1
rg -t sol -g "*.sol" -A 10 "encodeZapData|encodeV1"

# Also check for any interface definitions or implementations
fd -e sol -x cat {} | rg -A 10 "interface.*Zap|contract.*Zap"

Length of output: 14537


Script:

#!/bin/bash
# Let's check the ZapDataV1 library implementation to verify parameter handling
fd -e sol -x cat {} | rg -A 20 "library ZapDataV1"

# Also check for any TokenZapV1 contract implementations
fd -e sol -x cat {} | rg -A 20 "contract TokenZapV1"

Length of output: 4420

packages/contracts-rfq/test/router/SynapseIntentRouter.t.sol (20)

79-81: 'getWrapZapData' function updated with 'finalToken' and 'forwardTo'.

The addition of finalToken and forwardTo parameters in the getWrapZapData function enhances the flexibility of token zapping operations, aligning with the PR objectives.


85-92: 'getUnwrapZapData' function now accepts 'forwardTo' parameter.

The modification to include forwardTo in getUnwrapZapData correctly allows proceeds to be forwarded to a specified address, as intended.


96-105: Updated 'getSwapZapData' to incorporate 'forwardTo'.

The inclusion of the forwardTo parameter in getSwapZapData ensures that swapped tokens can be directed to a specified recipient, which is consistent with the enhancement goals.


115-117: Inclusion of 'finalToken' and 'forwardTo' in 'getDepositZapData'.

Adding finalToken and forwardTo parameters to getDepositZapData improves the modularity and reusability of the code, facilitating better control over token destinations.


429-444: New function 'getSwapForwardERC20Steps' implemented effectively.

The getSwapForwardERC20Steps function correctly sets up the steps for swapping WETH to ERC20 tokens and forwarding them to the user, aligning with the new forwarding functionality.


447-459: Test 'test_swapForwardERC20_exactAmount' added for swapping and forwarding.

The test accurately verifies that the user receives the correct amount of ERC20 tokens after swapping and that the forwarding mechanism works as expected.


462-474: Extra funds handling in 'test_swapForwardERC20_exactAmount_extraFunds' is correct.

The test confirms that extra funds are appropriately utilized when forwarding tokens, ensuring no discrepancies in user balances.


477-479: Deadline exceedance test 'test_swapForwardERC20_exactAmount_revert_deadlineExceeded' is properly implemented.

The test ensures the contract correctly reverts the transaction when the deadline is exceeded, adhering to expected behavior.


481-484: Insufficient amount test 'test_swapForwardERC20_exactAmount_revert_lastStepAmountInsufficient' functions correctly.

This test validates that the contract reverts when the last step amount is insufficient, maintaining transaction integrity.


486-489: Message value check in 'test_swapForwardERC20_exactAmount_revert_msgValueAboveExpected' is accurate.

The test correctly handles scenarios where msgValue is above expected, ensuring proper error handling.


491-503: Full balance swap in 'test_swapForwardERC20_fullBalance' operates as intended.

The test verifies that swapping the full balance works correctly and that tokens are forwarded appropriately.


506-518: Handling extra funds in 'test_swapForwardERC20_fullBalance_extraFunds' is correctly validated.

This test ensures extra funds are accounted for in full balance swaps and that user balances reflect the correct amounts.


520-534: Revert conditions in 'swapForwardERC20' tests are properly checked.

The added tests comprehensively cover revert scenarios, such as deadline exceedance and insufficient amounts, ensuring robust error handling.


538-561: Function 'getSwapUnwrapForwardNativeSteps' added for swapping, unwrapping, and forwarding.

The implementation correctly sets up the steps to swap ERC20 tokens to WETH, unwrap WETH to native tokens, and forward them to the user.


563-576: Test 'test_swapUnwrapForwardNative_exactAmounts' verifies swapping, unwrapping, and forwarding.

The test accurately confirms that the user receives the correct amount of native tokens, ensuring the steps function cohesively.


579-592: Extra funds handling in 'test_swapUnwrapForwardNative_exactAmounts_extraFunds' is validated.

The test ensures that extra funds are correctly utilized in the last forward instruction, updating the user's balance appropriately.


677-695: Test 'test_swapUnwrapForwardNative_exactAmount1_extraFunds_revertWithBalanceChecks' correctly handles extra funds.

The test demonstrates that extra funds are processed when no balance checks are performed, and the user's native balance reflects the additional amount.


780-782: 'zapData' modification in 'getSwapDepositERC20Steps' aligns with updates.

The use of getSwapZapData with address(0) for forwardTo parameter is appropriate for the deposit operation.


Line range hint 780-856: Swap and deposit ERC20 tests added and implemented correctly.

The suite of tests for swapping WETH to ERC20 tokens and depositing them ensures all scenarios, including extra funds and revert conditions, are thoroughly covered.


1173-1175: 'zapData' in 'getUnwrapDepositNativeSteps' correctly updated with 'forwardTo'.

The use of getUnwrapZapData with address(0) for forwardTo parameter aligns with the intended functionality of depositing native tokens.

packages/contracts-rfq/contracts/libs/ZapDataV1.sol (1)

15-18: Offsets in struct definition and constants are updated correctly

The updated offsets for finalToken, forwardTo, and target in the struct definition and their corresponding constants accurately reflect the sizes and positions of the new fields. This ensures that the data is packed correctly and can be decoded reliably.

Also applies to: 22-25

packages/contracts-rfq/contracts/zaps/TokenZapV1.sol (2)

51-51: ⚠️ Potential issue

Redundant check for zero address in zap function

The check if (token == address(0)) revert TokenZapV1__TokenZeroAddress(); may be redundant if the zap function is intended to support native gas tokens (e.g., ETH), which are represented by the constant NATIVE_GAS_TOKEN. Since NATIVE_GAS_TOKEN is set to a specific address, this check could prevent the use of native tokens.

Consider revising the check to allow token to be either an ERC20 address or NATIVE_GAS_TOKEN:

- if (token == address(0)) revert TokenZapV1__TokenZeroAddress();
+ if (token == address(0) && msg.value == 0) revert TokenZapV1__TokenZeroAddress();

Alternatively, ensure that NATIVE_GAS_TOKEN is not equal to address(0) to differentiate it from an invalid token address.

Likely invalid or redundant comment.


87-91: Ensure _forwardToken handles zero balance scenarios safely

The _forwardToken function assumes that there is a positive balance of finalToken. If the balance is zero, it reverts with TokenZapV1__FinalTokenBalanceZero(). Consider whether reverting is the desired behavior when there is no balance to forward, or if it should silently succeed.

Run the following script to check for any calls to _forwardToken where the balance might be zero:

Verify that in all code paths leading to _forwardToken, the balance of finalToken is expected to be greater than zero, and that reverting on zero balance aligns with the intended contract logic.

packages/contracts-rfq/contracts/router/SynapseIntentPreviewer.sol (1)

66-72: Handle the default case explicitly in intent creation

In the previewIntent function, after handling Action.Swap, Action.AddLiquidity, and Action.RemoveLiquidity, the else block calls _createHandleHativeSteps. Ensure that this function correctly handles any other possible actions or defaults to a safe state.

Review the logic in _createHandleHativeSteps to confirm it appropriately handles unexpected actions or tokens.

packages/contracts-rfq/test/zaps/TokenZapV1.t.sol (2)

57-59: Ensure test helpers reflect new parameters

The test helper functions getZapDataDeposit and getZapDataDepositNoAmount have been updated to include finalToken and forwardTo parameters. Ensure that all calls to these functions in the test cases supply appropriate values to thoroughly test the new functionality.

Also applies to: 62-63


264-309: Ensure tests handle extra funds correctly

In the tests test_zap_unwrapForwardNativeEOA_placeholderZero_extraFunds and similar, extra tokens are transferred to tokenZap before the zap operation. Ensure that these tests assert not only the successful completion but also verify that the extra funds are handled as expected, preventing any unintended side effects.

Review the tests to confirm that:

  • Extra funds do not cause unexpected behavior.
  • The final balances of tokenZap, the recipient, and any involved tokens are as intended.
packages/contracts-rfq/contracts/interfaces/ISynapseIntentPreviewer.sol (2)

11-12: LGTM! Well-documented parameter addition.

The documentation for the new forwardTo parameter is clear and comprehensive, including the important note about using address(0) when forwarding is not required.


21-21: Verify integration with existing implementations.

The parameter placement in the function signature is logical, but ensure all implementations of this interface are updated accordingly.

✅ Verification successful

Implementation is aligned with the interface

The implementation in SynapseIntentPreviewer.sol matches exactly with the interface definition in ISynapseIntentPreviewer.sol, including the forwardTo parameter placement. No integration issues found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for all implementations of previewIntent to ensure they're updated
ast-grep --pattern 'function previewIntent(address $_, address $_, address $_, address $_, uint256 $_)'

Length of output: 105


Script:

#!/bin/bash
# Search for interface definition
echo "Interface definition:"
rg -l "ISynapseIntentPreviewer" 

# Search for any implementations of previewIntent function
echo -e "\nImplementations:"
rg "function previewIntent" -A 5

Length of output: 1462

packages/contracts-rfq/test/harnesses/ZapDataV1Harness.sol (2)

16-17: LGTM! Consistent parameter addition.

The new parameters finalToken_ and forwardTo_ are correctly added to the encodeV1 function, maintaining consistency with the main library implementation.

Also applies to: 25-25


32-38: LGTM! Well-structured getter functions.

The new getter functions finalToken and forwardTo follow the established pattern and correctly delegate to the underlying library.

packages/contracts-rfq/deployments/optimism/SynapseIntentPreviewer.json (3)

31-35: LGTM! ABI updated correctly.

The ABI has been properly updated to include the new forwardTo parameter with correct type and positioning.


88-92: LGTM! Appropriate error handling.

The new error type SIP__NoOpForwardNotSupported has been added to handle invalid forwarding scenarios.


2-2: Verify deployment transaction.

The contract has been redeployed with a new address. Ensure the deployment transaction was successful and the contract is verified on the Optimism block explorer.

Also applies to: 5-6

✅ Verification successful

Let me verify the contract deployment by checking the contract code at the specified address.


Contract deployment verified successfully

The deployment transaction (0x928a7db8741fb992934302f73e076f7630075151384529b538cb133e797c4bac) was successful with status "0x1", and the contract at address 0x9519E8D136d0a89d7e10D1a66C97249E0135544B contains the expected bytecode, confirming a successful deployment.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Get deployment block information
curl -s "https://api-optimistic.etherscan.io/api?module=proxy&action=eth_getTransactionReceipt&txhash=0x928a7db8741fb992934302f73e076f7630075151384529b538cb133e797c4bac"

Length of output: 1355


Script:

#!/bin/bash
# Get contract code at the specified address
curl -s "https://api-optimistic.etherscan.io/api?module=proxy&action=eth_getCode&address=0x9519E8D136d0a89d7e10D1a66C97249E0135544B&tag=latest"

Length of output: 15438

packages/contracts-rfq/test/libs/ZapDataV1.t.sol (3)

21-30: LGTM: Proper encoding of new parameters

The encodeZapData function correctly encodes the new finalToken and forwardTo parameters in the packed data structure.


53-64: LGTM: Comprehensive roundtrip testing

The test cases thoroughly verify the encoding and decoding of both finalToken and forwardTo parameters, including edge cases with zero addresses.

Also applies to: 81-90


114-126: LGTM: Proper error handling verification

The test cases properly verify error conditions for invalid encodings and parameter combinations.

packages/contracts-rfq/test/router/SynapseIntentRouter.BalanceChecks.t.sol (1)

208-257: LGTM: Comprehensive test coverage for unspent funds

The new test cases thoroughly verify the handling of unspent funds in swap and unwrap operations, including scenarios with forwarding. The test coverage includes:

  • Unspent ERC20 tokens
  • Unspent WETH
  • Extra funds scenarios
  • Balance checks with forwarding
packages/contracts-rfq/test/router/SynapseIntentPreviewer.t.sol (2)

43-43: LGTM: Clean test setup and helper functions

The test setup and helper functions are well-organized with proper handling of the new forwardTo parameter. The separation between noForward and withForward test cases improves test clarity.

Also applies to: 107-141


Line range hint 364-399: LGTM: Proper validation of no-op intents with forwarding

The test cases correctly verify that forwarding is not supported for no-op intents, with proper error handling for both token and native currency scenarios.

Comment on lines +87 to +89
amountPosition: 4 + 32 * 2,
finalToken: address(0),
forwardTo: address(0)
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 test coverage for non-zero forwardTo and finalToken addresses

The test cases only cover scenarios where both finalToken and forwardTo are set to address(0). Given that the PR's main objective is to support forwarding assets to a specified address, we should add test coverage for:

  1. Non-zero forwardTo addresses to verify the forwarding functionality
  2. Different combinations of finalToken and forwardTo values
  3. Edge cases like forwarding to the same address as the user

Here's a suggested test structure to add:

function test_ForwardToSpecifiedAddress() public {
    address forwardTo = makeAddr("ForwardTo");
    bytes memory zapData = dstZap.encodeZapData({
        target: address(dstVault),
        payload: getDepositPayload(address(dstToken)),
        amountPosition: 4 + 32 * 2,
        finalToken: address(dstToken),
        forwardTo: forwardTo
    });
    // Add assertions to verify tokens are forwarded correctly
}

function test_ForwardToZeroAddress() public {
    // Test that tokens are sent to user when forwardTo is address(0)
}

function test_ForwardToWithDifferentFinalToken() public {
    // Test forwarding with finalToken != depositToken
}

Also applies to: 98-100, 106-108, 114-116, 121-123

Comment on lines +51 to +58
/// @param finalToken_ The token produced as a result of the Zap action (ERC20 or native gas token).
/// A zero address value signals that the Zap action doesn't result in any asset per se,
/// like bridging or depositing into a vault without an LP token.
/// Note: this parameter must be set to a non-zero value if the `forwardTo_` parameter is
/// set to a non-zero value.
/// @param forwardTo_ The address to which `finalToken` should be forwarded. This parameter is required only
/// if the Zap action does not automatically transfer the token to the intended recipient.
/// Otherwise, it must be set to address(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

Ensure finalToken_ and forwardTo_ parameters are validated appropriately

The addition of finalToken_ and forwardTo_ parameters enhances the flexibility of the encodeV1 function. However, there should be explicit validations to ensure that if forwardTo_ is not the zero address, then finalToken_ must also be a non-zero address, as mentioned in the documentation. Consider adding a require statement to enforce this constraint.

Apply this diff to include the validation:

function encodeV1(
    uint16 amountPosition_,
    address finalToken_,
    address forwardTo_,
    address target_,
    bytes memory payload_
)
    internal
    pure
    returns (bytes memory encodedZapData)
{
    if (target_ == address(0)) revert ZapDataV1__TargetZeroAddress();
+   if (forwardTo_ != address(0) && finalToken_ == address(0)) revert ZapDataV1__FinalTokenZeroAddress();
    // Amount is encoded in [amountPosition_ .. amountPosition_ + 32), which should be within the payload.
    if (amountPosition_ != AMOUNT_NOT_PRESENT && (uint256(amountPosition_) + 32 > payload_.length)) {
        revert ZapDataV1__InvalidEncoding();
    }
    return abi.encodePacked(VERSION, amountPosition_, finalToken_, forwardTo_, target_, payload_);
}

This ensures that the function reverts if forwardTo_ is set without a corresponding finalToken_, preventing potential runtime errors.

Also applies to: 66-67

Comment on lines +111 to +118
/// @param finalToken The token produced as a result of the Zap action (ERC20 or native gas token).
/// A zero address value signals that the Zap action doesn't result in any asset per se,
/// like bridging or depositing into a vault without an LP token.
/// Note: this parameter must be set to a non-zero value if the `forwardTo` parameter is
/// set to a non-zero value.
/// @param forwardTo The address to which `finalToken` should be forwarded. This parameter is required only
/// if the Zap action does not automatically transfer the token to the intended recipient.
/// Otherwise, it must be set to address(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 validation for finalToken and forwardTo in encodeZapData

While the documentation mentions that finalToken must be non-zero if forwardTo is set, the function does not enforce this constraint. Consider adding a require statement to ensure data integrity.

Apply this diff to include the validation:

function encodeZapData(
    address target,
    bytes memory payload,
    uint256 amountPosition,
    address finalToken,
    address forwardTo
)
    external
    pure
    returns (bytes memory)
{
    if (payload.length > ZapDataV1.AMOUNT_NOT_PRESENT) {
        revert TokenZapV1__PayloadLengthAboveMax();
    }
+   // Ensure finalToken is non-zero if forwardTo is set
+   if (forwardTo != address(0) && finalToken == address(0)) {
+       revert TokenZapV1__FinalTokenZeroAddress();
+   }
    // External integrations do not need to understand the specific `AMOUNT_NOT_PRESENT` semantics.
    // Therefore, they can specify any value greater than or equal to `payload.length` to indicate
    // that the amount is not present in the payload.
    if (amountPosition >= payload.length) {
        amountPosition = ZapDataV1.AMOUNT_NOT_PRESENT;
    }
    // At this point, we have checked that both `amountPosition` and `payload.length` fit in uint16.
    return ZapDataV1.encodeV1({
        amountPosition_: uint16(amountPosition),
        finalToken_: finalToken,
        forwardTo_: forwardTo,
        target_: target,
        payload_: payload
    });
}

This ensures that incorrect combinations of finalToken and forwardTo are prevented at the time of encoding.

Also applies to: 133-136

Comment on lines +29 to +32
error TokenZapV1__FinalTokenBalanceZero();
error TokenZapV1__PayloadLengthAboveMax();
error TokenZapV1__TargetZeroAddress();
error TokenZapV1__TokenZeroAddress();
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 missing error definition for TokenZapV1__FinalTokenZeroAddress

The TokenZapV1__FinalTokenZeroAddress() error is referenced in the contract but not defined. Ensure that this error is properly declared to maintain consistency and clarity in error handling.

Apply this diff to declare the missing error:

error TokenZapV1__FinalTokenBalanceZero();
error TokenZapV1__PayloadLengthAboveMax();
error TokenZapV1__TargetZeroAddress();
+ error TokenZapV1__FinalTokenZeroAddress();
error TokenZapV1__TokenZeroAddress();

This addition will prevent potential compilation errors and improve error reporting.

📝 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
error TokenZapV1__FinalTokenBalanceZero();
error TokenZapV1__PayloadLengthAboveMax();
error TokenZapV1__TargetZeroAddress();
error TokenZapV1__TokenZeroAddress();
error TokenZapV1__FinalTokenBalanceZero();
error TokenZapV1__PayloadLengthAboveMax();
error TokenZapV1__TargetZeroAddress();
error TokenZapV1__FinalTokenZeroAddress();
error TokenZapV1__TokenZeroAddress();

@ChiTimesChi ChiTimesChi merged commit e28e56e into feat/syn-intent-router Dec 10, 2024
49 of 52 checks passed
@ChiTimesChi ChiTimesChi deleted the fix/FbV2-zap-data-funds-recipient branch December 10, 2024 22:27
ChiTimesChi added a commit that referenced this pull request Dec 10, 2024
* feat: scaffold IntentRouter

* feat: initial implementation

* test: single step

* feat: scaffold checked/unchecked `completeIntent`

* feat: implement balance checks

* test: add cases where TokenZap has non-zero initial amount

* test: double step cases (erc20 and/or native combos)

* feat: SIR, TokenZap deployment script

* deploy: test deploys for SIR

* test: update to #3434 changes

* feat: scaffold SIP

* test: coverage for SIP

* feat: Synapse Intent Previewer

* feat: update deploy script, deploy SIP

* fix(contracts-rfq): add `forwardTo` to ZapData for Zap Actions that don't forward assets to the user (#3451)

* feat: scaffold finalToken, forwardTo in ZapDataV1

* feat: add finalToken, forwardTo

* feat: scaffold TokenZap.encodeZapData

* test: update existing tests

* test: forwardTo scenarios

* feat: token zeor address checks

* feat:scaffold token forwarding

* test: more revert cases

* feat: final token forwarding

* test: forwardTo behaviour in SIP

* feat: support optional `forwardTo` in SIP

* deploy: redeploy SIP, TokenZap
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant