xanoutas/solidity-security-findings huggingface dataset:
Token decimals may be above 18 leading to underflow issues
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L49
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L67
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L650
https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L675


# Vulnerability details

## Impact
In both StableVault and Trading, there is an assumption that token decimal amounts are <=18.  However this can break if token decimals are >18, resulting in underflow which can lead to unpredictable behaviors, and extreme amounts during deposits and withdraws. 

## Proof of Concept
1) Token with decimals above 18 gets approved
2) User does a deposit() or withdraw() in one of the following: 
-StableVault deposit(): https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L49 
-StableVault withdraw(): https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/StableVault.sol#L67 
-Trading _handleDeposit(): https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L650 
- Trading _handleWithdraw(): https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L675 
3) Causes unexpectedly large amount of deposit/withdrawal 

## Tools Used
None

## Recommended Mitigation Steps
Add checks on the decimals either during whitelisting of tokens or add reverts in the functions handling deposits and withdrawals.
Error when handling deposit in the `addToPosition` function
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L255-L305


# Vulnerability details

## Impact

In the function `addToPosition` from the `Trading` contract the amount of open fees are handled using the `_handleOpenFees` function but when calling the `_handleDeposit` function the wrong margin is passed, in fact the `_handleDeposit` function gets `_addMargin - _fee` instead of `_addMargin` 

So this mean that the open fees are calculated and handled but when depositing there value will not be transferred from the trader and will not be deposited in the stableVault.

## Proof of Concept

The issue occurs in the `addToPosition` function :

File: contracts/Trading.sol [Line 255-305](https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L255-L305)

```
function addToPosition(
    uint _id,
    uint _addMargin,
    PriceData calldata _priceData,
    bytes calldata _signature,
    address _stableVault,
    address _marginAsset,
    ERC20PermitData calldata _permitData,
    address _trader
)
    external
{
    ...
    
    /* @audit
       fee are calculated and handled with _handleOpenFees
    */
    uint _fee = _handleOpenFees(_trade.asset, _addMargin*_trade.leverage/1e18, _trader, _trade.tigAsset, false);
    
    /* @audit
       But only (_addMargin - _fee) amount is deposited
    */
    _handleDeposit(
        _trade.tigAsset,
        _marginAsset,
        _addMargin - _fee,
        _stableVault,
        _permitData,
        _trader
    );
    ...
}
```

As you can see from the code above the `_handleDeposit` function receive `_addMargin - _fee` as new margin, this value is used to calculate the transferred amount from the trader :

File: contracts/Trading.sol [Line 565-576](https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L643-L659)
```
function _handleDeposit(address _tigAsset, address _marginAsset, uint256 _margin, address _stableVault, ERC20PermitData calldata _permitData, address _trader) internal {
    IStable tigAsset = IStable(_tigAsset);
    if (_tigAsset != _marginAsset) {
        if (_permitData.usePermit) {
            ERC20Permit(_marginAsset).permit(_trader, address(this), _permitData.amount, _permitData.deadline, _permitData.v, _permitData.r, _permitData.s);
        }
        uint256 _balBefore = tigAsset.balanceOf(address(this));
        uint _marginDecMultiplier = 10**(18-ExtendedIERC20(_marginAsset).decimals());
        
        /* @audit
           _margin == (_addMargin - _fee) is used to calculate transferred amount from trader 
           instead of the whole _addMargin value
        */
    
        IERC20(_marginAsset).transferFrom(_trader, address(this), _margin/_marginDecMultiplier);
        IERC20(_marginAsset).approve(_stableVault, type(uint).max);
        IStableVault(_stableVault).deposit(_marginAsset, _margin/_marginDecMultiplier);
        if (tigAsset.balanceOf(address(this)) != _balBefore + _margin) revert BadDeposit();
Ignored return value from "IERC20.transferFrom()"
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/StableVault.sol#L46
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L72
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L90
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/BondNFT.sol#L216


# Vulnerability details

## Impact
The return value from IERC20.transferFrom in "StableVault" was not checked, a malicious actor could first deposit a number of tokens without actually having it and then subsequently withdraw that amount of tokens from the "StableVault"

## Proof of Concept
first, by calling the function 
```solidity
function deposit(address _token, uint256 _amount) public {
        require(allowed[_token], "Token not listed");
        IERC20(_token).transferFrom(_msgSender(), address(this), _amount);
        IERC20Mintable(stable).mintFor(
            _msgSender(),
            _amount*(10**(18-IERC20Mintable(_token).decimals()))
        );
    }
```
with the address of a token in the allowed mapping, the contract mints a "StableToken" with the number of tokens passed to the function 
[mint function](#https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/StableVault.sol#L47)

Then a call to the "withdraw" function will send tokens to the caller
```solidity
function withdraw(address _token, uint256 _amount) external returns (uint256 _output) {
        IERC20Mintable(stable).burnFrom(_msgSender(), _amount);
        _output = _amount/10**(18-IERC20Mintable(_token).decimals());
        IERC20(_token).transfer(
            _msgSender(),
            _output
        );
    }
```


## Tools Used
Brownie, Slither

## Recommended Mitigation Steps
The above-mentioned attack can be mitigated by changing the line

```solidity
IERC20(_token).transferFrom(_msgSender(), address(this), _amount);
```
to

```solidity
require(IERC20(_token).transferFrom(_msgSender(), address(this), _amount)
    "Insufficient Funds");
```
Unchecked setters
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Referrals.sol#L32-L41


# Vulnerability details

## Impact
Incorrect data: If the '_referred' or 'protocol' variables are set to incorrect values, it could result in incorrect or unexpected behavior in the contract.

Manipulation: Malicious actors could potentially exploit this vulnerability to manipulate the system in their favor. For example, they could set the protocol variable to their own address to gain control of the contract.
## Proof of Concept
The 'setReferred' and 'setProtocol' functions in the Referrals contract allow anyone to set the _referred and protocol variables, respectively, without any checks or restrictions. This could potentially lead to incorrect data being set or malicious actors manipulating the system.
## Tools Used
Mythril and Truffle
## Recommended Mitigation Steps
To mitigate this vulnerability, the setReferred and setProtocol functions should be modified to include appropriate checks and restrictions. For example, the setReferred function could be modified to only allow the protocol address to set the _referred variable, and the setProtocol function could be modified to only allow the contract owner to set the protocol variable.
Truncate of values can be avoided
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/Trading.sol#L779
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/Trading.sol#L780
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L38-L40
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L64
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L38-L48


# Vulnerability details

## Truncate of values can be avoided
### Summary
Solidity integer division might truncate. As a result, performing multiplication before division can sometimes avoid loss of precision.
### Details 
In general, this is a problem due to precision. In this case, it also affects assets, that makes me suggest High, as this operations are performed frecuently
### Impact
Less fees, payouts, smaller prices and also size of positions may happen as result of this
### Proof of Concept
Affecting fees and prices:
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/Trading.sol#L779
`_daoFeesPaid = (_positionSize * _fees.daoFees / DIVISION_CONSTANT) * asset.feeMultiplier / DIVISION_CONSTANT`

https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/Trading.sol#L780

`_burnFeesPaid = (_positionSize * _fees.burnFees / DIVISION_CONSTANT) * asset.feeMultiplier / DIVISION_CONSTANT`

https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L38-L40

First is called
`_initPositionSize = _margin * _leverage / 1e18`

And then used to calculate the `_payout`
`_payout = int256(_margin) + int256(_initPositionSize * (1e18 * _currentPrice / _price - 1e18) / 1e18) + accInterest`

https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L64

`_liqPrice = _tradePrice - ((_tradePrice * 1e18 / _leverage) * uint256(int256(_margin) + _accInterest) / _margin) * _liqPercent / 1e10`

Not affecting assets directly:
https://github.com/code-423n4/2022-12-tigris/blob/0cb05a462e78c4470662e9d9a4f9ab587f266bb5/contracts/utils/TradingLibrary.sol#L38-L48

`_initPositionSize = _margin * _leverage / 1e18`

That then is used in:
`_positionSize = _initPositionSize * _currentPrice / _price`

### Tools
Slither + manual analysis


### Recommended Mitigation Steps
Reorder the operations for avoiding lack of precision
For example
`_daoFeesPaid = (_positionSize * _fees.daoFees / DIVISION_CONSTANT) * asset.feeMultiplier / DIVISION_CONSTANT`

would be

`_daoFeesPaid = (_positionSize * _fees.daoFees  * asset.feeMultiplier) / (DIVISION_CONSTANT * DIVISION_CONSTANT)`
Lack of access control
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Referrals.sol#L20-L24


# Vulnerability details

The 'createReferralCode' function in the 'Referrals' contract allows any address to create a referral code. This could potentially lead to spam or misuse of the system.
## Impact
If an attacker is able to create a large number of referral codes, they could potentially overwhelm the system and cause it to become resource-intensive or even unresponsive.
If referral codes are being used for some kind of reward or incentive, allowing any address to create them could lead to abuse or manipulation of the system.

## Proof of Concept
An attacker could write a script to create a large number of referral codes in a short period of time, potentially causing resource exhaustion or performance issues.
An attacker could create referral codes that they are able to use themselves, potentially leading to abuse of the rewards or incentives associated with the codes.

## Tools Used

## Recommended Mitigation Steps
To mitigate this vulnerability, access control should be implemented on the 'createReferralCode' function. This could involve restricting the function to only be callable by certain addresses or requiring that a certain condition be met before a referral code can be created.
Consider adding limits on the number of referral codes that can be created by a single address to prevent spamming or resource exhaustion.
Consider implementing some kind of validation or verification process for referral codes to ensure that they are being used appropriately.
Regularly review and monitor the system to identify and address any potential abuses of referral codes.
User can abuse tight stop losses and high leverage to make risk free trades
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/TradingExtension.sol#L88-L120


# Vulnerability details

## Impact

User can abuse how stop losses are priced to open high leverage trades with huge upside and very little downside

## Proof of Concept

    function limitClose(
        uint _id,
        bool _tp,
        PriceData calldata _priceData,
        bytes calldata _signature
    )
        external
    {
        _checkDelay(_id, false);
        (uint _limitPrice, address _tigAsset) = tradingExtension._limitClose(_id, _tp, _priceData, _signature);
        _closePosition(_id, DIVISION_CONSTANT, _limitPrice, address(0), _tigAsset, true);
    }

    function _limitClose(
        uint _id,
        bool _tp,
        PriceData calldata _priceData,
        bytes calldata _signature
    ) external view returns(uint _limitPrice, address _tigAsset) {
        _checkGas();

        IPosition.Trade memory _trade = position.trades(_id);
        _tigAsset = _trade.tigAsset;
        getVerifiedPrice(_trade.asset, _priceData, _signature, 0);
        uint256 _price = _priceData.price;
        if (_trade.orderType != 0) revert("4"); //IsLimit
        if (_tp) {
            if (_trade.tpPrice == 0) revert("7"); //LimitNotSet
            if (_trade.direction) {
                if (_trade.tpPrice > _price) revert("6"); //LimitNotMet
            } else {
                if (_trade.tpPrice < _price) revert("6"); //LimitNotMet
            }
            _limitPrice = _trade.tpPrice;
        } else {
            if (_trade.slPrice == 0) revert("7"); //LimitNotSet
            if (_trade.direction) {
                if (_trade.slPrice < _price) revert("6"); //LimitNotMet
            } else {
                if (_trade.slPrice > _price) revert("6"); //LimitNotMet
            }
            //@audit stop loss is closed at user specified price NOT market price
            _limitPrice = _trade.slPrice;
        }
    }

When closing a position with a stop loss the user is closed at their SL price rather than the current price of the asset. A user could abuse this in directional markets with high leverage to make nearly risk free trades. A user could open a long with a stop loss that in $0.01 below the current price. If the price tanks immediately on the next update then they will be closed out at their entrance price, only out the fees to open and close their position. If the price goes up then they can make a large gain.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Take profit and stop loss trades should be executed at the current price rather than the price specified by the user:

             if (_trade.tpPrice == 0) revert("7"); //LimitNotSet
            if (_trade.direction) {
                if (_trade.tpPrice > _price) revert("6"); //LimitNotMet
            } else {
                if (_trade.tpPrice < _price) revert("6"); //LimitNotMet
            }
    -       _limitPrice = _trad
`_priceData.price` is not verified in `_limitClose`
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L88-L120


# Vulnerability details

## Impact

In the function `_limitClose` from the `TradingExtension` contract the `_priceData.price` is not verified with the `getVerifiedPrice` function instead its value is directly used, and because the the `getVerifiedPrice` internally calls the function `TradingLibrary.verifyPrice` which is responsible of verifying that the price is signed by a whitelisted node, the `_limitClose` function can potentiely use a price that is not signed by a whitelisted node.

This will cause problems in the `limitClose` function from the `Trade` contract which calls `_limitClose`, and it will affect the closing of the position.

## Proof of Concept

The issue occurs in the `_limitClose` function :

File: contracts/TradingExtension.sol [Line 88-120](https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/TradingExtension.sol#L88-L120)

```
function _limitClose(
    uint _id,
    bool _tp,
    PriceData calldata _priceData,
    bytes calldata _signature
) external view returns(uint _limitPrice, address _tigAsset) {
    _checkGas();
    IPosition.Trade memory _trade = position.trades(_id);
    _tigAsset = _trade.tigAsset;
    
    /* @audit
       _price is not verified and is used directely
    */
    getVerifiedPrice(_trade.asset, _priceData, _signature, 0);
    uint256 _price = _priceData.price;

    if (_trade.orderType != 0) revert("4"); //IsLimit

    if (_tp) {
        if (_trade.tpPrice == 0) revert("7"); //LimitNotSet
        if (_trade.direction) {
            if (_trade.tpPrice > _price) revert("6"); //LimitNotMet
        } else {
            if (_trade.tpPrice < _price) revert("6"); //LimitNotMet
        }
        _limitPrice = _trade.tpPrice;
    } else {
        if (_trade.slPrice == 0) revert("7"); //LimitNotSet
        if (_trade.direction) {
            if (_trade.slPrice < _price) revert("6"); //LimitNotMet
        } else {
            if (_trade.slPrice > _price) revert("6"); //LimitNotMet
        }
        _limitPrice = _trade.slPrice;
    }
}
```

As you can see from the code above the `getVerifiedPrice` function is called but its return value is not used instead the price is used directly from `_priceData.price`.

The `_limitClose` function will be called by `limitClose` function from the `Trading` contract when trying to close a position at pre-set price : 

File: contracts/Trading.sol [Line 565-576](https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Trading.sol#L565-L576)
```
function limitClose(
    uint _id,
    bool _tp,
    PriceData calldata _priceData,
    bytes calldata _signature
)
    external
{
    _checkDelay(_id, false);
    (uint _limitPrice, address _tigAsset) = tradingExtension._limitClose(_id, _tp, _priceData, _signature);
    _closePosition(_id, DIVISION_CONSTANT, _limitPrice, address(0), _tigAsset, true);
}
```

Because the returned price `_limitPrice` from `_lim
[NAZ-H1] Reentrancy From Use of `_safeMint()`
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/main/contracts/Position.sol#L148


# Vulnerability details

## Impact
The `mint()` function is used to mint a new position NFT and is only callable by minter. This function uses `_safeMint()` to mint these position NFTs which has been known in the past to have Reentrancy issues. 

## Proof of Concept
[`The dangers of surprising code`](https://www.paradigm.xyz/2021/08/the-dangers-of-surprising-code) by samczsun is a great article describing this foarm of Reentrancy. If a minter were to be compromised they could use Reentrancy to mint the same position NFT.

## Tools Used
Manual Review

## Recommended Mitigation Steps
Although this is protected with an `onlyMinter()` modifier it should use `reentrancyguard` to prevent this issue.
Unable to release funds deposited through Lock-extendLock
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L89-L91
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L103


# Vulnerability details

## Impact

Users depositing tig assets to the bondNFT through the Lock contract could find themselves unable to release their funds.
The only explanation the user would receive is an "Arithmetic over/underflow" error.
This issue greatly deteriorates the user experience and usability of the platform. 

Issue arises from the Lock-extendLock function not updating the totalLocked value for that particular tig asset. [source](https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L89-L91)
This leads to Lock-release underflowing when the user tries to release their funds after the duration of the lock has passed. [source](https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L103)

## Proof of Concept
Foundry project directory which includes the failing test: https://github.com/sha256yan/tig
Failing test is located in test/Lock.t.sol [permalink](https://github.com/sha256yan/tig/blob/ae498e5047d2c1270761cdb00bce391685e8533f/test/Lock.t.sol#L18-L36)

## Tools Used

Foundry-rs

## Recommended Mitigation Steps

Remove the totalLocked mapping all-together, or keep it and update it in extendLock().
Extending period in `Lock` contract will block user funds
Audit: 2022-12-tigris-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L84-L92
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L73
https://github.com/code-423n4/2022-12-tigris/blob/588c84b7bb354d20cbca6034544c4faa46e6a80e/contracts/Lock.sol#L103


# Vulnerability details

## Impact
Extending lock will block users' funds.

Contract: `Lock.sol`

## Proof of Concept
Locking tokens with function `lock(...)` will update mapping mapping `totalLocked` for given asset with value of `amount`, here: `totalLocked[_asset] += _amount`. However, when extending lock with function `extendLock(...)` the mapping `totalLocked` is not updated. This blocks user funds, since to relea tokens with `release(...)` function, the released amount is subtracted in mapping `totalLocked`. This makes every amount passed in `extendLock(...)` not be able to release.
This may also allow malicious user to block other users' funds by locking tokens, extending lock with large amount and then releasing - other users will not be able to release their funds.

## Tools Used
Manual review.

## Recommended Mitigation Steps
Consider updating mapping `totalLocked` on extending lock.