xanoutas/solidity-security-findings huggingface dataset:
## [MEDIUM-1] SafeTransfer should be used in place of transfer
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/utils/UFragments.sol#L185
https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/utils/UFragments.sol#L105
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/utils/UFragments.sol#L252
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/utils/UFragments.sol#L233


# Vulnerability details

## Impact
SafeTransfer should be used in place of Transfer for Solidity contracts to ensure robust security and error handling. Unlike the basic Transfer function, SafeTransfer incorporates safeguards against potential smart contract vulnerabilities, such as reentrancy attacks and unexpected token loss. By automatically validating the recipient's ability to receive tokens and reverting transactions in case of failures,


## Assessed type

Other
Liquidation frontrunning can prevent debt repayment upon unpausing
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L584


# Vulnerability details

## Impact
The protocol can be unpaused by privileged accounts, yes. But when this unpause happens the liquidators can frontrun and liquidate user positions before those users get a chance to make their positions healthy to avoid liquidation.
## Proof of Concept
The Pauser of [`VaultController`](https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L23C29-L23C37) can disable different functions of the contract, including repayments and Liquidations. As a result, when borrowers can't repay when they want to, and liquidator can liquidate any unhealthy positions or bad debt immediately after these functions are unpaused (front-running or liquidation mev bots)and borrowers won't be able to protect against that by repaying their debts. Thus, borrowers will be forced to lose their collateral in the vault.


## Tools Used
Manual observation

## Recommended Mitigation Steps
Consider removing the unpause from the repayment function, so that borrowers can repay their loans when they dim fit or when market conditions are favourable, to avoid liquidations


## Assessed type

DoS
the castvotebysig is not preventing users to vote proposalid 0 
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/179384321c36b669f48bc0485bbc1f807fba8fac/core/solidity/contracts/governance/GovernorCharlie.sol#L507-L523


# Vulnerability details

## Impact
the castvotebysig is not preventing users to vote proposalid 0 and it will cause unwanted behavior.
## Proof of Concept
instances: 
https://github.com/code-423n4/2023-07-amphora/blob/179384321c36b669f48bc0485bbc1f807fba8fac/core/solidity/contracts/governance/GovernorCharlie.sol#L507-L523
```solidity 
 function castVoteBySig(uint256 _proposalId, uint8 _support, uint8 _v, bytes32 _r, bytes32 _s) external override {
    bytes32 _domainSeparator =
      keccak256(abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(NAME)), _getChainIdInternal(), address(this)));
    bytes32 _structHash = keccak256(abi.encode(BALLOT_TYPEHASH, _proposalId, _support));

    bytes32 _digest = keccak256(abi.encodePacked('\x19\x01', _domainSeparator, _structHash));

    if (uint256(_s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
      revert GovernorCharlie_InvalidSignature();
    }
    address _signatory = ecrecover(_digest, _v, _r, _s);
    if (_signatory == address(0)) revert GovernorCharlie_InvalidSignature();
    uint96 _numberOfVotes = _castVoteInternal(_signatory, _proposalId, _support);
    emit VoteCastIndexed(_signatory, _proposalId, _support, _numberOfVotes, '');
    emit VoteCast(_signatory, _proposalId, _support, _numberOfVotes, '');
  }

```

## Tools Used
vscode
## Recommended Mitigation Steps
revert on voting for proposalid 0 


## Assessed type

Governance
## [M‑02] _safeMint() should be used rather than _mint() wherever possible
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/core/WUSDA.sol#L216


# Vulnerability details

## Impact
`_mint()` is discouraged in favor of `_safeMint()` which ensures that the recipient is either an EOA or implements `IERC721Receiver`.
## Proof of Concept
 Both [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/d4d8d2ed9798cc3383912a23b5e8d5cb602f7d4b/contracts/token/ERC721/ERC721.sol#L238-L250) and [solmate](https://github.com/Rari-Capital/solmate/blob/4eaf6b68202e36f67cab379768ac6be304c8ebde/src/tokens/ERC721.sol#L180) have versions of this function. 

## Tools Used

## Recommended Mitigation Steps
Use `_safeMint()`


## Assessed type

Other
## [M-01] DefaultAccount#fallback lack payable
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/main/core/solidity/contracts/periphery/oracles/EthSafeStableCurveOracle.sol#L54


# Vulnerability details

## Impact
fallback lack `payable`,will lead to differences from the mainnet, and many existing protocols may not work

## Proof of Concept
https://www.geeksforgeeks.org/solidity-fall-back-function/

## Tools Used

## Recommended Mitigation Steps
should marked as payable


## Assessed type

Payable
Vault.claimRewards can break if Convex changes the operator
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/Vault.sol#L183


# Vulnerability details

## Impact
`Vault.claimRewards` assumes that CVX will always get minted to the Vault (if there is a CRV reward). If CVX does not get minted, the claim will fail, preventing payout of CRV and extra rewards. Looking at the Convex code there can be the case where the operator has changed, causing no mint to happen.

## Proof of Concept
The function `Vault.claimRewards` calculates the CVX reward that is expected, which is then meant to be transferred to AMPHClaimer and the minter:

```js
...
 _totalCvxReward += _calculateCVXReward(_crvReward);
...
// Claim AMPH tokens depending on how much CRV and CVX was claimed
_amphClaimer.claimAmph(this.id(), _totalCvxReward, _totalCrvReward, _msgSender());
...
if (_totalCvxReward > 0) CVX.transfer(_msgSender(), _totalCvxReward);
```

The `Cvx` contract which performs the mint contains the following logic:

```js
function mint(address _to, uint256 _amount) external {
    if(msg.sender != operator){
        //dont error just return. if a shutdown happens, rewards on old system
        //can still be claimed, just wont mint cvx
        return;
    }
```

The `operator` is the `Booster` contract which is called by `BaseRewardPool` which again is called by `Vault.claimRewards`. As can be seen in the snippet, the Convex protocol enables a shutdown case that wont break the `BaseRewardPool`, however the `Vault` implementation has not taken that case into consideration.

Severity deemed to be medium, due to high impact but special requirement.

## Tools Used

Manual Review

## Recommended Mitigation Steps

Check the CVX balance of the vault before and after the claim to assert that the correct CVX amount has been minted.


## Assessed type

Other
_amountToSolvency calculation is wrong
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L831-L833
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L846-L851
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L866-L888
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L768-L810


# Vulnerability details

## Impact
Vault will remain insolvent after liquidation, because ```_amountToSolvency``` that is being calculated is not sufficient enough to keep the vault solvent after liquidation has been concluded.

## Proof of Concept
```
 // calculate the amount to liquidate and the 'bad fill price' using liquidationMath
    // see _liquidationMath for more detailed explaination of the math
    (uint256 _tokenAmount, uint256 _badFillPrice) = _liquidationMath(_id, _assetAddress, _tokensToLiquidate);
    // set _tokensToLiquidate to this calculated amount if the function does not fail
    if (_tokenAmount > 0) _tokensToLiquidate = _tokenAmount;
    // the USDA to repurchase is equal to the bad fill price multiplied by the amount of tokens to liquidate
```

The statement in the snippet below is not true. The reason is after the liquidation of that amount of token based on the protocol calculation, the vault will still be insolvent. Instance will be explained in detail;
```
// the maximum amount of tokens to liquidate is the amount that will bring the vault to solvency
    // divided by the denominator
    uint256 _maxTokensToLiquidate = (_usdaToSolvency * 1e18) / _denominator;
```
Follow a scenario where a vault with $100 worth of asset decides to take a loan with an 80% ltv.

1. Loan of $80(max obtainable based on 80% ltv) worth was obtained by the vault.

2. Asset dropped to $90 based on market condition, making the vault insolvent, as the current loan is now above the borrowPower of the vault.

3. A liquidator calls the ```liquidateVault``` method to liquidate the vault.

```
  function _amountToSolvency(uint96 _id) internal returns (uint256 _usdaToSolvency) {
    _usdaToSolvency = _vaultLiability(_id) - _getVaultBorrowingPower(_getVault(_id));
  }
```

This above snippet is where the problem lies, in this case, _vaultLiability(_id) is $80, while the current borowPower based on $90 asset value and 80% ltv, is $72.

Following the usdaToSolvency calculation it will be ```80 - 72 = 8```

Following the liquidation incentive (5% in this case), the liquidator will pay $8 debt to liquidate $8.4 worth of asset.

After the liquidation that amount, the vault will still be insolvent because debt will be ```80 - 8 = 72```, while asset will be reduced to ```90 - 8.4 = 81.6```

Following the requirement for solvency that current lown
Nonces are not used in the signature checks
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/179384321c36b669f48bc0485bbc1f807fba8fac/core/solidity/contracts/governance/GovernorCharlie.sol#L337


# Vulnerability details

## Impact
in the contract `GovernorCharlie.sol` in function `executeTransaction` Nonces are not used in the signature

A nonce can prevent an old value from being used when a new value exists. Without one, two transactions submitted in one order, can appear in a block in a different order


## Proof of Concept
here is instance: 
https://github.com/code-423n4/2023-07-amphora/blob/179384321c36b669f48bc0485bbc1f807fba8fac/core/solidity/contracts/governance/GovernorCharlie.sol#L337

```solidity 
 function executeTransaction(
    address _target,
    uint256 _value,
    string memory _signature,
    bytes memory _data,
    uint256 _eta
  ) external payable override {
    if (msg.sender != address(this)) revert GovernorCharlie_NotGovernorCharlie();

    bytes32 _txHash = keccak256(abi.encode(_target, _value, _signature, _data, _eta));
    if (!queuedTransactions[_txHash]) revert GovernorCharlie_ProposalNotQueued();
    if (_getBlockTimestamp() < _eta) revert GovernorCharlie_TimelockNotReached();
    if (_getBlockTimestamp() > _eta + GRACE_PERIOD) revert GovernorCharlie_TransactionStale();

    queuedTransactions[_txHash] = false;

    bytes memory _callData;

    if (bytes(_signature).length == 0) _callData = _data;
    else _callData = abi.encodePacked(bytes4(keccak256(bytes(_signature))), _data);

    // solhint-disable-next-line avoid-low-level-calls
    (bool _success, /*bytes memory returnData*/ ) = _target.call{value: _value}(_callData);
    if (!_success) revert GovernorCharlie_TransactionReverted();

    emit ExecuteTransaction(_txHash, _target, _value, _signature, _data, _eta);
  }
```
## Tools Used
manually/ vs code
## Recommended Mitigation Steps
Include a nonce in what is signed

```solidity
+    bytes32 _txHash = keccak256(abi.encode(_target, _value, _signature, _data, _eta, nonce));

```

instead of 
```solidity
 bytes32 _txHash = keccak256(abi.encode(_target, _value, _signature, _data, _eta));

```


## Assessed type

Governance
The missing salt/proposalId in the hash construction for queuedTransactions leads to the possible collision of records in the queue
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L261
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L299
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L337
https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L405


# Vulnerability details

The missing salt/proposalId in the hash construction for queuedTransactions leads to the impossibility of performing the same operations with the same eta

## Impact

No id/salt/proposalId is used to create an ID for `queuedTransactions`:
```с
        queuedTransactions[keccak256(
          abi.encode(
            _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _eta
          )
```

Еhe problem is mitigated by the presence of _eta and the presence of the need for voting, but this only reduces the chances of its occurrence. But since _eta is not unique, this problem is unlikely but does not go away and provides opportunities for manipulation

Which leads to the following situations:
1. Impossibility of executing two identical calls within one offer
2. In the case of hitting a queue call transaction, for different offers that have the same transaction, it will lead to the failure of a later queue call
3. The possibility of blocking the sending of transactions to the queue of the selected offer by duplicating the offer and sending queue() your own offer before the one you want to block
4. When proposalTimelockDelay is changed, the chance of a hash collision for queuedTransactions appears again
    
## Proof of Concept
Instances:
* https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L261
* https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L299C1-L300C1
* https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L337
* https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L405
* 
```c
File: contracts/governance/GovernorCharlie.sol

function queue(uint256 _proposalId) 

261:  queuedTransactions[keccak256(
          abi.encode(
            _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _eta
          )
        )]

function _queueTransaction(

299:  _txHash = keccak256(abi.encode(_target, _value, _signature, _data, _eta));
      queuedTransactions[_txHa
Gas Limit Vulnerability in vaultSummaries Function Due to Large Number of enabledTokens
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/VaultController.sol#L988-L1012


# Vulnerability details

## Impact
The vaultSummaries function in the provided Solidity code has a potential issue that may lead to reverts or out-of-gas errors when there are a large number of enabledTokens. The function is designed to return the status of a range of vaults, including their token balances. However, if the number of enabledTokens is excessively high, the gas cost for fetching and storing the token balances in the loop might exceed the maximum gas limit, causing the function to fail. This can result in failed transactions and loss of user funds if not handled properly.


## Proof of Concept
```solidity
function vaultSummaries(uint96 _start, uint96 _stop) public view returns (VaultSummary[] memory _vaultSummaries) {
  if (_stop > vaultsMinted) _stop = vaultsMinted;
  _vaultSummaries = new VaultSummary[](_stop - _start + 1);
  for (uint96 _i = _start; _i <= _stop;) {
    IVault _vault = _getVault(_i);
    uint256[] memory _tokenBalances = new uint256[](enabledTokens.length);

    for (uint256 _j; _j < enabledTokens.length;) {
      _tokenBalances[_j] = _vault.balances(enabledTokens[_j]);

      unchecked {
        ++_j;
      }
    }
    _vaultSummaries[_i - _start] =
      VaultSummary(_i, _peekVaultBorrowingPower(_vault), this.vaultLiability(_i), enabledTokens, _tokenBalances);

    unchecked {
      ++_i;
    }
  }
}
```

In the above function, if there are a large number of enabledTokens, the inner loop that populates the _tokenBalances array for each vault might result in excessive gas consumption. When the total gas cost of the function exceeds the maximum gas limit allowed for a single transaction, the function execution will be reverted.


## Tools Used
Manual review

## Recommended Mitigation Steps

Optimize the vaultSummaries function to process a smaller subset of enabledTokens at a time, reducing the gas cost of the operation.


## Assessed type

Other
the '_calculate' function in AMPHClaimer.sol may have rounding error vulnerability due to the use of floating-point arithmetic with 1e6 precision
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#L222


# Vulnerability details

## Impact
The ‘_calculate’ function in the AMPHClaimer.sol contract may have rounding error vulnerabilities due to the use of floating-point arithmetic with 1e6 precision.

Rounding errors occur when performing arithmetic operations involving floating-point numbers. In the ‘_calculate’ function, some calculations involve multiplying and then dividing values by 1e6, which introduces rounding errors.

In this code:
     _amphForThisTurn = ((_rate * _tempAmountReceived) / 1e12) / 1e6; // 1e6


## Proof of Concept
In the code above, the ‘_rate’ is represented with 1e6 precision (6 decimal places), and ‘_tempAmountReceived’ has 1e18 precision (18 decimal places). The division by 1e12 is to prevent an intermediate overflow, but it introduces rounding errors. Similarly, the final division by 1e6 converts the result to 1e18 precision, again introducing rounding errors and also unintended results due to overflow or underflow.

The rounding errors could lead to inaccuracies in the calculated amphForThisTurn, amphToMint, and potentially the overall amount of AMPH tokens minted.

Contract name: AMPHClaimer.sol

Code link: https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/core/AMPHClaimer.sol#222

Code line:
     _amphForThisTurn = ((_rate * _tempAmountReceived) / 1e12) / 1e6; // 1e6


## Tools Used
Manual review

## Recommended Mitigation Steps
To mitigate rounding errors, consider using integer arithmetic instead of floating-point arithmetic. You could convert the calculations to integer operations by multiplying the values with the appropriate factors to move the decimal points to an integer precision (e.g., 1e18). This approach would reduce the chances of encountering rounding errors.
This way:

function calculateAmount(uint256 inputValue) internal pure returns (uint256) {
    // Perform fixed-point arithmetic using the precision constant
    uint256 result = multiply(inputValue, 123456789); // Multiply by a constant
    result = divide(result, 987654321); // Divide by another constant
    return result;
}

Also, using fixed-point arithmetic with integer values, you can avoid rounding errors and achieve precise calculations in your smart contracts.
This way:

uint256 internal constant PRECISION = 1e18;

 amphForThisTurn = (tempAmountReceived * rate) / PRECISION;
 The ‘PRECISION’ constant with a value of 1e18 is introduced, representing 18 decimal places. All calculations involving rates and amounts have been adapted to use fixed-point arithmetic by multiplying and dividing by ‘PRECISION.’ 




## Assessed type

Decimal
Everyone can cancel each other proposal
Audit: 2023-07-amphora-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-07-amphora/blob/daae020331404647c661ab534d20093c875483e1/core/solidity/contracts/governance/GovernorCharlie.sol#L361-L390


# Vulnerability details

## Impact
cancel() function in overnorCharlie.sol have the wrong check for caller. basically if msg.sender is not the proposer, can cancel proposal. So everyone can cancel each other proposal.

## Proof of Concept
This is cancel() function:
```solidity
function cancel(uint256 _proposalId) external override {
    if (state(_proposalId) == ProposalState.Executed) revert GovernorCharlie_ProposalAlreadyExecuted();

    Proposal storage _proposal = proposals[_proposalId];

    // Proposer can cancel
    if (msg.sender != _proposal.proposer) {
      // Whitelisted proposers can't be canceled for falling below proposal threshold
      if (isWhitelisted(_proposal.proposer)) {
        if (
          (amph.getPriorVotes(_proposal.proposer, (block.number - 1)) >= proposalThreshold)
            || msg.sender != whitelistGuardian
        ) revert GovernorCharlie_WhitelistedProposer();
      } else {
        if ((amph.getPriorVotes(_proposal.proposer, (block.number - 1)) >= proposalThreshold)) {
          revert GovernorCharlie_ProposalAboveThreshold();
        }
      }
    }

    _proposal.canceled = true;
    for (uint256 _i = 0; _i < _proposal.targets.length; _i++) {
      _cancelTransaction(
        _proposal.targets[_i], _proposal.values[_i], _proposal.signatures[_i], _proposal.calldatas[_i], _proposal.eta
      );
    }

    emit ProposalCanceledIndexed(_proposalId);
    emit ProposalCanceled(_proposalId);
  }
```
logic is function checks ```msg.sender != _proposal.proposer``` but doesn't revert at all and just checks things like shouldn't be whitelisted proposal or not above threshold. So users who call this function with another user proposal id, be able to cancel.
## Tools Used
Manual Review
## Recommended Mitigation Steps
```solidity
// Proposer can cancel
    if (msg.sender != _proposal.proposer) {
      // Whitelisted proposers can't be canceled for falling below proposal threshold
      if (isWhitelisted(_proposal.proposer)) {
        if (
          (amph.getPriorVotes(_proposal.proposer, (block.number - 1)) >= proposalThreshold)
            || msg.sender != whitelistGuardian
        ) revert GovernorCharlie_WhitelistedProposer();
      } else {
        if ((amph.getPriorVotes(_proposal.proposer, (block.number - 1)) >= proposalThreshold)) {
          revert GovernorCharlie_ProposalAboveThreshold();
        }
      }
         + revert GovernorCharlie_CallerIsNotProposer();
    }
```
Consider this line for avoid this issue:
```revert GovernorCharlie_CallerIsNotProposer();```


## Assessed type

Other