-
Notifications
You must be signed in to change notification settings - Fork 24
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
refactor(SwapHelperLib)!: replace system contract with uniswap router address #197
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,7 +4,6 @@ pragma solidity 0.8.26; | |||||||||||||
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol"; | ||||||||||||||
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router01.sol"; | ||||||||||||||
import "./shared/interfaces/IZRC20.sol"; | ||||||||||||||
import "./SystemContract.sol"; | ||||||||||||||
import "./shared/libraries/UniswapV2Library.sol"; | ||||||||||||||
|
||||||||||||||
library SwapHelperLib { | ||||||||||||||
|
@@ -112,41 +111,39 @@ library SwapHelperLib { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
function swapExactTokensForTokens( | ||||||||||||||
SystemContract systemContract, | ||||||||||||||
address router, | ||||||||||||||
address zrc20, | ||||||||||||||
uint256 amount, | ||||||||||||||
address targetZRC20, | ||||||||||||||
uint256 minAmountOut | ||||||||||||||
) internal returns (uint256) { | ||||||||||||||
address factory = IUniswapV2Router01(router).factory(); | ||||||||||||||
address wzeta = IUniswapV2Router01(router).WETH(); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential Mismatch: The Verify that - address wzeta = IUniswapV2Router01(router).WETH();
+ address wzeta = IWZETA(wzetaContractAddress).address; Ensure that the correct interface or method is used to obtain the
Comment on lines
+120
to
+121
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security Risk: Relying on Unverified By obtaining the Ensure that the + require(isTrustedRouter(router), "SwapHelperLib: Untrusted router address");
address factory = IUniswapV2Router01(router).factory();
address wzeta = IUniswapV2Router01(router).WETH(); Alternatively, consider obtaining
|
||||||||||||||
|
||||||||||||||
address[] memory path; | ||||||||||||||
path = new address[](2); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = targetZRC20; | ||||||||||||||
|
||||||||||||||
bool isSufficientLiquidity = _isSufficientLiquidity( | ||||||||||||||
systemContract.uniswapv2FactoryAddress(), | ||||||||||||||
factory, | ||||||||||||||
amount, | ||||||||||||||
minAmountOut, | ||||||||||||||
path | ||||||||||||||
); | ||||||||||||||
|
||||||||||||||
bool isZETA = targetZRC20 == systemContract.wZetaContractAddress() || | ||||||||||||||
zrc20 == systemContract.wZetaContractAddress(); | ||||||||||||||
bool isZETA = targetZRC20 == wzeta || zrc20 == wzeta; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect Comparison: The comparison Confirm that - bool isZETA = targetZRC20 == wzeta || zrc20 == wzeta;
+ address wZetaAddress = /* obtain correct wZETA address */;
+ bool isZETA = targetZRC20 == wZetaAddress || zrc20 == wZetaAddress;
|
||||||||||||||
|
||||||||||||||
if (!isSufficientLiquidity && !isZETA) { | ||||||||||||||
path = new address[](3); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = systemContract.wZetaContractAddress(); | ||||||||||||||
path[1] = wzeta; | ||||||||||||||
path[2] = targetZRC20; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
IZRC20(zrc20).approve( | ||||||||||||||
address(systemContract.uniswapv2Router02Address()), | ||||||||||||||
amount | ||||||||||||||
); | ||||||||||||||
uint256[] memory amounts = IUniswapV2Router01( | ||||||||||||||
systemContract.uniswapv2Router02Address() | ||||||||||||||
).swapExactTokensForTokens( | ||||||||||||||
IZRC20(zrc20).approve(address(router), amount); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Security Concern: Approving Unverified Approving the Before granting approval, validate the + require(isTrustedRouter(router), "SwapHelperLib: Untrusted router address");
IZRC20(zrc20).approve(address(router), amount); Implement or update the
|
||||||||||||||
uint256[] memory amounts = IUniswapV2Router01(router) | ||||||||||||||
.swapExactTokensForTokens( | ||||||||||||||
amount, | ||||||||||||||
minAmountOut, | ||||||||||||||
path, | ||||||||||||||
|
@@ -157,17 +154,16 @@ library SwapHelperLib { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
function swapExactTokensForTokensDirectly( | ||||||||||||||
SystemContract systemContract, | ||||||||||||||
address router, | ||||||||||||||
address zrc20, | ||||||||||||||
uint256 amount, | ||||||||||||||
address targetZRC20, | ||||||||||||||
uint256 minAmountOut | ||||||||||||||
) internal returns (uint256) { | ||||||||||||||
bool existsPairPool = _existsPairPool( | ||||||||||||||
systemContract.uniswapv2FactoryAddress(), | ||||||||||||||
zrc20, | ||||||||||||||
targetZRC20 | ||||||||||||||
); | ||||||||||||||
address factory = IUniswapV2Router01(router).factory(); | ||||||||||||||
address wzeta = IUniswapV2Router01(router).WETH(); | ||||||||||||||
|
||||||||||||||
Comment on lines
+163
to
+165
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repeat Validation: Ensure Consistent Similar to earlier functions, the Add validation for the + require(isTrustedRouter(router), "SwapHelperLib: Untrusted router address");
address factory = IUniswapV2Router01(router).factory();
address wzeta = IUniswapV2Router01(router).WETH(); Ensure that this validation is consistently applied across all functions that use the 📝 Committable suggestion
Suggested change
|
||||||||||||||
bool existsPairPool = _existsPairPool(factory, zrc20, targetZRC20); | ||||||||||||||
|
||||||||||||||
address[] memory path; | ||||||||||||||
if (existsPairPool) { | ||||||||||||||
|
@@ -177,17 +173,13 @@ library SwapHelperLib { | |||||||||||||
} else { | ||||||||||||||
path = new address[](3); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = systemContract.wZetaContractAddress(); | ||||||||||||||
path[1] = wzeta; | ||||||||||||||
path[2] = targetZRC20; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
IZRC20(zrc20).approve( | ||||||||||||||
address(systemContract.uniswapv2Router02Address()), | ||||||||||||||
amount | ||||||||||||||
); | ||||||||||||||
uint256[] memory amounts = IUniswapV2Router01( | ||||||||||||||
systemContract.uniswapv2Router02Address() | ||||||||||||||
).swapExactTokensForTokens( | ||||||||||||||
IZRC20(zrc20).approve(wzeta, amount); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect Approval: Approving In the line Update the approval to target the - IZRC20(zrc20).approve(wzeta, amount);
+ IZRC20(zrc20).approve(router, amount); This aligns with the pattern used in other functions and ensures the 📝 Committable suggestion
Suggested change
|
||||||||||||||
uint256[] memory amounts = IUniswapV2Router01(router) | ||||||||||||||
.swapExactTokensForTokens( | ||||||||||||||
amount, | ||||||||||||||
minAmountOut, | ||||||||||||||
path, | ||||||||||||||
|
@@ -198,17 +190,16 @@ library SwapHelperLib { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
function swapTokensForExactTokens( | ||||||||||||||
SystemContract systemContract, | ||||||||||||||
address router, | ||||||||||||||
address zrc20, | ||||||||||||||
uint256 amount, | ||||||||||||||
address targetZRC20, | ||||||||||||||
uint256 amountInMax | ||||||||||||||
) internal returns (uint256) { | ||||||||||||||
bool existsPairPool = _existsPairPool( | ||||||||||||||
systemContract.uniswapv2FactoryAddress(), | ||||||||||||||
zrc20, | ||||||||||||||
targetZRC20 | ||||||||||||||
); | ||||||||||||||
address factory = IUniswapV2Router01(router).factory(); | ||||||||||||||
address wzeta = IUniswapV2Router01(router).WETH(); | ||||||||||||||
|
||||||||||||||
bool existsPairPool = _existsPairPool(factory, zrc20, targetZRC20); | ||||||||||||||
|
||||||||||||||
address[] memory path; | ||||||||||||||
if (existsPairPool) { | ||||||||||||||
|
@@ -218,17 +209,13 @@ library SwapHelperLib { | |||||||||||||
} else { | ||||||||||||||
path = new address[](3); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = systemContract.wZetaContractAddress(); | ||||||||||||||
path[1] = wzeta; | ||||||||||||||
path[2] = targetZRC20; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
IZRC20(zrc20).approve( | ||||||||||||||
address(systemContract.uniswapv2Router02Address()), | ||||||||||||||
amountInMax | ||||||||||||||
); | ||||||||||||||
uint256[] memory amounts = IUniswapV2Router01( | ||||||||||||||
systemContract.uniswapv2Router02Address() | ||||||||||||||
).swapTokensForExactTokens( | ||||||||||||||
IZRC20(zrc20).approve(router, amountInMax); | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Approval Addresses Need Standardization The verification reveals inconsistent approval addresses across the contract:
While the specific line in question uses 🔗 Analysis chainInconsistent Approval Address: Ensure Approval is Granted to In the Run the following script to check for inconsistencies in approval addresses: 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Verify that all approvals are granted to the `router` address.
# Search for approval statements in the contract
rg 'approve\(([^,]+),' contracts/SwapHelperLib.sol -A 2
# Expected result: All `approve` calls should target `router`.
Length of output: 661 |
||||||||||||||
uint256[] memory amounts = IUniswapV2Router01(router) | ||||||||||||||
.swapTokensForExactTokens( | ||||||||||||||
amount, | ||||||||||||||
amountInMax, | ||||||||||||||
path, | ||||||||||||||
|
@@ -239,28 +226,31 @@ library SwapHelperLib { | |||||||||||||
} | ||||||||||||||
|
||||||||||||||
function getMinOutAmount( | ||||||||||||||
SystemContract systemContract, | ||||||||||||||
address router, | ||||||||||||||
address zrc20, | ||||||||||||||
address target, | ||||||||||||||
uint256 amountIn | ||||||||||||||
) public view returns (uint256 minOutAmount) { | ||||||||||||||
address factory = IUniswapV2Router01(router).factory(); | ||||||||||||||
address wzeta = IUniswapV2Router01(router).WETH(); | ||||||||||||||
|
||||||||||||||
Comment on lines
+234
to
+236
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validation Required: Unverified Use of The Add a validation check for the + require(isTrustedRouter(router), "SwapHelperLib: Untrusted router address");
address factory = IUniswapV2Router01(router).factory();
address wzeta = IUniswapV2Router01(router).WETH(); Ensure that all functions interacting with external contracts validate input addresses.
|
||||||||||||||
address[] memory path; | ||||||||||||||
|
||||||||||||||
path = new address[](2); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = target; | ||||||||||||||
uint[] memory amounts1 = UniswapV2Library.getAmountsOut( | ||||||||||||||
systemContract.uniswapv2FactoryAddress(), | ||||||||||||||
factory, | ||||||||||||||
amountIn, | ||||||||||||||
path | ||||||||||||||
); | ||||||||||||||
|
||||||||||||||
path = new address[](3); | ||||||||||||||
path[0] = zrc20; | ||||||||||||||
path[1] = systemContract.wZetaContractAddress(); | ||||||||||||||
path[1] = wzeta; | ||||||||||||||
path[2] = target; | ||||||||||||||
uint[] memory amounts2 = UniswapV2Library.getAmountsOut( | ||||||||||||||
systemContract.uniswapv2FactoryAddress(), | ||||||||||||||
factory, | ||||||||||||||
amountIn, | ||||||||||||||
path | ||||||||||||||
); | ||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
import type * as interfaces from "./interfaces"; | ||
export type { interfaces }; | ||
import type * as token from "./token"; | ||
export type { token }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
import type { BaseContract, Signer, utils } from "ethers"; | ||
|
||
import type { Listener, Provider } from "@ethersproject/providers"; | ||
import type { | ||
TypedEventFilter, | ||
TypedEvent, | ||
TypedListener, | ||
OnEvent, | ||
} from "../../../../common"; | ||
|
||
export interface IERC1155ErrorsInterface extends utils.Interface { | ||
functions: {}; | ||
|
||
events: {}; | ||
} | ||
|
||
export interface IERC1155Errors extends BaseContract { | ||
connect(signerOrProvider: Signer | Provider | string): this; | ||
attach(addressOrName: string): this; | ||
deployed(): Promise<this>; | ||
|
||
interface: IERC1155ErrorsInterface; | ||
|
||
queryFilter<TEvent extends TypedEvent>( | ||
event: TypedEventFilter<TEvent>, | ||
fromBlockOrBlockhash?: string | number | undefined, | ||
toBlock?: string | number | undefined | ||
): Promise<Array<TEvent>>; | ||
|
||
listeners<TEvent extends TypedEvent>( | ||
eventFilter?: TypedEventFilter<TEvent> | ||
): Array<TypedListener<TEvent>>; | ||
listeners(eventName?: string): Array<Listener>; | ||
removeAllListeners<TEvent extends TypedEvent>( | ||
eventFilter: TypedEventFilter<TEvent> | ||
): this; | ||
removeAllListeners(eventName?: string): this; | ||
off: OnEvent<this>; | ||
on: OnEvent<this>; | ||
once: OnEvent<this>; | ||
removeListener: OnEvent<this>; | ||
|
||
functions: {}; | ||
|
||
callStatic: {}; | ||
|
||
filters: {}; | ||
|
||
estimateGas: {}; | ||
|
||
populateTransaction: {}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
import type { BaseContract, Signer, utils } from "ethers"; | ||
|
||
import type { Listener, Provider } from "@ethersproject/providers"; | ||
import type { | ||
TypedEventFilter, | ||
TypedEvent, | ||
TypedListener, | ||
OnEvent, | ||
} from "../../../../common"; | ||
|
||
export interface IERC20ErrorsInterface extends utils.Interface { | ||
functions: {}; | ||
|
||
events: {}; | ||
} | ||
|
||
export interface IERC20Errors extends BaseContract { | ||
connect(signerOrProvider: Signer | Provider | string): this; | ||
attach(addressOrName: string): this; | ||
deployed(): Promise<this>; | ||
|
||
interface: IERC20ErrorsInterface; | ||
|
||
queryFilter<TEvent extends TypedEvent>( | ||
event: TypedEventFilter<TEvent>, | ||
fromBlockOrBlockhash?: string | number | undefined, | ||
toBlock?: string | number | undefined | ||
): Promise<Array<TEvent>>; | ||
|
||
listeners<TEvent extends TypedEvent>( | ||
eventFilter?: TypedEventFilter<TEvent> | ||
): Array<TypedListener<TEvent>>; | ||
listeners(eventName?: string): Array<Listener>; | ||
removeAllListeners<TEvent extends TypedEvent>( | ||
eventFilter: TypedEventFilter<TEvent> | ||
): this; | ||
removeAllListeners(eventName?: string): this; | ||
off: OnEvent<this>; | ||
on: OnEvent<this>; | ||
once: OnEvent<this>; | ||
removeListener: OnEvent<this>; | ||
|
||
functions: {}; | ||
|
||
callStatic: {}; | ||
|
||
filters: {}; | ||
|
||
estimateGas: {}; | ||
|
||
populateTransaction: {}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
import type { BaseContract, Signer, utils } from "ethers"; | ||
|
||
import type { Listener, Provider } from "@ethersproject/providers"; | ||
import type { | ||
TypedEventFilter, | ||
TypedEvent, | ||
TypedListener, | ||
OnEvent, | ||
} from "../../../../common"; | ||
|
||
export interface IERC721ErrorsInterface extends utils.Interface { | ||
functions: {}; | ||
|
||
events: {}; | ||
} | ||
|
||
export interface IERC721Errors extends BaseContract { | ||
connect(signerOrProvider: Signer | Provider | string): this; | ||
attach(addressOrName: string): this; | ||
deployed(): Promise<this>; | ||
|
||
interface: IERC721ErrorsInterface; | ||
|
||
queryFilter<TEvent extends TypedEvent>( | ||
event: TypedEventFilter<TEvent>, | ||
fromBlockOrBlockhash?: string | number | undefined, | ||
toBlock?: string | number | undefined | ||
): Promise<Array<TEvent>>; | ||
|
||
listeners<TEvent extends TypedEvent>( | ||
eventFilter?: TypedEventFilter<TEvent> | ||
): Array<TypedListener<TEvent>>; | ||
listeners(eventName?: string): Array<Listener>; | ||
removeAllListeners<TEvent extends TypedEvent>( | ||
eventFilter: TypedEventFilter<TEvent> | ||
): this; | ||
removeAllListeners(eventName?: string): this; | ||
off: OnEvent<this>; | ||
on: OnEvent<this>; | ||
once: OnEvent<this>; | ||
removeListener: OnEvent<this>; | ||
|
||
functions: {}; | ||
|
||
callStatic: {}; | ||
|
||
filters: {}; | ||
|
||
estimateGas: {}; | ||
|
||
populateTransaction: {}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
export type { IERC1155Errors } from "./IERC1155Errors"; | ||
export type { IERC20Errors } from "./IERC20Errors"; | ||
export type { IERC721Errors } from "./IERC721Errors"; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/* Autogenerated file. Do not edit manually. */ | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
import type * as draftIerc6093Sol from "./draft-IERC6093.sol"; | ||
export type { draftIerc6093Sol }; |
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.
Critical Security Concern: Validate the
router
AddressThe function now accepts an
address router
parameter. Since this address is used to interact with external contracts and is critical for the swapping functionality, it's imperative to ensure that therouter
address provided is a trusted Uniswap router contract. Passing an unverifiedrouter
address could lead to interactions with malicious contracts, resulting in loss of funds or other security breaches.Consider adding a validation mechanism to ensure the
router
address is trusted:+ require(isTrustedRouter(router), "SwapHelperLib: Untrusted router address");
Implement the
isTrustedRouter
function to check therouter
address against a whitelist of known, trusted router addresses.