As of 14 Oct 2026, Virtualness has 1 audit report on Trustblock, by QuillAudits, dated 24 Jul 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 |
|---|---|---|---|---|---|
| Virtualness | Security firm: QuillAudits | Date: | Scope: Files named in the report | No open critical findings | Open · quillaudits.com |
Statuses are the security firm’s own, from each report.
| Severity | Open | Acknowledged | Fixed |
|---|---|---|---|
| Critical | 0 | 0 | 0 |
| High | 1 | 0 | 0 |
| Medium | 2 | 0 | 3 |
| Low | 19 | 0 | 16 |
transferFunds() calls royaltyInfo(tokenId, price) on collection contract to take receiver and royaltyAmount. In case any collection doesn’t implement ERC2981 standard the royaltyInfo() function would be absent in that contract and the call will fail.
Open the reportTransferExecutor:transferFunds() function uses _transferTo() to transfer tokens “from” to “to” address. Here _transferTo() calls transferERC20() from the ExecutionDelegate contract.But in transferERC20() it can happen that the transferFrom() will fail to transfer tokens (e.g in case of not having enough tokens in account). In this case if the token contract is a non reverting token (which doesn’t revert on failure and returns bool value) the boolean status value is not getting checked after that call. So it can happen that the malicious buyer won’t have anything in the account to transfer and would be able to buy tokens for free (i.e without spending tokens to buy NFT)
Open the reportWhile lazy minting tokens with fulfillLazyMintOrder() , in matchAndLazyMint() function transferFunds() and tokenLazyMint() gets executed. But here while executing transferFunds() the “(address receiver, uint256 royaltyAmount) = IERC2981Upgradeable(collection).royaltyInfo(tokenId, price);” will return receiver as zero address and it won’t send royaltyAmount to the receiver. The reason the receiver would be zero address is because the royalty info for the token is getting set after the transferFunds() call i.e in tokenLazyMint().
Open the reportIn function _saveSupply() there is a require statement on L247 stating supply of token should be zero but it does not have a meaningful error message if the function is called on the same token id again.
Open the reportAdd a constructor and call _disableInitializers() in constructor of this contract,calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized to any version. It is recommended to use this to lock implementation contracts that are designed to be called through proxies.
Open the reportAdd a constructor and call _disableInitializers() in the constructor of this contract,calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized to any version. It is recommended to use this to lock implementation contracts that are designed to be called through proxies.
Open the reportAdd a constructor and call _disableInitializers() in the constructor of this contract,calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized to any version. It is recommended to use this to lock implementation contracts that are designed to be called through proxies.
Open the reportIn function cancelOrder() the require statement on L274 checks if message.sender is the trader who is going to cancel the order but there is no error message set if the msg.sender is not the trader so it will revert wihtout the error message.
Open the reportLets say, Seller/trader wants to cancel the order he checks on the website/interface that the order isn’t executed yet and proceeds to cancel it. at that moment someone buys the order before it gets canceled i.e someone bought it before cancelOrder transaction executes. So in this case the cancelOrder() won’t execute the code in the if block because cancelledOrFilled[hash] was set to true when the buyer bought it. So it will proceed execution without setting it to true again but also without reverting the transaction. In this case it can happen that the seller will get false assurance that his transaction got canceled even though it was executed. Adding require statement to revert transaction in this case will help for handling this situation as adding some check from the backend will can’t handle this situation e.g dapp backend checks that the cancelledOrFilled[hash] is false means the order is not filled yet but as mentioned in above example it can happen that the order will get filled once user executes cancelOrder() transaction.
Open the reportpragma abicoder v2; getting declared , but ABI coder v2 is activated by default from 0.8.0 version. As can be seen here https://docs.soliditylang.org/en/v0.8.0/080-breaking-changes.html
Open the reportpragma abicoder v2; getting declared , but ABI coder v2 is activated by default from 0.8.0 version. As can be seen here https://docs.soliditylang.org/en/v0.8.0/080-breaking-changes.html
Open the reportInitializable is getting imported but UUPSUpgradeable already imports Initializable which makes it redundant.
Open the reportContracts are using floating pragma (pragma solidity ^0.8.17), Contracts should be deployed with the same compiler version and flags that they have been tested thoroughly. Using floating pragma does not ensure that the contracts will be deployed with the same version. It is possible that the most recent compiler version gets selected while deploying a contract which has higher chances of having bugs in it.
Open the reportIn the lazyMint() function there is some code on L187 and L197 which is commented out and is not used.
Open the reportIn the lazyMint() function there is some code on L209 which is commented out and is not used.
Open the reportEvent Creators(uint256 indexed tokenId, LibPart.Part[] indexed creators) is not used in contract.
Open the reportERC721Upgradeable and AccessControlUpgradeable are not getting inherited by ERC721Virtualness. Unused/uninherited imports can be removed.
Open the reportIn function _transferTo() send() is used to transfer eth which is not the recommended way. The recommended way to transfer eth is to use call{}. The reason being send and transfer both uses 2300 gas for transferring but because there can be changes in gas in future the gas limit for both those options might change which will result in failure of the eth transfer.
Open the reportIn the contract VirtualnessV1Core the function validateOrderTime() allows expiration time to be set to 0. It can happen that the order signature remains unexecuted for long time and someone will able to execute that order later where seller may don’t want to execute that order for that price specified before.
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="virtualness"></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