Quantstamp reviewed Secured Finance on 12 Dec 2023: 45 findings, 0 critical; 23 marked fixed, 17 acknowledged, 5 open.
Report hosted on certificate.quantstamp.com.
Trustblock does not review code.
Statuses are the security firm’s own, from its report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 4 |
| Medium | 1 | 3 | 6 |
| Low | 4 | 14 | 13 |
Several functions in the contract `TokenVault` only accept to work for currencies registered in the mapping `tokenAddresses`, based on the modifier `onlyRegisteredCurrency()`. The owner of the contract can register new currencies via the function `registerCurrency()`. Only currencies with an existing identifier registered in the contract `CurrencyController` can be registered. However, it is possible to unregister a currency by setting it to the `address(0)`. This can lead to: 1. The owner can call this function with the wrong address, halting the deposit and withdrawal system of the protocol. All transfer calls to this wrong address will revert. 2. The address passed can be different from the one listed in `CurrencyController`. 3. Duplicated `CurrencyRegistered` events.
1. The function `MixinAddressResolver.buildCache()` can be called by anyone to update the addresses associated with the required contract names used by the contract. An event `CacheUpdated` is emitted for each required contract, whether it is updated or not. This could result in more events emitted than required. 2. The function `MixinWallet.executeTransactions()` can be called by the owner of the contract. It results in the emission of an event `TransactionsExecuted` even if no transaction has been executed.
It is important to validate inputs, even if they only come from trusted addresses, to avoid human error: 1. `BeaconProxyController`: verify the value of `LendingMarket.MINIMUM_RELIABLE_AMOUNT_IN_BASE_CURRENCY` when the contract becomes the implementation contract of the beacon. 2. `LendingMarketOperationLogic.createOrderBook()`: verify that the duration between `_preOpeningDate` and `_openingDate` is short enough to avoid locking tokens by placing pre-orders. 3. qs-badge-fixed `MixinLiquidationConfiguration._updateLiquidationConfiguration()`: verify that the value of `_liquidationThresholdRate` is higher than `Constants.PCT_DIGIT` to prevent the under-collateralization of the protocol. 4. qs-badge-fixed `LendingMarketController.initializeLendingMarket()`: verify the correctness of the values used as parameters.
The function `importAddresses()` can be called by the owner of the contract to update the mapping of a list of addresses with new names. Such action will also result in the update of the storage list `addressCaches`. However, this function can be called several times and maintain previous mapping associations valid. For instance: 1. Owner calls the function with `_names = ["A", "B"]` and `_addresses = [0x01,0x02]`. The mapping `addresses` is updated accordingly and `addressCaches` takes the value of `_addresses`. 2. Owner calls again the function with `_names = ["A"]` and `_addresses = [0x03]`. The mapping `addresses` is updated accordingly and `addressCaches` takes the value of `_addresses`. 3. After the operation: * `addressCaches` is `[0x03]`; * `addresses["A"] = 0x03`'; * `addresses["B"] = 0x02`'; This could lead to storage inconsistencies between what is stored in the mapping `addresses` and the list `addressCaches` and ultimately to broken assumptions about the system if the function `importAddresses()` is called with inconsistent parameters. Also, duplicate items are possible in both lists (`_names` and `_addresses`). Having duplicates could result in unexpected mapping associations and duplicates in the list `addressCaches`.
1. The function `FullMath.mulDiv()` overflows when `a * b > type(uint256).max`. Note that an implementation of the same algorithm by Open Zeppelin uses an `unchecked` block for the whole function: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/769071d47366addc20e160bce53a6dd480d5f89d/contracts/utils/math/Math.sol#L124. 2. The function `RoundingInt256.div()` overflows when `a x 10 > type(int256).max` and underflows when `a x 10 < type(int256).min`. 3. The function `RoundingUint256.div()` overflows when `a x 10 > type(uint256).max`. However, we assessed that it was unlikely to use these functions with such values for `a` and `b`.
The report names a repository or files. Open the report to see its scope.
Repository and files the report names (70)
236 projects reviewed · 332 reports · latest Oct 2026
See Quantstamp’s auditsSomething wrong on this page? A missing report, a wrong date, a finding that was fixed since. Tell us and we check it against its source.
Tell us