As of 23 Oct 2026, Byte Masons - Reliquary has 2 audit reports by 1 security firm on Trustblock; the latest is by CertiK, dated 20 Nov 2022. Those reports list no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Granary v1 | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
| Bytemasons - Multistrategy Vault | Security firm: CertiK | Date: | Scope: Files named in the report | No open critical findings | Open · skynet.certik.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 2 | 2 | 0 |
| Medium | 0 | 3 | 0 |
| Low | 26 | 0 | 9 |
In the contract `ATokensAndRatesHelper`, the role `owner` has authority over the following functions: - function initDeployment(), to initialize deployment, and set reserve interest rate strategy. - function configureReserves(), to config reserves, set the reserve collateral parameters, the reserve borrowing parameters, and the reserve factor. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `StableAndVariableTokensHelper`, the role `owner` has authority over the following functions: - function initDeployment(), to initialize deployment, deploy stable debt token and variable debt token. - function setOracleBorrowRates(), to set borrow rates of assets. - function setOracleOwnership(), to transfer the ownership of the contract `LendingRateOracle` to the `admin` address. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `BaseImmutableAdminUpgradeabilityProxy`, the role `ADMIN` has authority over the following functions: - function upgradeTo(), to upgrade the backing implementation of the proxy. - function upgradeToAndCall(), to upgrade the backing implementation of the proxy and call a function. Any compromise to the `ADMIN` account may allow a hacker to take advantage of this authority. In the contract `GranaryRewardsVault`, the role `owner` has authority over the following functions: - function emergencyEtherTransfer(), to transfer all amount of ETHs in the contract `GranaryRewardsVault` to any address. - function emergencyTokenTransfer(), to transfer any tokens in the contract `GranaryRewardsVault` to any address. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `GranaryRewardsVault`, the role `poolAdmin` has authority over the following functions: - function approveIncentivesController(), to sets `value` as the allowance of `INCENTIVES_CONTROLLER` over the contract `GranaryRewardsVault's` tokens. Any compromise to the `poolAdmin` account may allow a hacker to take advantage of this authority.
Open the reportIn the contract `Rewarder`, the role `owner` has authority over the following functions: - function setRewardsVault(), to the reward vault address for the reward. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `RewardsController`, the role `owner` has authority over the following functions: - function setClaimer(), to authorize the caller to claim the rewards of the user. - function configureAssets(), to configure the assets for a specific emission. Any compromise to the `_owner` account may allow a hacker to take advantage of this authority. In the contract `RewardsDistributor`, the role `owner` has authority over the following functions: - function setDistributionEnd(), to the end timestamp of distributing rewards. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `Timelock`, the role `admin` has authority over the following functions: - function queueTransaction(), to add a transaction to the execution queue. - function cancelTransaction(), to cancel a transaction. - function executeTransaction(), to execute a transaction. Any compromise to the `admin` account may allow a hacker to take advantage of this authority. In the contract `Ownable`, the role `owner` has authority over the following functions: - function renounceOwnership(), to renounce the ownership and leave the contract without the owner. - function transferOwnership(), to transfer the ownership of the contract to a new account. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `GranaryTreasury`, the role `owner` has authority over the following functions: - function transferToMultisig(), to any tokens in the contract `GranaryTreasury` to the `multisig` address. - function setMultisig(), to change the address of `multisig`. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `GranaryTreasury`, the role `poolAdmin` has authority over the following functions: - function setTreasury(), to set the new treasury address. Any compromise to the `poolAdmin` account may allow a hacker to take advantage of this authority. In the contract `Ownable`, the role `owner` has authority over the following functions: - function renounceOwnership(), to renounce the ownership and leave the contract without the owner. - function transferOwnership(), to transfer the ownership of the contract to a new account. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `AaveOracle`, the role `owner` has authority over the following functions: - function setAssetSources(), to set or replace sources of assets. - function setFallbackOracle(), to set the address of `fallbackOracle`. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `WETHGateway`, the role `owner` has authority over the following functions: - function authorizeLendingPool(), to authorize the `LendingPool`. - function emergencyTokenTransfer(), to transfer any tokens in the contract `WETHGateway` to any address. - function emergencyEtherTransfer(), to transfer all ETHs in the contract `WETHGateway` to any address. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `LendingPoolAddressesProvider`, the role `owner` has authority over the following functions: - function setMarketId(), to set the market which this `LendingPoolAddressesProvider` represents. - function setAddressAsProxy(), to update the implementation of a proxy registered with certain `id`. - function setAddress(), to set an address for an id replacing the address saved in the addresses map. - function setLendingPoolImpl(), to set the implementation of the `LendingPool`. - function setLendingPoolConfiguratorImpl(), to update the implementation of the `LendingPoolConfigurator`. - function setLendingPoolCollateralManager(), to update the address of the `LendingPoolCollateralManager`. - function setPoolAdmin(), to set the pool admin. - function setEmergencyAdmin(), to set the emergency admin. - function setPriceOracle(), to set the price oracle. - function setLendingRateOracle(), to set the lending rate oracle. Any compromise to the `owner` account may allow a hacker to take advantage of this authority. In the contract `LendingPoolAddressesProviderRegistry`, the role `owner` has authority over the following functions: - function registerAddressesProvider(), to register an addresses provider. - function unregisterAddressesProvider(), to removes a LendingPoolAddressesProvider from the list of registered addresses provider. Any compromise to the `owner` account may allow a hacker to take advantage of this authority.
Open the reportBoolean constants can be used directly and do not need to be compared to true or false.
Open the reportWhen transferring standard ERC20 deflationary tokens, the input amount may not be equal to the received amount due to the charged transaction fee. As a result, an inconsistency in the amount will occur and the transaction may fail due to the validation checks.
Open the reportThere should always be events emitted in the sensitive functions that are controlled by centralization roles.
Open the reportThe **require** can be used to check for conditions and throw an exception if the condition is not met. It is better to provide a string message containing details about the error that will be passed back to the caller.
Open the reportAddresses should be checked before assignment or external call to make sure they are not zero addresses. ```solidity=25 (bool success, ) = _logic.delegatecall(_data); ``` - `_logic` is not zero-checked before being used. --- ```solidity=43 pool = _pool; ``` - `_pool` is not zero-checked before being used. --- ```solidity=44 addressesProvider = _addressesProvider; ``` - `_addressesProvider` is not zero-checked before being used. --- ```solidity=45 poolConfigurator = _poolConfigurator; ``` - `_poolConfigurator` is not zero-checked before being used. --- ```solidity=28 _owner = msgSender; ``` - `msgSender` is not zero-checked before being used. --- ```solidity=46 BASE_CURRENCY = baseCurrency; ``` - `baseCurrency` is not zero-checked before being used. --- ```solidity=435 (bool success, bytes memory result) = collateralManager.delegatecall( abi.encodeWithSignature( 'liquidationCall(address,address,address,uint256,bool)', collateralAsset, debtAsset, user, debtToCover, receiveAToken ) ); ``` - `collateralAsset` is not zero-checked before being used. --- ```solidity=20 ADMIN = admin; ``` - `admin` is not zero-checked before being used. --- ```solidity=69 (bool success, ) = newImplementation.delegatecall(data); ``` - `newImplementation` is not zero-checked before being used. --- ```solidity=96 _treasury = treasury; ``` - `treasury` is not zero-checked before being used. --- ```solidity=97 _underlyingAsset = underlyingAsset; ``` - `underlyingAsset` is not zero-checked before being used. --- ```solidity=55 _underlyingAsset = underlyingAsset; ``` - `underlyingAsset` is not zero-checked before being used. --- ```solidity=49 _underlyingAsset = underlyingAsset; ``` - `underlyingAsset` is not zero-checked before being used. --- ```solidity=30 admin = admin_; ``` - `admin_` is not zero-checked before being used. --- ```solidity=55 pendingAdmin = pendingAdmin_; ``` - `pendingAdmin_` is not zero-checked before being used. --- ```solidity=99 (bool success, bytes memory returnData) = target.call.value(value)(callData); ``` - `target` is not zero-checked before being used. --- ```solidity=54 currentTreasury = newTreasury; ``` - `newTreasury` is not zero-checked before being used. --- ```solidity=58 multisig = newMultisig; ``` - `newMultisig` is not zero-checked before being used. --- ```solidity=25 INCENTIVES_CONTROLLER = incentivesController; ``` - `incentivesController` is not zero-checked before being used. --- ```solidity=27 REWARD_TOKEN = rewardToken; ``` - `rewardToken` is not zero-checked before being used. --- ```solidity=35 (bool success, ) = to.call{value: amount}(new bytes(0)); ``` - `to` is not zero-checked before being used.
Open the reportThe asset `StableDebtToken` is not supported since the contract `StableDebtToken` does not inherit the interface `IScaledBalanceToken` and not implement the functions `scaledTotalSupply()` and `getScaledUserBalanceAndSupply()`. ```solidity=33 for (uint256 i = 0; i < config.length; i++) { config[i].totalSupply = IScaledBalanceToken(config[i].asset).scaledTotalSupply(); } ``` ```solidity=115 for (uint256 i = 0; i < assets.length; i++) { userState[i].underlyingAsset = assets[i]; (userState[i].userBalance, userState[i].totalSupply) = IScaledBalanceToken(assets[i]) .getScaledUserBalanceAndSupply(user); } ```
Open the reportThe `permit` function performs the operation of deriving signer address from the signature values of `v`, `r` and `s`. The state variable `DOMAIN_SEPARATOR` that is used to calculate hash has a value of `chainid` that is derived only once in the constructor, which does not change after contract deployment. The issue arises in the event of fork when the cross-chain replay attacks can be executed. The attack scenario can be thought of as if a fork of Ethereum happens and two different networks have id of for example `1` and `9`. The `chainid` coded in `DOMAIN_SEPARATOR` will be the same on contracts residing in both of the forks. If the chainid `1` is stored in the contract then the `permit` transaction signed for chainid `1` will be executable on both of the forks.
Open the reportMalicious hackers may observe the pending transaction which will execute the `initialize` function and launch a similar transaction with the hacker's address and set variables of the contract.
Open the reportSafeMath from OpenZeppelin is not used in contracts which makes them possible for overflow/underflow and will lead to an inaccurate calculation result.
Open the reportThe return value of the transfer()/transferFrom() call is not checked. ```solidity=69 aWETH.transferFrom(msg.sender, address(this), amountToWithdraw); ``` --- ```solidity=156 IERC20(token).transfer(to, amount); ``` --- ```solidity=50 IERC20(asset).transfer(multisig, value); ``` --- ```solidity=44 IERC20(token).transfer(to, amount); ```
Open the reportSince transfer throws an exception on failure and cannot call back here. The reason for reverting is that there is no safe way to continue execution because an expected effect did not occur. Because we want to keep the atomicity of transactions, the safest action is to revert all changes and make the whole transaction (or at least call) without effect.
Open the reportWhen calling the function `transferRewards()`, the source of the `reward` is unknown for how the contract will guarantee user rewards, as no automatic token transfer is made.
Open the reportThe return value of an external call is not stored in a local or state variable. ```solidity=149 try oracle.BASE_CURRENCY_UNIT() returns (uint256 baseCurrencyUnit) { if (ETH_CURRENCY_UNIT == baseCurrencyUnit) { baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT; baseCurrencyInfo .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator .latestAnswer(); } else { baseCurrencyInfo.marketReferenceCurrencyUnit = baseCurrencyUnit; baseCurrencyInfo.marketReferenceCurrencyPriceInUsd = int256(baseCurrencyUnit); } } catch ( bytes memory /*lowLevelData*/ ) { baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT; baseCurrencyInfo .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator .latestAnswer(); } ``` --- ```solidity=149 try oracle.BASE_CURRENCY_UNIT() returns (uint256 baseCurrencyUnit) { if (ETH_CURRENCY_UNIT == baseCurrencyUnit) { baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT; baseCurrencyInfo .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator .latestAnswer(); } else { baseCurrencyInfo.marketReferenceCurrencyUnit = baseCurrencyUnit; baseCurrencyInfo.marketReferenceCurrencyPriceInUsd = int256(baseCurrencyUnit); } } catch ( bytes memory /*lowLevelData*/ ) { baseCurrencyInfo.marketReferenceCurrencyUnit = ETH_CURRENCY_UNIT; baseCurrencyInfo .marketReferenceCurrencyPriceInUsd = marketReferenceCurrencyPriceInUsdProxyAggregator .latestAnswer(); } ``` --- ```solidity=31 WETH.approve(lendingPool, uint256(-1)); ``` --- ```solidity=70 ILendingPool(lendingPool).withdraw(address(WETH), amountToWithdraw, address(this)); ``` --- ```solidity=104 ILendingPool(lendingPool).repay(address(WETH), msg.value, rateMode, onBehalfOf); ``` --- ```solidity=316 IVariableDebtToken(reserve.variableDebtTokenAddress).mint( msg.sender, msg.sender, stableDebt, reserve.variableBorrowIndex ); ``` --- ```solidity=328 IStableDebtToken(reserve.stableDebtTokenAddress).mint( msg.sender, msg.sender, variableDebt, reserve.currentStableBorrowRate ); ``` --- ```solidity=370 IStableDebtToken(address(stableDebtToken)).mint( user, user, stableDebt, reserve.currentStableBorrowRate ); ``` --- ```solidity=506 IAToken(aTokenAddresses[vars.i]).transferUnderlyingTo(receiverAddress, amounts[vars.i]); ``` --- ```solidity=916 IAToken(vars.aTokenAddress).transferUnderlyingTo(vars.user, vars.amount); ``` --- ```solidity=43 LENDING_POOL.withdraw(assets[i], balance, currentTreasury); ``` --- ```solidity=31 IERC20(REWARD_TOKEN).approve(INCENTIVES_CONTROLLER, value); ```
Open the reportThe linked variables assigned in the constructor can be declared as `immutable`. Immutable state variables can be assigned during contract creation but will remain constant throughout the lifetime of a deployed contract. A big advantage of immutable variables is that reading them is significantly cheaper than reading from regular state variables since they will not be stored in storage.
Open the reportThe linked declarations do not conform to the [Solidity style guide](https://solidity.readthedocs.io/en/v0.7.3/style-guide.html#naming-conventions) with regards to its naming convention. Particularly: - `camelCase`: Should be applied to function names, argument names, local and state variable names, modifiers - `UPPER_CASE`: Should be applied to `constant` variables - `CapWords`: Should be applied to contract names, struct names, event names and enums
Open the reportThe `initialize()` function of **ReaperStrategyTombMai** contract defines a ERC20 token hardcoded address as `0x45f4682B560d4e3B8FF1F1b3A38FDBe775C7177b`. The hardcoded address belongs to UniSwapV2Pair as can be confirmed in [FTMScan Explorer](https://ftmscan.com/address/0x45f4682B560d4e3B8FF1F1b3A38FDBe775C7177b#code) ```solidity=60 __ReaperBaseStrategy_init(_vault, 0x45f4682B560d4e3B8FF1F1b3A38FDBe775C7177b, _strategists, _multisigRoles); ```
Open the reportIn Solidity, the functions that write or update the status of sensitive state variables should emit descriptive events as notifications.
Open the reportWhen calculating the conversion between assets and shares, the input amount is not validated. Affected functions are: ```solidity=51 function convertToShares(uint256 assets) ``` ```solidity=66 function convertToAssets(uint256 shares) ``` Input data of public and external functions should always be verified.
Open the reportDuring the definition of **ReaperStrategyTombMai** contract, the `poolId` variable is defined as follows: ```solidity=49 uint256 public poolId; ``` However, the `poolId` is set to be 2 in function `initialize()` and not modified at any point of the code, so could be declared as constant.
Open the reportThere is the risk that attackers could become the unintended administrators of deployed contracts. The initialization of `ReaperBaseStrategyv4` based contracts, including inherited contract, can only be done by calling function `__ReaperBaseStrategy_init()`. In theory, hackers and automatic bots can monitor the transaction of new contract deployment and front-run contracts with a similar transaction to initialize it. As a consequence, the frontrunner will become the unintended administrator of the contract and will be to control upgrades.
Open the reportThe functions `IUniswapV2Router02(_router).swapExactTokensForTokensSupportingFeeOnTransferTokens()` and `IUniswapV2Router02(TOMB_ROUTER).addLiquidity()` in the aforementioned lines are executed without setting restrictions on slippage, which would make the swapping and liquidity-adding processes sensitive to price fluctuation from the DEX. In this case, it would be vulnerable to potential sandwich attacks, and thus the project might suffer unexpected losses.
Open the reportIn **ReaperStrategyTombMai** the function `_swap()` is declared as follows: ```solidity=133 function _swap( uint256 _amount, address[] memory _path, address _router ) internal { if (_path.length < 2 || _amount == 0) { return; } IERC20Upgradeable(_path[0]).safeIncreaseAllowance(_router, _amount); IUniswapV2Router02(_router).swapExactTokensForTokensSupportingFeeOnTransferTokens( _amount, 0, _path, address(this), block.timestamp ); } ``` This function silently fails when: 1. Input path contains less than two elements 2. Swap amount is zero In the previous two conditions, the caller won't be notified that the swap failed and the execution will continue as if the call to `_swap()` succeeded. An example of a malicious call could be crafted as: ```solidity function doSwap(uint256 _debt) public { _debt = 0; _swap(_debt, tombToMaiPath, TOMB_ROUTER); } ```
Open the reportThe contract has unlocked compiler version. An unlocked compiler version in the source code of the contract permits the user to compile it at or above a particular version. This, in turn, leads to differences in the generated bytecode between compilations due to differing compiler version numbers. This can lead to an ambiguity when debugging as compiler specific bugs may occur in the codebase that would be hard to identify over a span of multiple compiler versions rather than a specific one.
Open the reportThe return value of an external call is not used as a function return nor `require()` function check. ```solidity=162 IUniswapV2Router02(TOMB_ROUTER).addLiquidity( lpToken0, lpToken1, lp0Bal, lp1Bal, 0, 0, address(this), block.timestamp ); ```
Open the reportThe variable `PERCENT_DIVISOR` is declared but the current code logic doesn't use it. ```solidity=15 uint256 public constant PERCENT_DIVISOR = 10_000; ```
Open the reportThe variables `numStrategists` and `numRoles` can be inlined since no more references to them are found in the code.
Open the reportThe reports name a repository or files. Open a report to see its scope.
Is this your project? Show this record on your own website. The label states what the record holds, links to this page and updates by itself. It is free and needs no sign-in.
Automatic: the three strongest facts of this project’s own record (its last audit and two more), highlighted. They update with the record. Picking a fact turns Automatic off.
<head><script src="https://widget.trustblock.run/project-widget.min.js" defer></script></head><body><divdata-tb-project-widgetdata-tb-project-slug="byte-masons-reliquary"></div></body>
Paste the code where the label should appear. It uses no API credit and updates by itself.
Something 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