From 496c468b2b5fba5bd66037d929060ebee8dadf89 Mon Sep 17 00:00:00 2001 From: Jun Kim <64379343+junkim012@users.noreply.github.com> Date: Tue, 1 Oct 2024 21:38:36 -0400 Subject: [PATCH 1/2] feat: LayerZeroOFT decoder verifies the refundReceiver. Deletes StargateV2 Decoder --- .../LayerZeroOFTDecoderAndSanitizer.sol | 2 +- .../StargateV2DecoderAndSanitizer.sol | 46 ------------------- 2 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 src/base/DecodersAndSanitizers/StargateV2DecoderAndSanitizer.sol diff --git a/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol index 3c6a242..5d3e77f 100644 --- a/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol @@ -33,7 +33,7 @@ contract LayerZeroOFTDecoderAndSanitizer is BaseDecoderAndSanitizer { view returns (bytes memory) { - if (bytes32ToAddress(_sendParam.to) != boringVault) { + if (bytes32ToAddress(_sendParam.to) != boringVault || refundReceiver != boringVault) { revert LayerZeroOFTDecoderAndSanitizer_NotVault(); } if (_sendParam.composeMsg.length > 0) { diff --git a/src/base/DecodersAndSanitizers/StargateV2DecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/StargateV2DecoderAndSanitizer.sol deleted file mode 100644 index 8ec7cfd..0000000 --- a/src/base/DecodersAndSanitizers/StargateV2DecoderAndSanitizer.sol +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.21; - -import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol"; -import { MessagingFee, OFTReceipt, SendParam } from "@layerzerolabs/lz-evm-oapp-v2/contracts/oft/interfaces/IOFT.sol"; - -contract StargateV2DecoderAndSanitizer is BaseDecoderAndSanitizer { - constructor(address _boringVault) BaseDecoderAndSanitizer(_boringVault) { } - - error StargateV2DecoderAndSanitizer_ComposedMsgNotSupported(); - error StargateV2DecoderAndSanitizer_MustBeVault(); - /** - * @dev _sendParam: - * uint32 dstEid; // Destination endpoint ID. [VERIFY] - * bytes32 to; // Recipient address. [VERIFY] - * uint256 amountLD; // Amount to send in local decimals. - * uint256 minAmountLD; // Minimum amount to send in local decimals. - * bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message. - * bytes composeMsg; // The composed message for the send() operation. - * bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations. [NONE] - * @dev _fee: - * uint256 nativeFee; - * uint256 lzTokenFee; - */ - - function sendToken( - SendParam memory _sendParam, - MessagingFee memory _messagingFee, - address _refundAddress - ) - external - returns (bytes memory) - { - if (bytes32ToAddress(_sendParam.to) != boringVault || _refundAddress != boringVault) { - revert StargateV2DecoderAndSanitizer_MustBeVault(); - } - if (_sendParam.composeMsg.length > 0) { - revert StargateV2DecoderAndSanitizer_ComposedMsgNotSupported(); - } - return abi.encodePacked(_sendParam.dstEid); - } - - function bytes32ToAddress(bytes32 b) internal pure returns (address) { - return address(uint160(uint256(b))); - } -} From 92347959376e255399b69f6b2eaa9489124b9202 Mon Sep 17 00:00:00 2001 From: Jun Kim <64379343+junkim012@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:29:52 -0400 Subject: [PATCH 2/2] feat: seiyanETH decoder --- .../BaseDecoderAndSanitizer.sol | 2 + .../LayerZeroOFTDecoderAndSanitizer.sol | 10 ++--- .../Protocols/CurveDecoderAndSanitizer.sol | 5 ++- .../Protocols/ERC4626DecoderAndSanitizer.sol | 20 ++++++++-- .../NativeWrapperDecoderAndSanitizer.sol | 2 +- .../Protocols/PirexEthDecoderAndSanitizer.sol | 3 ++ .../SeiyanEthRebalanceDecoderAndSanitizer.sol | 39 +++++++++++++++++-- 7 files changed, 66 insertions(+), 15 deletions(-) diff --git a/src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol index 35b7ee3..a1a91bc 100644 --- a/src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol @@ -5,6 +5,8 @@ pragma solidity 0.8.21; import { DecoderCustomTypes } from "src/interfaces/DecoderCustomTypes.sol"; contract BaseDecoderAndSanitizer { + error NotVault(); + //============================== IMMUTABLES =============================== /** diff --git a/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol index 5d3e77f..8ae0c2e 100644 --- a/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol @@ -5,11 +5,8 @@ import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDeco import { SendParam } from "@layerzerolabs/oft-evm/contracts/interfaces/IOFT.sol"; import { MessagingFee } from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol"; -contract LayerZeroOFTDecoderAndSanitizer is BaseDecoderAndSanitizer { +abstract contract LayerZeroOFTDecoderAndSanitizer is BaseDecoderAndSanitizer { error LayerZeroOFTDecoderAndSanitizer_ComposedMsgNotSupported(); - error LayerZeroOFTDecoderAndSanitizer_NotVault(); - - constructor(address _boringVault) BaseDecoderAndSanitizer(_boringVault) { } /** * @dev _sendParam: @@ -19,7 +16,8 @@ contract LayerZeroOFTDecoderAndSanitizer is BaseDecoderAndSanitizer { * uint256 minAmountLD; // Minimum amount to send in local decimals. * bytes extraOptions; // Additional options supplied by the caller to be used in the LayerZero message. * bytes composeMsg; // The composed message for the send() operation. [NONE] - * bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations. [NONE] + * bytes oftCmd; // The OFT command to be executed, unused in default OFT implementations. 0 for Taxi (faster, + * expensive) 1 for Bus (slower, cheaper) * @dev _fee: * uint256 nativeFee; * uint256 lzTokenFee; @@ -34,7 +32,7 @@ contract LayerZeroOFTDecoderAndSanitizer is BaseDecoderAndSanitizer { returns (bytes memory) { if (bytes32ToAddress(_sendParam.to) != boringVault || refundReceiver != boringVault) { - revert LayerZeroOFTDecoderAndSanitizer_NotVault(); + revert NotVault(); } if (_sendParam.composeMsg.length > 0) { revert LayerZeroOFTDecoderAndSanitizer_ComposedMsgNotSupported(); diff --git a/src/base/DecodersAndSanitizers/Protocols/CurveDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/CurveDecoderAndSanitizer.sol index 50cf818..9aac096 100644 --- a/src/base/DecodersAndSanitizers/Protocols/CurveDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/CurveDecoderAndSanitizer.sol @@ -29,7 +29,10 @@ abstract contract CurveDecoderAndSanitizer is BaseDecoderAndSanitizer { return addressesFound; } - function deposit(uint256, address receiver) external pure virtual returns (bytes memory addressesFound) { + function deposit(uint256, address receiver) external view virtual returns (bytes memory addressesFound) { + if (receiver != boringVault) { + revert NotVault(); + } addressesFound = abi.encodePacked(receiver); } diff --git a/src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol index 0bb8c93..b75011d 100644 --- a/src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol @@ -6,11 +6,17 @@ import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDeco abstract contract ERC4626DecoderAndSanitizer is BaseDecoderAndSanitizer { //============================== ERC4626 =============================== - function deposit(uint256, address receiver) external pure virtual returns (bytes memory addressesFound) { + function deposit(uint256, address receiver) external view virtual returns (bytes memory addressesFound) { + if (receiver != boringVault) { + revert NotVault(); + } addressesFound = abi.encodePacked(receiver); } - function mint(uint256, address receiver) external pure virtual returns (bytes memory addressesFound) { + function mint(uint256, address receiver) external view virtual returns (bytes memory addressesFound) { + if (receiver != boringVault) { + revert NotVault(); + } addressesFound = abi.encodePacked(receiver); } @@ -20,10 +26,13 @@ abstract contract ERC4626DecoderAndSanitizer is BaseDecoderAndSanitizer { address owner ) external - pure + view virtual returns (bytes memory addressesFound) { + if (receiver != boringVault) { + revert NotVault(); + } addressesFound = abi.encodePacked(receiver, owner); } @@ -33,10 +42,13 @@ abstract contract ERC4626DecoderAndSanitizer is BaseDecoderAndSanitizer { address owner ) external - pure + view virtual returns (bytes memory addressesFound) { + if (receiver != boringVault) { + revert NotVault(); + } addressesFound = abi.encodePacked(receiver, owner); } } diff --git a/src/base/DecodersAndSanitizers/Protocols/NativeWrapperDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/NativeWrapperDecoderAndSanitizer.sol index 3314fae..79f6110 100644 --- a/src/base/DecodersAndSanitizers/Protocols/NativeWrapperDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/NativeWrapperDecoderAndSanitizer.sol @@ -4,7 +4,7 @@ pragma solidity 0.8.21; import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol"; abstract contract NativeWrapperDecoderAndSanitizer is BaseDecoderAndSanitizer { - //============================== ETHERFI =============================== + //============================== WETH/ETHERFI =============================== function deposit() external pure virtual returns (bytes memory addressesFound) { // Nothing to sanitize or return diff --git a/src/base/DecodersAndSanitizers/Protocols/PirexEthDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/Protocols/PirexEthDecoderAndSanitizer.sol index c956777..cd0831b 100644 --- a/src/base/DecodersAndSanitizers/Protocols/PirexEthDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/Protocols/PirexEthDecoderAndSanitizer.sol @@ -5,6 +5,9 @@ import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDeco abstract contract PirexEthDecoderAndSanitizer is BaseDecoderAndSanitizer { function deposit(address receiver, bool) external returns (bytes memory) { + if (receiver != boringVault) { + revert NotVault(); + } return abi.encodePacked(receiver); } } diff --git a/src/base/DecodersAndSanitizers/SeiyanEthRebalanceDecoderAndSanitizer.sol b/src/base/DecodersAndSanitizers/SeiyanEthRebalanceDecoderAndSanitizer.sol index 3be20de..51c9dfe 100644 --- a/src/base/DecodersAndSanitizers/SeiyanEthRebalanceDecoderAndSanitizer.sol +++ b/src/base/DecodersAndSanitizers/SeiyanEthRebalanceDecoderAndSanitizer.sol @@ -2,16 +2,49 @@ pragma solidity 0.8.21; import { BaseDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/BaseDecoderAndSanitizer.sol"; -import { ERC4626DecoderAndSanitizer } from "src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol"; import { PirexEthDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/Protocols/PirexEthDecoderAndSanitizer.sol"; +import { LayerZeroOFTDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/LayerZeroOFTDecoderAndSanitizer.sol"; import { NativeWrapperDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/Protocols/NativeWrapperDecoderAndSanitizer.sol"; +import { ERC4626DecoderAndSanitizer } from "src/base/DecodersAndSanitizers/Protocols/ERC4626DecoderAndSanitizer.sol"; +import { CurveDecoderAndSanitizer } from "src/base/DecodersAndSanitizers/Protocols/CurveDecoderAndSanitizer.sol"; contract SeiyanEthRebalanceDecoderAndSanitizer is BaseDecoderAndSanitizer, - ERC4626DecoderAndSanitizer, PirexEthDecoderAndSanitizer, - NativeWrapperDecoderAndSanitizer + LayerZeroOFTDecoderAndSanitizer, + NativeWrapperDecoderAndSanitizer, + ERC4626DecoderAndSanitizer, + CurveDecoderAndSanitizer { constructor(address _boringVault) BaseDecoderAndSanitizer(_boringVault) { } + + function deposit( + uint256, + address receiver + ) + external + view + override(CurveDecoderAndSanitizer, ERC4626DecoderAndSanitizer) + returns (bytes memory addressesFound) + { + if (receiver != boringVault) { + revert NotVault(); + } + addressesFound = abi.encodePacked(receiver); + } + + /** + * @notice Curve and WETH both specifies a `withdraw(uint256)`, but all + * cases are handled the same way. + */ + function withdraw(uint256) + external + pure + override(CurveDecoderAndSanitizer, NativeWrapperDecoderAndSanitizer) + returns (bytes memory addressesFound) + { + // Nothing to sanitize or return + return addressesFound; + } }