xanoutas/solidity-security-findings huggingface dataset:
Incorrect Refund Amount Calculation in `swapNoPath` Function
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/main/src/swappers/UniSwapper.sol#L107-L113


# Vulnerability details

## Impact:

The identified issue in the `swapNoPath` function could lead to incorrect refund calculations, potentially resulting in a discrepancy between the refunded amount and the actual amount spent. The problem arises from subtracting `swapParams.amountOut` from `swapParams.amountIn`, which will not accurately represent the correct amount to be refunded. This discrepancy could impact the financial integrity of the protocol and result in unexpected behavior during token swaps.

## Proof of Concept:

The issue is evident in the following code snippet:

```solidity
function swapNoPath(
    SwapParams memory swapParams,
    address receiver,
    address refund
) public payable returns (address tokenOut, uint256 amountOut) {
    swapParams = _receiveAndWrapIfNeeded(swapParams);

    if (swapParams.direction == SwapDirection.EXACT_OUT) {
        _refundUser(
            refund,
            swapParams.tokenIn,
            //@audit wrong amount refunded
            swapParams.amountIn - swapParams.amountOut
        );
    }

    uint amt2Recipient = swapParams.direction == SwapDirection.EXACT_OUT
        ? swapParams.amountOut
        : swapParams.amountIn;

    _sendToRecipient(receiver, swapParams.tokenOut, amt2Recipient);
    return (swapParams.tokenOut, amt2Recipient);
}
```

The `swapParams.amountIn` and `swapParams.amountOut` variables represent amounts of different tokens, possibly with different decimal precision, tokenIn could be ETH (18 decimals) and tokenOut could be USDC (6 decimals). Subtracting `swapParams.amountOut` from `swapParams.amountIn` doesn't make sense and will not accurately calculate the correct refund amount, especially when dealing with tokens with varying decimal places.

To address this issue, the correct refund amount should be based on the `swapParams.amountIn` value alone.

## Tools Used:

Manual review

## Recommended Mitigation Steps:

Update the `_refundUser` call to ensure that the correct amount is refunded based on `swapParams.amountIn` only. Modify the code as follows:

```solidity
_refundUser(
    refund,
    swapParams.tokenIn,
    swapParams.amountIn
);
```


## Assessed type

Error
hardcoded slippage can freeze users funds during market turblances.
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/07ef78215e3d246d47a410651906287c6acec3ef/src/swappers/UniSwapper.sol#L123-L141


# Vulnerability details

## Impact
hardcoded slippage can freeze users funds during market turblances.

the if you look at the function `swapExactin` in `uniswapper.sol` you will see the slippage is hard coded for the amount in which is unacceptable at all,tokens price may go down.

the function `swapExactIn` did it like this `swapExactIn`

If Luna/UST things happen again, users' funds may get locked.

as it is in uniswap docs hardly specified that this is very dangerous
`docs: amountOutMinimum: we are setting to zero, but this is a significant risk in production. For a real deployment, this value should be calculated using our SDK or an onchain price oracle - this helps protect against getting an unusually bad price for a trade due to a front running sandwich or another type of price manipulation`

https://docs.uniswap.org/contracts/v3/guides/swaps/single-swaps#swap-input-parameters

the amount of `amountOutMinimum` should be only taken from oracle or uniswap SDK like how all projects do and uniswap said in docs otherwise problem. 
## Proof of Concept
```solidity 

 function swapExactIn(
        SwapParams memory swapParams, // SwapParams is a struct
        address receiver
    ) public payable routerIsSet returns (uint256 amountOut) {
        swapParams = _receiveAndWrapIfNeeded(swapParams);

        IV3SwapRouter.ExactInputParams memory params = IV3SwapRouter
            .ExactInputParams({
                path: swapParams.path,
                recipient: address(this),
                amountIn: swapParams.amountIn,
                amountOutMinimum: swapParams.amountOut
            });

        IERC20(swapParams.tokenIn).approve(uniswap_router, swapParams.amountIn);
        amountOut = IV3SwapRouter(uniswap_router).exactInput(params);

        _sendToRecipient(receiver, swapParams.tokenOut, amountOut);
    }
```
## Tools Used
vs code
## Recommended Mitigation Steps
- consider using uniswap advices as its best source: "For a real deployment, this value should be calculated using our SDK or an onchain price oracle - this helps protect against getting an unusually bad price for a trade due to a front running sandwich or another type of price manipulation"





## Assessed type

Uniswap
Attacker could steal every ERC20 token from the UTBExecutor contract
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/UTB.sol#L168-L200
https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/UTB.sol#L259


# Vulnerability details

## Impact
The vulnerability is identified within the crypto protocol's UTB contract, specifically in the swapAndModifyPostBridge function, part of the UTBExecutor on the target chain. The issue arises from a lack of validation for the correctness of the output token during a token swap operation. In this scenario, an attacker can manipulate the tokenOut address, potentially swapping for a more profitable token within the UTBExecutor contract on the target chain. This manipulation can lead to the unauthorized acquisition of valuable tokens within the contract.

## Proof of Concept
The vulnerability occurs in the performSwap function, where the value of tokenOut is not adequately validated. By exploiting this, an attacker can adjust the tokenOut address, allowing them to target the most lucrative tokens within the UTBExecutor contract on the target chain. Consequently, the attacker can illegitimately acquire tokens of higher value than intended during the cross-chain transfer.
vulnerable function
```
function swapAndModifyPostBridge(
    BridgeInstructions memory instructions
)
    private
    returns (
        uint256 amount2Bridge,
        BridgeInstructions memory //@audit --> could be re-written in this way, saving gas
    )
{
    (address tokenOut, uint256 amountOut) = performSwap(
        instructions.preBridge
    );

    // Ensure that the tokenOut is a valid token address
    require(isValidToken(tokenOut), "Invalid tokenOut address");

    SwapParams memory newPostSwapParams = abi.decode(
        instructions.postBridge.swapPayload,
        (SwapParams)
    );

    // The vulnerability lies here, where tokenOut is not adequately checked
    newPostSwapParams.tokenOut = tokenOut;

    newPostSwapParams.amountIn = IBridgeAdapter(
        bridgeAdapters[instructions.bridgeId]
    ).getBridgedAmount(amountOut, tokenOut, newPostSwapParams.tokenIn);

    instructions.postBridge.swapPayload = ISwapper(swappers[
        instructions.postBridge.swapperId
    ]).updateSwapParams(
        newPostSwapParams,
        instructions.postBridge.swapPayload
    );

    amount2Bridge = amountOut;
}
```
summary:
attacker will set newPostSwapParams.tokenIn to like DAI(1e18 decimals) and newPostSwapParams.tokenOut will be USDC(1e6 decimals) in theory they will transfer 1 dai in the other chain,but in practise they are transfering 1e18/1e6,so 1e12 USDC (1000000000) to the target user of the other chain,because the current implementation only checks for amountOut but the tokenOut is only checked if it is the address(0) one,in all other cases the scenario shown above could be used to drain the UTBExecutor contract of the target chain.

newPostSwapParams will be this:
```
SwapParams memory newPostSwapPar
```UniSwapper :: `swapExactOut` can be called by anyone  and contracts can loss funds
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/swappers/UniSwapper.sol#L143


# Vulnerability details

## Impact
anyone can swap out token after they are locked. attacker can swap out all 
tokens for to them self. 

 
## Tools Used
manual

## Recommended Mitigation Steps
add a function modifier for `swapExactOut`


## Assessed type

Access Control
Insufficient access control in `setRouter()` allows uncontrolled minting of `DcntEth`
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20-L30


# Vulnerability details

## Impact
The `DcntEth` contract is designed to interface with the `DecentEthRouter` contract, which is intended to be the sole entity capable of calling the functions [`mint()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L24) and [`burn()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L28). These functions are critical as they directly affect the token supply of `DcntEth`. The [`setRouter(address _router)`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DcntEth.sol#L20) function is meant to establish the router's address, which is then enforced by the `onlyRouter` modifier on sensitive functions.

However, the current implementation of `setRouter()` lacks any form of access control, allowing any user to set themselves as the router. This poses a severe security risk as an unauthorized user could call `setRouter()` to set their address as the router and subsequently invoke `mint()` to arbitrarily increase the token supply in their favor, leading to potential token inflation and devaluation.

## Proof of Concept
1. An attacker deploys their own contract or uses an EOA.
2. The attacker calls `setRouter()` with their address.
3. The attacker is now set as the router and can call `mint()` to mint an arbitrary amount of `DcntEth` to any address they choose.

## Tools Used
Manual review

## Recommended Mitigation Steps
To mitigate this issue, implement access control in the `setRouter()` function. This can be achieved by adding the `onlyOwner` modifier.

The code fix would be as follows:

```solidity
function setRouter(address _router) public onlyOwner {
    router = _router;
}
```

This change ensures that only the owner of the contract can set or change the router, preventing unauthorized manipulation of the token supply.


## Assessed type

Access Control
Router could be drained due to re-entrancy
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L313-L319


# Vulnerability details

## Impact

`removeLiquidityEth()` is open to a reentrancy attack on all chains where `address.transfer()` isn't enough to block re-entrancy. Currently only 2300 gas is forwarded which blocks reentrancy on ethereum mainnet, but even this [could change in the future](https://github.com/ethereum/solidity/issues/7455).

The more immediate danger is EVM-chains that have different opcode costs than Etherium mainnet. Given that Decent will be deployed to networks with different opcode costs than Ethereum Decent could potentially be drained. An example of such a network is [zkSync](https://docs.zksync.io/build/developer-reference/fee-model.html) where the storage cost is dynamically based on L1 costs. The cost of storage writes is also set to change significantly for zkSync and other L2s with EIP4844.

## Proof of Concept

The following code is used to withdraw eth:

```solidity
 function removeLiquidityEth(
        uint256 amount
    ) public onlyEthChain userIsWithdrawing(amount) {
        dcntEth.burn(address(this), amount);
        weth.withdraw(amount);
        payable(msg.sender).transfer(amount);
    }
```

with the following modifier:

```solidity
 modifier userIsWithdrawing(uint256 amount) {
        uint256 balance = balanceOf[msg.sender];
        require(balance >= amount, "not enough balance");
        _;
        balanceOf[msg.sender] -= amount;
    }
```

As we can see the balance is upgraded after the call. We can therefore re-enter and drain the contract IF `address.transfer()` isn't enough to block reentrancy. 

## Tools Used
vscode
## Recommended Mitigation Steps
Update balance before ETH is transferred out of the contract.


## Assessed type

Reentrancy
Malicious user can take out all the funds from UniSwapper.sol if present
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/main/src/swappers/UniSwapper.sol#L100-L121


# Vulnerability details

## Impact
Malicious user can take out all tokens from `UniSwapper.sol` using the function `swapNoPath()`

## Proof of Concept

Initially, the public function swapNoPath() lacks input validation.

A potential security concern arises when a malicious user, having configured the swapParams.direction as SwapDirection.EXACT_IN, invokes the function. Subsequently, the function transfers the specified amount of tokens (swapParams.amountIn) to itself, as facilitated by _receiveAndWrapIfNeeded(). Following this, an equal quantity of `swapParams.tokenOut` tokens is then transferred to the designated receiver.
This is seen in this following snippet
```Solidity
        uint amt2Recipient = swapParams.direction == SwapDirection.EXACT_OUT
            ? swapParams.amountOut
            : swapParams.amountIn;

        _sendToRecipient(receiver, swapParams.tokenOut, amt2Recipient);
```

The malicious user can create their own ERC20 token and then call this function while setting `swapParams.amountOut` as the token they want to steal and `swapParams.amountIn` as their own built ERC20 token. 
And will steal all the tokens present in this address.

## Tools Used
Manual Review

## Recommended Mitigation Steps
This function is supposed to be internal and not public since it is not validating any inputs and is called by the function `swap()`





## Assessed type

ERC20
Failed calls made via `bridgeWithPayload()` may transfer funds to address not under user control
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentBridgeExecutor.sol#L36
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentBridgeExecutor.sol#L63


# Vulnerability details

## Impact
The `DecentBridgeExecutor` contract has two private functions, [`_executeWeth()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentBridgeExecutor.sol#L24) and [`_executeEth()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentBridgeExecutor.sol#L54), which are used to execute transactions with a custom payload received through the Decent bridge.

In both functions, if the call to the target contract fails, the contract sends the funds back to the `from` address. This behavior is problematic because the `from` address is hardcoded as `msg.sender` in the `_getCallParams()` function on the [sender side](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L148):
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L100-L109
```solidity
	if (msgType == MT_ETH_TRANSFER) {
		payload = abi.encode(msgType, msg.sender, _toAddress, deliverEth);
	} else {
		payload = abi.encode(
			msgType,
			msg.sender,
			_toAddress,
			deliverEth,
			additionalPayload
		);
```

The problem is that the sender in the source chain may not be in control of the same address in the destination chain. For instance, this could occur if the sender is a Gnosis Safe created using the `createProxy()` function of the Proxy Factory. This issue has been exploited in the past to [steal 20 million $OP](https://inspexco.medium.com/how-20-million-op-was-stolen-from-the-multisig-wallet-not-yet-owned-by-wintermute-3f6c75db740a).

## Proof of Concept

1. Alice owns a Gnosis Safe deployed using the `createProxy()` function of the Gnosis Safe Proxy Factory. 
2. Alice initiates a cross-chain transaction from her safe through the [`DecentEthRouter.bridgeWithPayload()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L197)function. The `_getCallParams()` function hardcodes the address of Alice's safe on the source chain as the `from` address.
3. The transaction is processed by either the `_executeWeth()` or `_executeEth()` function in the `DecentBridgeExecutor` contract of the target chain.
4. The transaction call to the target contract fails due to an issue outside of Alice's control, such as the target contract being paused.
5. The `DecentBridgeExecutor` contract sends the funds to the `from` address, which is the address of Alice's safe on the source chain.
6. However, since Alice does not control this address on the destination chain, she is unable to access these funds. This results in a loss of funds for Alice.

## Too
Return value of call() in UTBExecutor is not checked causing loss of funds
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-01-decent/blob/011f62059f3a0b1f3577c8ccd1140f0cf3e7bb29/src/UTBExecutor.sol#L41


# Vulnerability details

## Impact
Currently in the UTBExecutor.sol contract, there are two instances where the return value of call is not checked. In the first instance, this would lead to complete loss of output tokens received from the swap. In the second instance, this would break any external application changes that were supposed to be made by calling the payload.

## Proof of Concept

Both instances exist in the execute() function.

First instance:
- Assume both the target and refund address are the same address.
 - On Line 53, if the call to the target reverts, we enter the if block on Line 54.
 - On Line 55, since refund is the same address as target, the call reverts there as well. The issue here is that the return value of call made to the refund address is not checked, which allows further execution of the contract. i.e. we return early. This would cause permanent loss of funds for the user.
```solidity
File: UTBExecutor.sol
50:         bool success;
51:         if (token == address(0)) {
53:             (success, ) = target.call{value: amount}(payload);
54:             if (!success) {
55:                 (refund.call{value: amount}(""));
56:             }
57:             return;
58:         }
```

Second instance:
 - On line 75, the return value is cached but it is not checked to be true or false. Due to this if the call fails, this could break any external application changes that were supposed to be made by calling the payload.
```solidity
File: UTBExecutor.sol
73:         } else {
74:             
75:             (success, ) = target.call(payload);
76:         }
```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Check the return value of call() by wrapping it around a require statement.


## Assessed type

Error
Dropping payload in `onOFTReceived()` may lead to loss of funds
Audit: 2024-01-decent-findings
Severity: HIGH

# Lines of code

https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L266-L269


# Vulnerability details

## Impact
The [`DecentEthRouter.onOFTReceived()`](https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L237) function is responsible for handling incoming messages from the Decent bridge. It decodes the payload of the transfer to extract necessary information such as the type of message, sender, recipient, and whether the transfer should be in ETH or WETH.

If the message type is `MT_ETH_TRANSFER_WITH_PAYLOAD` and the sender sets `deliverEth` to false, the transaction is expected to allow the target contract to pull the WETH amount in a call with the given payload:
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentBridgeExecutor.sol#L31-L33
```solidity
	weth.approve(target, amount);
	(bool success, ) = target.call(callPayload);
```

However, if the WETH balance of the `DecentEthRouter` is lower than the transferred amount, the payload is simply dropped and instead, `DcntEth` is sent to the target address:
https://github.com/decentxyz/decent-bridge/blob/7f90fd4489551b69c20d11eeecb17a3f564afb18/src/DecentEthRouter.sol#L266-L269
```solidity
	if (weth.balanceOf(address(this)) < _amount) {
		dcntEth.transfer(_to, _amount);
		return;
	}
```

This could lead to loss of funds as the user may have required the payload to be executed to obtain the funds.

## Proof of Concept

1. A user initiates a cross-chain transaction by submitting a message through the `DecentEthRouter.bridgeWithPayload()` function. They want to stake WETH on a contract on another chain by calling the function `stakeWETHFor(address account, uint256 amount)`.
2. The `DecentEthRouter` receives the message in `onOFTReceived()`.
3. Its WETH balance is less than the amount of WETH the user is transferring.
4. The payload is dropped and instead transfers `DcntEth` directly to the target contract.
6. The user's funds are locked as `DcntEth` in the contract and cannot be recovered.

## Tools Used
Manual review

## Recommended Mitigation Steps
 If the WETH balance is not sufficient when processing a message of type `MT_ETH_TRANSFER_WITH_PAYLOAD`, revert and allow the sender to retry the message later. Alternatively, ensure there is always enough WETH in all supported chains, or at the very least document this behavior.


## Assessed type

Other