Skip to main content

Blur Finance Exchange

Smart Contract Security Assessment

October 21, 2022

Blur

SUMMARY


ABSTRACT

Dedaub was commissioned to perform a security audit of the Blur Protocol.

Two earlier versions of the protocol had already been audited by Dedaub in June 2022. The corresponding reports can be found here (v1.0) and here (v1.1).

The Blur protocol consists of a decentralized NFT Exchange which supports the exchange of ERC721 tokens for ETH or WETH.

Traders sign and submit orders off-chain through the Blur web application. Orders can be submitted as single orders or in bulk, by providing appropriate signatures.

The BlurExchange contract provides functionality which allows the matching of a sell order and a buy order, committing the trade on-chain. The caller of this functionality can thus cause the automatic transfer of the NFTs and WETH from one party to the other. On the other hand, the transfer of the NFTs for ETH requires the buyer to match the orders.

An order can be submitted with or without an expiration time set. In the latter case, the order will become invalid once a certain block range set by the exchange is exceeded, or when the user has requested his off-chain oracle to stop providing authorisation signatures.

Orders may be canceled at any time by specifying the order to be canceled, or a number of orders to be canceled. The exchange also supports the facility of canceling all of a user's orders by incrementing the user’s nonce.

A PolicyManager contract allows matching policies to be whitelisted by the Blur team. This provides extensibility by specifying the conditions under which a buy and a sell order can be matched by the exchange contract. Currently, only one matching policy is available.

The ExecutionDelegate contract performs the transfer of assets between the buyer and the seller that was mentioned above. Only contracts approved by the Blur team are able to execute this functionality. In addition, users can revoke permission from the ExecutionDelegate to perform transfers on their behalf at any time.

This audit report covers the contracts of the at-the-time private repository blur-io/contracts-snapshot-not-public of the Blur protocol, at commit hash 8c8b62ab9e8b94f9ffc6027813af8571af1b9beb.

Two auditors worked on the codebase for 7 days.

The full audited contract list is the following:

contracts/
  • BlurExchange.sol
  • ExecutionDelegate.sol
  • PolicyManager.sol
  • interfaces/
    • IBlurExchange.sol
    • IExecutionDelegate.sol
    • IMatchingPolicy.sol
    • IPolicyManager.sol
  • lib/
    • EIP712.sol
    • ERC1967Proxy.sol
    • MerkleVerifier.sol
    • OrderStructs.sol
    • ReentrancyGuarded.sol
  • matchingPolicies/
    • StandardPolicyERC721.sol

SETTING & CAVEATS

The audit’s main target is security threats, i.e., what the community understanding would likely call "hacking", rather than the regular use of the protocol. Functional correctness (i.e. issues in "regular use") is a secondary consideration. Typically it can only be covered if we are provided with unambiguous (i.e. full-detail) specifications of what is the expected, correct behaviour. In terms of functional correctness, we often trusted the code’s calculations and interactions, in the absence of any other specification. Functional correctness relative to low-level calculations (including units, scaling and quantities returned from external protocols) is generally most effectively done through thorough testing rather than human auditing.


VULNERABILITIES & FUNCTIONAL ISSUES

This section details issues affecting the functionality of the contract. Dedaub generally categorizes issues according to the following severities, but may also take other considerations into account such as impact or difficulty in exploitation:

Category
Description
CRITICAL
Can be profitably exploited by any knowledgeable third-party attacker to drain a portion of the system’s or users’ funds OR the contract does not function as intended and severe loss of funds may result.
HIGH
Third-party attackers or faulty functionality may block the system or cause the system or users to lose funds. Important system invariants can be violated.
MEDIUM
Examples:
  • User or system funds can be lost when third-party systems misbehave.
  • DoS, under specific conditions.
  • Part of the functionality becomes unusable due to a programming error.
LOW
Examples:
  • Breaking important system invariants but without apparent consequences.
  • Buggy functionality for trusted users where a workaround exists.
  • Security issues which may manifest when the system evolves.

Issue resolution includes “dismissed” or “acknowledged” but no action taken, by the client, or “resolved”, per the auditors.


CRITICAL SEVERITY

[No critical severity issues]


HIGH SEVERITY

H1

H1HIGH

Vulnerability related to non-ERC721 compliant listings
dismissed

Dismissed

The Blur team was consulted on this issue. Presently, Blur does not support ERC1155 tokens. In addition the Blur backend checks whether a collection is EC721 compliant and prevents collections which are non-compliant from being added to the backend. The backend only accepts orders that it itself has generated and signed, so that in the future it will not be possible to have the ERC721 matching policy assigned to a non-compliant collection.

Presently, the only matching policy available in the protocol is called StandardPolicyERC721. We understand that in the future Blur intends to allow the listing of other NFT categories on its exchange, such as ERC1155 NFTs.

In the current protocol, it is possible for a user to create a sell order for a non-ERC721 compliant NFT, while specifying the StandardPolicyERC721 as the matching policy. When this order is matched through the execute() function, the _canMatchOrders() function inside the BlurExchange contract will include an AssetType.ERC721 in its return value. Hence, when the _executeTokenTransfer() function runs, it will call the executionDelegate.transferERC721() function. This in turn will execute the external call IERC721(collection).safeTransferFrom(from, to, tokenId).

Now, a non-ERC721 compliant contract (such as an ERC1155 contract) may not have a function with the required signature. If this contract has a fallback function, any malicious code inside it will be executed instead. Importantly, if the fallback function is empty, the seller will receive the buyer’s funds and keep the NFT. Due to this bug, non-compliant but legitimate-looking NFTs can exploit this interaction with the Blur exchange to cause harm to buyers on the exchange.



MEDIUM SEVERITY

[No medium severity issues]


LOW SEVERITY

[No low severity issues]


OTHER / ADVISORY ISSUES

This section details issues that are not thought to directly affect the functionality of the project, but we recommend considering them.

A1

Warning with possible future use of _exists()

A1ADVISORY

Warning with possible future use of _exists()
info

The BlurExchange.sol::_exists() function, determines if an address is a contract by its code size calling extcodesize() function.

(same as OpenZeppelin’s Address.sol::isContract())

While this works when we look for contract addresses, it is unsafe to assume that an address for which _exists() returns 0, is an EOA.

extcodesize() can return 0 for the following reasons:

  • an EOA
  • a contract in construction
  • an address where a contract will be created or where a contract was previously created and was subsequently destroyed

Currently _exists() is used for verifying contract addresses, but we raise a warning for avoiding the use of the opposite condition in future changes and development.

A2

__UUPSUpgradeable_init() is not called

A2ADVISORY

__UUPSUpgradeable_init() is not called
acknowledged

Acknowledged

The Blur team has taken note of this advisory issue and has indicated that this may be fixed in a future version of the protocol.

The function __UUPSUpgradeable_init() of UUPSUpgradeable.sol is not called by the initialize() function of the BlurExchange.sol contract that inherits UUPSUpgradeable.sol.

__UUPSUpgradeable_init() may have an empty implementation at the moment but that could change in a future version of the Open Zeppelin code, which could be used by an upgraded version of the aforementioned contract. This omission of the call could lead to a serious bug if such a change went unnoticed or was not followed by the introduction of a call to __UUPSUpgradeable_init().

A3

Compiler bugs

A3ADVISORY

Compiler bugs
acknowledged

Acknowledged

The Blur team has taken note of this advisory issue and has indicated that contracts will be compiled with Solidity 0.8.17, which does not suffer from this compiler issue.

The code is compiled with Solidity 0.8.13. Version 0.8.13, in particular, has some known bugs. The only bug which is relevant to this protocol is:

This bug affects assembly blocks, such as those found inside the MerkleVerifier.sol contract’s _efficientHash() function. When the Yul Optimiser is enabled, as is the case with this project, mstore() instructions can be removed by the optimizer unless the assembly block accesses local Solidity variables or uses the stored bytes inside the same block.

However, currently, the function is not at risk because it accesses the variables a,b and value. We bring this to your attention in case you are planning changes to the protocol involving assembly.

function _efficientHash(bytes32 a, bytes32 b) private pure
returns (bytes32 value) {
assembly {
mstore(x00, a)
mstore(x20, b)
value := keccak256(x00, x40)
}
}

Note that this bug is only present when the Yul code is generated via the legacy code generation pipeline (which is still the default). The legacy pipeline will run the Yul optimizer individually on an inline assembly block if the block does not refer to any variables defined in the surrounding Solidity code. The new pipeline, on the other hand, optimizes the inline assembly blocks as a part of the whole Yul input.



DISCLAIMER

The audited contracts have been analyzed using automated techniques and extensive human inspection in accordance with state-of-the-art practices as of the date of this report. The audit makes no statements or warranties on the security of the code. On its own, it cannot be considered a sufficient assessment of the correctness of the contract. While we have conducted an analysis to the best of our ability, it is our recommendation for high-value contracts to commission several independent audits, a public bug bounty program, as well as continuous security auditing and monitoring through Dedaub Security Suite.


ABOUT DEDAUB

Dedaub offers significant security expertise combined with cutting-edge program analysis technology to secure some of the most prominent protocols in DeFi. The founders, as well as many of Dedaub's auditors, have a strong academic research background together with a real-world hacker mentality to secure code. Protocol blockchain developers hire us for our foundational analysis tools and deep expertise in program analysis, reverse engineering, DeFi exploits, cryptography and financial mathematics.