Platform: Code4rena
Start Date: 05/10/2022
Pot Size: $50,000 USDC
Total HM: 2
Participants: 80
Period: 5 days
Judge: GalloDaSballo
Id: 168
League: ETH
Rank: 58/80
Findings: 1
Award: $50.48
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: 0x4non
Also found by: 0x1f8b, 0xNazgul, 0xSmartContract, Deivitto, IllIllI, Lambda, RaymondFam, Rolezn, RustyRabbit, Trust, arcoun, bin2chen, brgltd, csanuragjain, d3e4, enckrish, exd0tpy, ladboy233, nicobevi, rbserver, rotcivegaf, simon135, zzykxx
50.4817 USDC - $50.48
1: _transferTo() Usage of deprecated transfer can revert. The original transfer used to send eth uses a fixed stipend 2300 gas. This was used to prevent reentrancy. However this limit your protocol to interact with others contracts that need more than that to process the transaction.
function _transferTo( address paymentToken, address from, address to, uint256 amount ) internal { if (amount == 0) { return; } if (paymentToken == address(0)) { /* Transfer funds in ETH. */ - payable(to).transfer(amount); + (bool success, ) = payable(address(this)).call{value:amount}(""); + require(success, "Transfer failed."); } else if (paymentToken == weth) { /* Transfer funds in WETH. */ executionDelegate.transferERC20(weth, from, to, amount); } else { revert("Invalid payment token"); } }
2: BlurExchange.sol initialize() chainId is passed through the parameter, there is a risk of cross-chain, it is recommended to use block.chainid
function initialize( --- uint chainId, address _weth, IExecutionDelegate _executionDelegate, IPolicyManager _policyManager, address _oracle, uint _blockRange ) public initializer { __Ownable_init(); isOpen = 1; DOMAIN_SEPARATOR = _hashDomain(EIP712Domain({ name : name, version : version, - chainId : chainId, + chainId : block.chainid, verifyingContract : address(this) }));
3: BlurExchange.sol is a Upgradeable contract, it is recommended that the subcontract EIP712.sol add gap, to facilitate the subsequent possible upgrade
contract EIP712 { .. bytes32 DOMAIN_SEPARATOR; .. + uint256[49] private __gap; }
4: execute() suggest to compliance “Checks Effects Interactions”
function execute(Input calldata sell, Input calldata buy) external payable reentrancyGuard whenOpen { .... + /* Mark orders as filled. */ + cancelledOrFilled[sellHash] = true; + cancelledOrFilled[buyHash] = true; _executeFundsTransfer( sell.order.trader, buy.order.trader, sell.order.paymentToken, sell.order.fees, price ); _executeTokenTransfer( sell.order.collection, sell.order.trader, buy.order.trader, tokenId, amount, assetType ); - /* Mark orders as filled. */ - cancelledOrFilled[sellHash] = true; - cancelledOrFilled[buyHash] = true;
5: oracle in initialize() does not require not to be 0, the subsequent can be set, so it is recommended that _validateOracleAuthorization() verification to avoid address(0) Because if oracle is 0, then _validateOracleAuthorization() signature verification will be invalid, can be arbitrary signature
function _validateOracleAuthorization( bytes32 orderHash, SignatureVersion signatureVersion, bytes calldata extraSignature, uint256 blockNumber ) internal view returns (bool) { + require(oracle != address(0)); bytes32 oracleHash = _hashToSignOracle(orderHash, blockNumber);
6: _transferFees() suggest to add the judgment recipient ! = address(0), to avoid losing funds
function _transferFees( Fee[] calldata fees, address paymentToken, address from, uint256 price ) internal returns (uint256) { uint256 totalFee = 0; for (uint8 i = 0; i < fees.length; i++) { uint256 fee = (price * fees[i].rate) / INVERSE_BASIS_POINT; + require(fees[i].recipient != address(0)); _transferTo(paymentToken, from, fees[i].recipient, fee); totalFee += fee; }
7: ExecutionDelegate.sol transferERC20() does not detect whether the transfer is successful, part of the token transfer failure is not revert. Although now only WETH used, but ExecutionDelegate.sol as a tool contract, it is suggest to add check, to avoid the subsequent more paymentToken
function transferERC20(address token, address from, address to, uint256 amount) approvedContract external returns (bool) { require(revokedApproval[from] == false, "User has revoked approval"); _ return IERC20(token).transferFrom(from, to, amount); + bool result = IERC20(token).transferFrom(from, to, amount); + require(result); + return result; }
#0 - GalloDaSballo
2022-10-22T21:07:33Z
L
L
L
R
L
L
## ExecutionDelegate.sol transferERC20() TODO M-01
Needs better formatting
#1 - GalloDaSballo
2022-11-07T20:27:11Z
5L 1R