-
Notifications
You must be signed in to change notification settings - Fork 2
[VPD-479]: Swap Router #16
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
Merged
Merged
Changes from 6 commits
Commits
Show all changes
31 commits
Select commit
Hold shift + click to select a range
642375a
feat: add generic swapper contract
kkirka e2312fa
feat: add backend signature verification to the swapper
kkirka 2981707
feat: add SwapRouter contract
Debugger022 fbc3044
test: add unit test for SwapRouter
Debugger022 82082ba
feat: add deployment script
Debugger022 3417be5
feat: add SwapRouter fork test
Debugger022 f487c79
fix: fix comments
Debugger022 f2459c8
fix: major fixes
Debugger022 e21d01b
fix: fix unit and fork test
Debugger022 85f2930
Merge branch 'feat/swapper' into feat/swapRouter
Debugger022 e233965
Merge branch 'develop' into feat/swapRouter-develop-merge
Exef 215a735
test: update unit test for swapRouter
Debugger022 059cd0a
Merge pull request #31 from VenusProtocol/feat/swapRouter-develop-merge
Debugger022 a5bf806
fix: tests
Debugger022 e6add02
test: update swapRouter fork tests
Debugger022 9f06257
feat: add swapRouter bscmainnet deployment
Debugger022 de928dd
feat: updating deployment files
Debugger022 4487e12
feat: add swapNativeAndRepayFull function
Debugger022 594b4ff
feat: L-01
Debugger022 aeb20e1
feat: L-05
Debugger022 f042ecd
refactor: consolidate slippage check in repayFull
Debugger022 0f8abbe
feat: I-01
Debugger022 50a4993
feat: add SwapRouter audits
Debugger022 f949020
Merge pull request #45 from VenusProtocol/fix/VPD-458
Debugger022 6b3774d
Merge pull request #43 from VenusProtocol/fix/vpd-440
Debugger022 d1d28c0
feat: add deployments
Debugger022 41bb9e0
feat: updating deployment files
Debugger022 ec44ad8
Merge branch 'develop' into feat/swapRouter
Debugger022 1db1685
feat: add barrel Interfaces.sol to re-export split interface files
Debugger022 8de1ccf
feat: updating deployment files
Debugger022 65165ef
chore: clean up .gitignore duplicates and organize sections
Debugger022 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
| pragma solidity 0.8.25; | ||
|
|
||
| import { SafeERC20Upgradeable, IERC20Upgradeable } from "@openzeppelin/contracts-upgradeable/token/ERC20/utils/SafeERC20Upgradeable.sol"; | ||
| import { AddressUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol"; | ||
| import { EIP712 } from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; | ||
| import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; | ||
|
|
||
| import { IWBNB } from "../Interfaces.sol"; | ||
|
|
||
| contract SwapHelper is EIP712 { | ||
| using SafeERC20Upgradeable for IERC20Upgradeable; | ||
| using AddressUpgradeable for address; | ||
|
|
||
| uint256 internal constant REENTRANCY_LOCK_UNLOCKED = 1; | ||
| uint256 internal constant REENTRANCY_LOCK_LOCKED = 2; | ||
| bytes32 internal constant MULTICALL_TYPEHASH = keccak256("Multicall(bytes[] calls,uint256 deadline)"); | ||
|
|
||
| /// @notice Wrapped native asset | ||
| IWBNB public immutable WRAPPED_NATIVE; | ||
|
|
||
| /// @notice Venus backend signer | ||
| address public immutable BACKEND_SIGNER; | ||
|
|
||
| /// @dev Reentrancy lock to prevent reentrancy attacks | ||
| uint256 private reentrancyLock; | ||
|
|
||
| /// @notice Error thrown when reentrancy is detected | ||
| error Reentrancy(); | ||
|
|
||
| /// @notice Error thrown when deadline is reached | ||
| error DeadlineReached(); | ||
|
|
||
| /// @notice Error thrown when caller is not the authorized backend signer | ||
| error Unauthorized(); | ||
|
|
||
| /// @notice In the locked state, allow contract to call itself, but block all external calls | ||
| modifier externalLock() { | ||
| bool isExternal = msg.sender != address(this); | ||
|
|
||
| if (isExternal) { | ||
| if (reentrancyLock == REENTRANCY_LOCK_LOCKED) revert Reentrancy(); | ||
| reentrancyLock = REENTRANCY_LOCK_LOCKED; | ||
| } | ||
|
|
||
| _; | ||
|
|
||
| if (isExternal) reentrancyLock = REENTRANCY_LOCK_UNLOCKED; | ||
| } | ||
|
|
||
| /// @notice Constructor | ||
| /// @param wrappedNative_ Address of the wrapped native asset | ||
| /// @param backendSigner_ Address of the backend signer | ||
| constructor(address wrappedNative_, address backendSigner_) EIP712("VenusSwap", "1") { | ||
| WRAPPED_NATIVE = IWBNB(wrappedNative_); | ||
| BACKEND_SIGNER = backendSigner_; | ||
| } | ||
|
|
||
| /// @notice Multicall function to execute multiple calls in a single transaction | ||
| /// @param calls Array of calldata to execute | ||
| /// @param deadline Deadline for the transaction | ||
| /// @param signature Backend signature | ||
| function multicall( | ||
| bytes[] calldata calls, | ||
| uint256 deadline, | ||
| bytes calldata signature | ||
| ) external payable externalLock { | ||
| if (block.timestamp > deadline) { | ||
| revert DeadlineReached(); | ||
| } | ||
|
|
||
| if (signature.length != 0) { | ||
| bytes32 digest = _hashMulticall(calls, deadline); | ||
| address signer = ECDSA.recover(digest, signature); | ||
| if (signer != BACKEND_SIGNER) { | ||
| revert Unauthorized(); | ||
| } | ||
| } | ||
|
|
||
| for (uint256 i = 0; i < calls.length; i++) { | ||
| address(this).functionCall(calls[i]); | ||
| } | ||
| } | ||
|
|
||
| /// @notice Generic call function to execute a call to an arbitrary address | ||
| /// @param target Address to call | ||
| /// @param data Calldata to execute | ||
| function genericCall(address target, bytes calldata data) external externalLock { | ||
| target.functionCall(data); | ||
| } | ||
|
|
||
| /// @notice Wraps native asset into an ERC-20 token | ||
| /// @param amount Amount of native asset to wrap | ||
| function wrap(uint256 amount) external externalLock { | ||
| WRAPPED_NATIVE.deposit{ value: amount }(); | ||
| } | ||
|
|
||
| /// @notice Sweeps an ERC-20 token to a specified address | ||
| /// @param token ERC-20 token to sweep | ||
| /// @param to Address to send the token to | ||
| function sweep(IERC20Upgradeable token, address to) external externalLock { | ||
| token.safeTransfer(to, token.balanceOf(address(this))); | ||
| } | ||
|
|
||
| /// @notice Approves the maximum amount of an ERC-20 token to a specified address | ||
| /// @param token ERC-20 token to approve | ||
| /// @param spender Address to approve the token to | ||
| function approveMax(IERC20Upgradeable token, address spender) external externalLock { | ||
| token.forceApprove(spender, 0); | ||
| token.forceApprove(spender, type(uint256).max); | ||
| } | ||
|
|
||
| /// @notice Produces an EIP-712 digest of the multicall data | ||
| /// @param calls Array of calldata to execute | ||
| /// @param deadline Deadline for the transaction | ||
| /// @return Digest of the multicall data | ||
| function _hashMulticall(bytes[] calldata calls, uint256 deadline) internal view returns (bytes32) { | ||
| bytes32[] memory callHashes = new bytes32[](calls.length); | ||
| for (uint256 i = 0; i < calls.length; i++) { | ||
| callHashes[i] = keccak256(calls[i]); | ||
| } | ||
| return | ||
| _hashTypedDataV4( | ||
| keccak256(abi.encode(MULTICALL_TYPEHASH, keccak256(abi.encodePacked(callHashes)), deadline)) | ||
| ); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,89 @@ | ||
| // SPDX-License-Identifier: BSD-3-Clause | ||
| pragma solidity 0.8.25; | ||
|
|
||
| /** | ||
| * @title ISwapRouter | ||
| * @author Venus Protocol | ||
| * @notice Interface for the SwapRouter contract implementing swap features | ||
| */ | ||
| interface ISwapRouter { | ||
| /** | ||
| * @notice Swaps tokens and supplies the result to a Venus market | ||
| * @param vToken The vToken market to supply to | ||
| * @param tokenIn The input token to swap from | ||
| * @param amountIn The amount of input tokens to swap | ||
| * @param minAmountOut The minimum amount of output tokens expected | ||
| * @param swapData Array of bytes containing swap instructions | ||
| * @custom:event Emits SwapAndSupply event | ||
| */ | ||
| function swapAndSupply( | ||
| address vToken, | ||
| address tokenIn, | ||
| uint256 amountIn, | ||
| uint256 minAmountOut, | ||
| bytes[] calldata swapData | ||
|
||
| ) external payable; | ||
|
|
||
| /** | ||
| * @notice Swaps native tokens (BNB) and supplies to a Venus market | ||
| * @param vToken The vToken market to supply to | ||
| * @param minAmountOut The minimum amount of output tokens expected | ||
| * @param swapData Array of bytes containing swap instructions | ||
| * @custom:event Emits SwapAndSupply event | ||
| */ | ||
| function swapNativeAndSupply(address vToken, uint256 minAmountOut, bytes[] calldata swapData) external payable; | ||
|
|
||
| /** | ||
| * @notice Swaps tokens and repays debt to a Venus market | ||
| * @param vToken The vToken market to repay debt to | ||
| * @param tokenIn The input token to swap from | ||
| * @param amountIn The amount of input tokens to swap | ||
| * @param minAmountOut The minimum amount of output tokens expected | ||
| * @param swapData Array of bytes containing swap instructions | ||
| * @custom:event Emits SwapAndRepay event | ||
| */ | ||
| function swapAndRepay( | ||
| address vToken, | ||
| address tokenIn, | ||
| uint256 amountIn, | ||
| uint256 minAmountOut, | ||
| bytes[] calldata swapData | ||
| ) external payable; | ||
|
|
||
| /** | ||
| * @notice Swaps native tokens and repays debt to a Venus market | ||
| * @param vToken The vToken market to repay debt to | ||
| * @param minAmountOut The minimum amount of output tokens expected | ||
| * @param swapData Array of bytes containing swap instructions | ||
| * @custom:event Emits SwapAndRepay event | ||
| */ | ||
| function swapNativeAndRepay(address vToken, uint256 minAmountOut, bytes[] calldata swapData) external payable; | ||
|
|
||
| /** | ||
| * @notice Swaps tokens and repays the full debt for a user | ||
| * @param vToken The vToken market to repay full debt to | ||
| * @param tokenIn The input token to swap from | ||
| * @param maxAmountIn The maximum amount of input tokens to use | ||
| * @param swapData Array of bytes containing swap instructions | ||
| * @custom:event Emits SwapAndRepay event | ||
| */ | ||
| function swapAndRepayFull( | ||
| address vToken, | ||
| address tokenIn, | ||
| uint256 maxAmountIn, | ||
| bytes[] calldata swapData | ||
| ) external payable; | ||
|
|
||
| /** | ||
| * @notice Sweeps leftover ERC-20 tokens from the contract | ||
| * @param token The token to sweep | ||
| * @custom:event Emits SweepToken event | ||
| */ | ||
| function sweepToken(address token) external; | ||
|
|
||
| /** | ||
| * @notice Sweeps leftover native tokens from the contract | ||
| * @custom:event Emits SweepNative event | ||
| */ | ||
| function sweepNative() external; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please include explicit return types in the function signatures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VBNBdoesn't have return types in the following functions.