As of 14 Oct 2026, Block has 1 audit report on Trustblock, by Quantstamp, dated 26 Apr 2023. That report lists no open critical findings.
Record last updated . It holds audits and findings, contracts and incidents up to Oct 2026. Statuses are the security firms’ own. Trustblock does not review code.
Newest first
| Audit | Security firm | Date | Scope | Critical findings | Report |
|---|---|---|---|---|---|
| Block | Security firm: Quantstamp | Date: | Scope: Files named in the report | No open critical findings | Open · certificate.quantstamp.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 0 | 0 | 2 |
| Medium | 0 | 1 | 5 |
| Low | 4 | 6 | 11 |
In `Marketplace.swap()L#129`, the `fullShare` variable is adjusted and later emitted in `L#138`. It is calculated by subtracting all collector shares of all tokens in the listing by the `FEE_DENOMINATOR`. Nevertheless, it does not consider the share of each collector conditioned on the token's share in the listing. Therefore, a valid listing might underflow the `fullShare` variable when the share of all royalties on all tokens adds up to more than `FEE_DENOMINATOR`. When using `solidity 0.8.18`, a transaction is reverted if a variable underflows.
Open the reportIn `Listings._createListing()`, there is no validation done on `tokenIds` being a non-empty array. As a result of this it is possible to create a valid empty listing, which can result in the following issues ranging from High to Medium severity: * A malicious actor can intentionally flood the marketplace with a series of empty listings with arbitrary listing amounts and trick users into accidentally paying for these empty listings. (High Severity) * A malicious actor can spoof the marketplace with fraudulent listings, creating artificial marketplace activity (Medium Severity)
Open the reportGas usage is a main concern for smart contract developers and users, since high gas costs may prevent users from wanting to use the smart contract. Even worse, some gas usage issues may prevent the contract from providing services entirely. For example, if a loop requires too much gas to finish processing, then it may prevent the contract from functioning correctly entirely. We have gas usage concerns around the following functions: * `Listings._createListings()` * `Marketplace.swap()` * `RoyaltiesOracle.setRoyaltyByToken()` The primary concern is that due to unbounded `tokenIds` and `collectors`, it is possible to introduce listings either with a large amount of royalty collectors, a large amount of `tokenIds`, or both. This can result in denial of service issues around attempted swaps of these large listings, making it impossible for the end user to successfully complete a swap due to running out of gas, not to mention extremely high gas costs.
Open the reportDivision before multiplication may result in a loss of precision when the operations are carried over integer numbers. We have identified several instances where this is the case: * `Utils._convertETHWeiToUSDWei()`: First performs division in `_getETHPriceInUSD` and multiplies by `amountInETH` after returned. * `Utils._convertUSDWeiToETHWei()`: Performs a division in `_getETHPriceInUSD` and subsequently divides by its return value. Can be rewritten as multiplication then division. * `Utils._isClose()`: Performs a division of `absDifference` by `originalAmount` prior to multiplying by `100`. * `Utils._getETHPriceInUSD() `: Performs a truncation of the USD cents.
Open the reportAccording to the documentation, `Marketplace.validate()` should validate that “The listing should have `validUntil` greater than the block timestamp”, however this check does not happen in the code. This results in expired listings being returned as valid, which can lead to denial of service issues for users looking to purchase these seemingly valid listings. Fortunately, this check is being performed in `Marketplace.swap()`, preventing the trading of expired listings.
Open the report`RoyaltiesOracle._setRoyalty()` updates the royalty share of a collector address in a specific token. It checks that the new share does not exceed the maximum possible shares (`FEE_DENOMINATOR`) in the token. ``` require(existingRoyalty + share < FEE_DENOMINATOR, "RoyaltiesOracle: existing royalties already at 1000000"); ``` However, this can be a problem when editing royalty shares. For example, if the limit was already reached and the owner wants to change the share of some collectors, the validation `existingRoyalty + share < FEE_DENOMINATOR` will fail and the transaction will revert.
Open the reportThe protocol just calls `latestRoundData()` to get the ether price from the Chainlink price feed contract. However, the data could be out of date. In the event of a rapid drop in the market price of the token, if Chainlink's feed is not updated in a timely manner, the smart contract may continue to believe that the token is worth more than its actual market value.
Open the reportThe [Checks-Effects-Interactions](https://solidity.readthedocs.io/en/latest/security-considerations.html#use-the-checks-effects-interactions-pattern) coding pattern is meant to mitigate any chance of other contracts manipulating the state of the blockchain in unexpected and possibly malicious ways before control is returned to the original contract. As the name implied, only after checking whether appropriate conditions are met and acting internally on those conditions should any external calls to, or interactions with, other contracts be done. This coding pattern is violated in the following instance: * In `Marketplace.swap()`, the following changes to state happen after external calls are made: * On `L#133`, the listing is being unlisted via `_deleteListing()` only after external calls for royalty payouts are made. * On `L#146`, the sales counter is being incremented only after all the external calls have been made.
Open the reportThe marketplace currently has a payable fallback function implemented, allowing for the marketplace to receive accidental transfers of ether. This can result in complicated situations involving the end user’s funds being locked up in the contract. *Note: This is slightly mitigated by the `drain()` function, allowing for the admin to potentially resolve any locking up of funds.
Open the reportIt is important to validate inputs, even if they only come from trusted addresses, to avoid human error. While other issues also involve missing input validation, we have included our remaining findings regarding this issue here due to the low severity nature of these findings: * In the constructor of `Listings.sol`, `blockBarBtl` is not being validated for a non-zero address. * In the constructor of `Utils.sol`, `priceFeedAddress` is not being validated for a non-zero address. * In `Utils._isClose()`, validate that `originalAmount` is a non zero integer to avoid any potential division by zero errors. * In `Marketplace.swap()`, there is no validation on `msg.value` being greater than 0.
Open the reportThe only duration requirement that is currently enforced around listing durations is that the `_validUntil` parameter being passed into `Listings._createListing()` is greater than `block.timestamp`. This can result in a scenario where a malicious user can flood the market with listings that expire right after being created, making it difficult for regular end-users to conduct regular trading activities as seemingly valid listings will immediately expire before a user can attempt to purchase them. Additionally this can result in spoofed market activity, where a sudden increase in seemingly valid listings can send false signals to traders.
Open the reportThere are several instances in which event emissions are either missing or potentially misleading: * In `RoyaltiesOracle.setRoyaltyByToken()`, `_setRoyalty` emits a `Royalty()` event per royalty update, which would make sense in the case of a single royalty update, however when doing a batch royalty assignment, it makes sense to emit the `Royalty()` event for the token only after all the royalties have been assigned. * In `RoyaltiesOracle.removeRoyaltyByToken()`, there is no event emitted regarding royalty removal.
Open the reportThe following roles have additional permissions, compromising the decentralization of the system: * `MANAGER_ROLE` * `PAUSER_ROLE` * `DEFAULT_ADMIN_ROLE`
Open the reportOpenZeppelin's `AccessControl` and `Ownable` contracts contain `renounceRole()` and `renounceOwnership()` functions which allow privileged addresses to give up their privileged roles. If privileged roles were renounced, all functionality associated with said role would be inaccessible.
Open the reportNatspec states that royalty shares *must not exceed 100%*, but the `RoyaltiesOracle._setRoyalty()` function ensures that it is strictly less than 100%. ```=223 require(existingRoyalty + share < FEE_DENOMINATOR, "RoyaltiesOracle: existing royalties already at 1000000"); ```
Open the reportSeveral functions have documentation stating that they can be called by "a contract admin or a caller with the Manager Role". However, these functions are currently permissioned only by a caller with `MANAGER_ROLE`. * `RoyaltiesOracle.setRoyaltyByToken()` * `RoyaltiesOracle.setRoyalty()` * `RoyaltiesOracle.removeRoyalty()` * `RoyaltiesOracle._removeRoyalty()` * `RoyaltiesOracle._setRoyalty()`
Open the reportThe `_owner` variable in `ExtendedAccessControl` seems to be unused. There are no functions or modifiers making use of it.
Open the reportOpenZeppelin's AccessControl library deprecated `_setupRole()` function in favor of `_grantRole()` ([documentation](https://docs.openzeppelin.com/contracts/4.x/api/access#AccessControl-_setupRole-bytes32-address-)).
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="block"></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