From 858998a3a62fa0addb3781ce0eb4b13c4ba53087 Mon Sep 17 00:00:00 2001 From: Karan Singh <132837775+CARDIN00@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:06:57 +0530 Subject: [PATCH 1/3] Update AssimilatorV3.sol --- src/assimilators/AssimilatorV3.sol | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/assimilators/AssimilatorV3.sol b/src/assimilators/AssimilatorV3.sol index 2deadd9..bee0d0c 100644 --- a/src/assimilators/AssimilatorV3.sol +++ b/src/assimilators/AssimilatorV3.sol @@ -208,10 +208,12 @@ contract AssimilatorV3 is IAssimilator { amount_ = Math.ceilDiv(_amount.mulu(10 ** (tokenDecimals + oracleDecimals + 18)), _rate * 1e18); require(amount_ > 0, "zero amount!"); if (_toETH) { + require(_dst != address(0), "Assimilator/Invalid Destination"); IWETH(wETH).withdraw(amount_); (bool success,) = payable(_dst).call{value: amount_}(""); require(success, "Assimilator/Transfer ETH Failed"); } else { + require(_dst != address(0), "Assimilator/Invalid Destination"); token.safeTransfer(_dst, amount_); } } From a01295128e802a3cfefc3da8fd3c6cb690fa23fb Mon Sep 17 00:00:00 2001 From: Karan Singh <132837775+CARDIN00@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:08:36 +0530 Subject: [PATCH 2/3] Update Zap.sol --- src/Zap.sol | 118 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/src/Zap.sol b/src/Zap.sol index 5afd450..6e838dd 100644 --- a/src/Zap.sol +++ b/src/Zap.sol @@ -16,6 +16,7 @@ pragma solidity ^0.8.13; pragma experimental ABIEncoderV2; +import "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import "@openzeppelin/contracts/utils/math/SafeMath.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; @@ -28,7 +29,7 @@ import "./interfaces/IOracle.sol"; import "./interfaces/ICurveFactory.sol"; import "./assimilators/AssimilatorV3.sol"; -contract Zap { +contract Zap is ReentrancyGuard{ using SafeMath for uint256; using SafeERC20 for IERC20Metadata; @@ -61,52 +62,77 @@ contract Zap { } function unzap( - address _curve, - uint256 _lpAmount, - uint256 _deadline, - uint256 _minTokenAmount, - address _token, - bool _toETH - ) public isDFXCurve(_curve) returns (uint256) { - address wETH = ICurve(_curve).getWeth(); - IERC20Metadata base = IERC20Metadata(Curve(payable(_curve)).numeraires(0)); - IERC20Metadata quote = IERC20Metadata(Curve(payable(_curve)).numeraires(1)); - require(_token == address(base) || _token == address(quote), "zap/token-not-supported"); - IERC20Metadata(_curve).safeTransferFrom(msg.sender, address(this), _lpAmount); - Curve(payable(_curve)).withdraw(_lpAmount, _deadline); - // from base - if (_token == address(base)) { - uint256 baseAmount = base.balanceOf(address(this)); - base.safeApprove(_curve, 0); - base.safeApprove(_curve, type(uint256).max); - Curve(payable(_curve)).originSwap(address(base), address(quote), baseAmount, 0, _deadline); - uint256 quoteAmount = quote.balanceOf(address(this)); - require(quoteAmount >= _minTokenAmount, "!Unzap/not-enough-token-amount"); - if (address(quote) == wETH && _toETH) { - IWETH(wETH).withdraw(quoteAmount); - (bool success,) = payable(msg.sender).call{value: quoteAmount}(""); - require(success, "zap/unzap-to-eth-failed"); - } else { - quote.safeTransfer(msg.sender, quoteAmount); - } - return quoteAmount; + address _curve, + uint256 _lpAmount, + uint256 _deadline, + uint256 _minTokenAmount, + address _token, + bool _toETH +) public nonReentrant isDFXCurve(_curve) returns (uint256) { + address wETH = ICurve(_curve).getWeth(); + IERC20Metadata base = IERC20Metadata(Curve(payable(_curve)).numeraires(0)); + IERC20Metadata quote = IERC20Metadata(Curve(payable(_curve)).numeraires(1)); + require(_token == address(base) || _token == address(quote), "zap/token-not-supported"); + + // Transfer LP tokens to this contract + IERC20Metadata(_curve).safeTransferFrom(msg.sender, address(this), _lpAmount); + + // Withdraw underlying tokens from the curve + Curve(payable(_curve)).withdraw(_lpAmount, _deadline); + + if (_token == address(base)) { + uint256 baseAmount = base.balanceOf(address(this)); + + // Approve the curve to handle base tokens + base.safeApprove(_curve, 0); + base.safeApprove(_curve, type(uint256).max); + + // Perform the origin swap + Curve(payable(_curve)).originSwap(address(base), address(quote), baseAmount, 0, _deadline); + + uint256 quoteAmount = quote.balanceOf(address(this)); + require(quoteAmount >= _minTokenAmount, "!Unzap/not-enough-token-amount"); + + if (address(quote) == wETH && _toETH) { + IWETH(wETH).withdraw(quoteAmount); + + // Safely transfer ETH to the user + require(msg.sender != address(0), "zap/invalid-recipient"); + (bool success, ) = payable(msg.sender).call{value: quoteAmount}(""); + require(success, "zap/unzap-to-eth-failed"); } else { - uint256 quoteAmount = quote.balanceOf(address(this)); - quote.safeApprove(_curve, 0); - quote.safeApprove(_curve, type(uint256).max); - Curve(payable(_curve)).originSwap(address(quote), address(base), quoteAmount, 0, _deadline); - uint256 baseAmount = base.balanceOf(address(this)); - require(baseAmount >= _minTokenAmount, "!Unzap/not-enough-token-amount"); - if (address(base) == wETH && _toETH) { - IWETH(wETH).withdraw(baseAmount); - (bool success,) = payable(msg.sender).call{value: baseAmount}(""); - require(success, "zap/unzap-to-eth-failed"); - } else { - base.safeTransfer(msg.sender, baseAmount); - } - return baseAmount; + quote.safeTransfer(msg.sender, quoteAmount); + } + + return quoteAmount; + } else { + uint256 quoteAmount = quote.balanceOf(address(this)); + + // Approve the curve to handle quote tokens + quote.safeApprove(_curve, 0); + quote.safeApprove(_curve, type(uint256).max); + + // Perform the origin swap + Curve(payable(_curve)).originSwap(address(quote), address(base), quoteAmount, 0, _deadline); + + uint256 baseAmount = base.balanceOf(address(this)); + require(baseAmount >= _minTokenAmount, "!Unzap/not-enough-token-amount"); + + if (address(base) == wETH && _toETH) { + IWETH(wETH).withdraw(baseAmount); + + // Safely transfer ETH to the user + require(msg.sender != address(0), "zap/invalid-recipient"); + (bool success, ) = payable(msg.sender).call{value: baseAmount}(""); + require(success, "zap/unzap-to-eth-failed"); + } else { + base.safeTransfer(msg.sender, baseAmount); } + + return baseAmount; } +} + /// @notice Zaps from a single token into the LP pool /// @param _curve The address of the curve @@ -116,7 +142,7 @@ contract Zap { /// @return uint256 - The amount of LP tokens received function zap(address _curve, uint256 _zapAmount, uint256 _deadline, uint256 _minLPAmount, address _token) public - isDFXCurve(_curve) + isDFXCurve(_curve) nonReentrant returns (uint256) { uint256 _zapAmount_ = _zapAmount; @@ -146,7 +172,7 @@ contract Zap { function zapETH(address _curve, uint256 _deadline, uint256 _minLPAmount) public payable - isDFXCurve(_curve) + isDFXCurve(_curve) nonReentrant returns (uint256) { require(msg.value > 0, "zap/zap-amount-is-zero"); From ffe5d537ce92383f1b88e897fa4da830b01e2752 Mon Sep 17 00:00:00 2001 From: Karan Singh <132837775+CARDIN00@users.noreply.github.com> Date: Sun, 12 Jan 2025 17:38:59 +0530 Subject: [PATCH 3/3] Update Zap.sol --- src/Zap.sol | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/Zap.sol b/src/Zap.sol index 6e838dd..d7ffb2a 100644 --- a/src/Zap.sol +++ b/src/Zap.sol @@ -68,26 +68,22 @@ contract Zap is ReentrancyGuard{ uint256 _minTokenAmount, address _token, bool _toETH -) public nonReentrant isDFXCurve(_curve) returns (uint256) { - address wETH = ICurve(_curve).getWeth(); - IERC20Metadata base = IERC20Metadata(Curve(payable(_curve)).numeraires(0)); - IERC20Metadata quote = IERC20Metadata(Curve(payable(_curve)).numeraires(1)); - require(_token == address(base) || _token == address(quote), "zap/token-not-supported"); - - // Transfer LP tokens to this contract - IERC20Metadata(_curve).safeTransferFrom(msg.sender, address(this), _lpAmount); + ) public isDFXCurve(_curve) nonReentrant returns (uint256) { + // Checks + address wETH = ICurve(_curve).getWeth(); + IERC20Metadata base = IERC20Metadata(Curve(payable(_curve)).numeraires(0)); + IERC20Metadata quote = IERC20Metadata(Curve(payable(_curve)).numeraires(1)); + require(_token == address(base) || _token == address(quote), "zap/token-not-supported"); - // Withdraw underlying tokens from the curve - Curve(payable(_curve)).withdraw(_lpAmount, _deadline); + // Effects + IERC20Metadata(_curve).safeTransferFrom(msg.sender, address(this), _lpAmount); + Curve(payable(_curve)).withdraw(_lpAmount, _deadline); + // Interaction if (_token == address(base)) { uint256 baseAmount = base.balanceOf(address(this)); - - // Approve the curve to handle base tokens base.safeApprove(_curve, 0); base.safeApprove(_curve, type(uint256).max); - - // Perform the origin swap Curve(payable(_curve)).originSwap(address(base), address(quote), baseAmount, 0, _deadline); uint256 quoteAmount = quote.balanceOf(address(this)); @@ -95,9 +91,6 @@ contract Zap is ReentrancyGuard{ if (address(quote) == wETH && _toETH) { IWETH(wETH).withdraw(quoteAmount); - - // Safely transfer ETH to the user - require(msg.sender != address(0), "zap/invalid-recipient"); (bool success, ) = payable(msg.sender).call{value: quoteAmount}(""); require(success, "zap/unzap-to-eth-failed"); } else { @@ -107,12 +100,8 @@ contract Zap is ReentrancyGuard{ return quoteAmount; } else { uint256 quoteAmount = quote.balanceOf(address(this)); - - // Approve the curve to handle quote tokens quote.safeApprove(_curve, 0); quote.safeApprove(_curve, type(uint256).max); - - // Perform the origin swap Curve(payable(_curve)).originSwap(address(quote), address(base), quoteAmount, 0, _deadline); uint256 baseAmount = base.balanceOf(address(this)); @@ -120,9 +109,6 @@ contract Zap is ReentrancyGuard{ if (address(base) == wETH && _toETH) { IWETH(wETH).withdraw(baseAmount); - - // Safely transfer ETH to the user - require(msg.sender != address(0), "zap/invalid-recipient"); (bool success, ) = payable(msg.sender).call{value: baseAmount}(""); require(success, "zap/unzap-to-eth-failed"); } else {