-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into audit_v2_4_0_flb_02c
- Loading branch information
Showing
20 changed files
with
704 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity 0.8.22; | ||
|
||
import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol"; | ||
|
||
/** | ||
* @title BuyerContract | ||
* | ||
* @notice Contract that acts as a buyer for testing purposes | ||
*/ | ||
contract BuyerContract is IERC721Receiver { | ||
enum FailType { | ||
None, | ||
Revert, | ||
ReturnWrongSelector | ||
} | ||
|
||
FailType public failType; | ||
|
||
/** | ||
* @dev Set fail type | ||
*/ | ||
function setFailType(FailType _failType) external { | ||
failType = _failType; | ||
} | ||
|
||
/** | ||
* @dev Return wrong selector to test revert | ||
*/ | ||
function onERC721Received( | ||
address operator, | ||
address from, | ||
uint256 tokenId, | ||
bytes calldata data | ||
) external returns (bytes4) { | ||
if (failType == FailType.Revert) revert("BuyerContract: revert"); | ||
if (failType == FailType.ReturnWrongSelector) return 0x12345678; | ||
return IERC721Receiver.onERC721Received.selector; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity 0.8.22; | ||
|
||
import { DisputeHandlerFacet } from "../protocol/facets/DisputeHandlerFacet.sol"; | ||
|
||
/** | ||
* @title TestDisputeHandlerFacet | ||
* | ||
* @notice Extended DisputeHandlerFacet with additional external functions for testing | ||
*/ | ||
contract TestDisputeHandlerFacet is DisputeHandlerFacet { | ||
/** | ||
* @notice Test function to test invalid final dispute state | ||
* | ||
* @param _exchangeId - the id of the associated exchange | ||
* @param _targetState - target final state | ||
*/ | ||
function finalizeDispute(uint256 _exchangeId, DisputeState _targetState) external { | ||
(, Exchange storage exchange) = fetchExchange(_exchangeId); | ||
(, Dispute storage dispute, DisputeDates storage disputeDates) = fetchDispute(_exchangeId); | ||
finalizeDispute(_exchangeId, exchange, dispute, disputeDates, _targetState, 1000); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,239 @@ | ||
// SPDX-License-Identifier: GPL-3.0-or-later | ||
pragma solidity ^0.8.9; | ||
|
||
import { IBosonOfferHandler } from "../interfaces/handlers/IBosonOfferHandler.sol"; | ||
import { IBosonExchangeHandler } from "../interfaces/handlers/IBosonExchangeHandler.sol"; | ||
import { BosonTypes } from "../domain/BosonTypes.sol"; | ||
import { ERC721 } from "../example/support/ERC721.sol"; | ||
import { IERC721Metadata } from "../example/support/IERC721Metadata.sol"; | ||
import { IERC721 } from "../interfaces/IERC721.sol"; | ||
import { IERC165 } from "../interfaces/IERC165.sol"; | ||
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; | ||
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; | ||
import { IERC721Receiver } from "../interfaces/IERC721Receiver.sol"; | ||
|
||
/** | ||
* @title MockWrapper | ||
* @notice Wrapper contract used in tests | ||
* | ||
*/ | ||
contract MockWrapper is BosonTypes, ERC721, IERC721Receiver { | ||
// Add safeTransferFrom to IERC20 | ||
using SafeERC20 for IERC20; | ||
|
||
// Contract addresses | ||
address private immutable voucherAddress; | ||
address private immutable mockAuctionAddress; | ||
address private immutable protocolAddress; | ||
address private immutable wethAddress; | ||
|
||
// Token ID for which the price is not yet known | ||
uint256 private pendingTokenId; | ||
|
||
// Mapping from token ID to price. If pendingTokenId == tokenId, this is not the final price. | ||
mapping(uint256 => uint256) private price; | ||
|
||
// Mapping to cache exchange token address, so costly call to the protocol is not needed every time. | ||
mapping(uint256 => address) private cachedExchangeToken; | ||
|
||
mapping(uint256 => address) private wrapper; | ||
|
||
/** | ||
* @notice Constructor | ||
* | ||
* @param _voucherAddress The address of the voucher that are wrapped by this contract. | ||
* @param _mockAuctionAddress The address of Mock Auction. | ||
*/ | ||
constructor( | ||
address _voucherAddress, | ||
address _mockAuctionAddress, | ||
address _protocolAddress, | ||
address _wethAddress | ||
) ERC721(getVoucherName(_voucherAddress), getVoucherSymbol(_voucherAddress)) { | ||
voucherAddress = _voucherAddress; | ||
mockAuctionAddress = _mockAuctionAddress; | ||
protocolAddress = _protocolAddress; | ||
wethAddress = _wethAddress; | ||
|
||
// Approve Mock Auction to transfer wrapped vouchers | ||
_setApprovalForAll(address(this), _mockAuctionAddress, true); | ||
} | ||
|
||
/** | ||
* @dev Returns true if this contract implements the interface defined by | ||
* `interfaceId`. See the corresponding | ||
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] | ||
* to learn more about how these ids are created. | ||
*/ | ||
function supportsInterface(bytes4 _interfaceId) public view virtual override(ERC721) returns (bool) { | ||
return (_interfaceId == type(IERC721).interfaceId || _interfaceId == type(IERC165).interfaceId); | ||
} | ||
|
||
/** | ||
* @notice Wraps the voucher, transfer true voucher to itself and approves the contract owner to operate on it. | ||
* | ||
* Reverts if: | ||
* - caller is not the contract owner | ||
* | ||
* @param _tokenId The token id. | ||
*/ | ||
function wrap(uint256 _tokenId) external { | ||
// Transfer voucher to this contract | ||
// Instead of msg.sender it could be voucherAddress, if vouchers were preminted to contract itself | ||
// Not using safeTransferFrom since this contract is the recipient and we are sure it can handle the vouchers | ||
IERC721(voucherAddress).transferFrom(msg.sender, address(this), _tokenId); | ||
|
||
// Mint to itself, so it can be used with Mock Auction | ||
_mint(address(this), _tokenId); // why not sender instead of address(this)? | ||
|
||
// Approves original token owner to operate on wrapped token | ||
_approve(msg.sender, _tokenId); | ||
|
||
wrapper[_tokenId] = msg.sender; | ||
} | ||
|
||
/** | ||
* @notice Unwraps the voucher, transfer true voucher to owner and funds to the protocol. | ||
* | ||
* Reverts if: | ||
* - caller is neither protocol nor voucher owner | ||
* | ||
* @param _tokenId The token id. | ||
*/ | ||
function unwrap(uint256 _tokenId) external { | ||
address wrappedVoucherOwner = ownerOf(_tokenId); | ||
if (wrappedVoucherOwner == address(this)) wrappedVoucherOwner = wrapper[_tokenId]; | ||
|
||
// Either contract owner or protocol can unwrap | ||
// If contract owner is unwrapping, this is equivalent to canceled auction | ||
require( | ||
msg.sender == protocolAddress || wrappedVoucherOwner == msg.sender, | ||
"MockWrapper: Only owner or protocol can unwrap" | ||
); | ||
|
||
// If some token price is not know yet, update it now | ||
if (pendingTokenId != 0) updatePendingTokenPrice(); | ||
|
||
uint256 priceToPay = price[_tokenId]; | ||
|
||
// Delete price and pendingTokenId to prevent reentrancy | ||
delete price[_tokenId]; | ||
delete pendingTokenId; | ||
|
||
// transfer voucher to voucher owner | ||
IERC721(voucherAddress).safeTransferFrom(address(this), wrappedVoucherOwner, _tokenId); | ||
|
||
// Transfer token to protocol | ||
if (priceToPay > 0) { | ||
IERC20(cachedExchangeToken[_tokenId]).safeTransfer(protocolAddress, priceToPay); | ||
} | ||
|
||
delete cachedExchangeToken[_tokenId]; // gas refund | ||
delete wrapper[_tokenId]; | ||
|
||
// Burn wrapped voucher | ||
_burn(_tokenId); | ||
|
||
// Send funds to protocol (testing purposes) | ||
payable(msg.sender).transfer(address(this).balance); | ||
} | ||
|
||
/** | ||
* @notice Handle transfers out of Mock Auction. | ||
* | ||
* @param _from The address of the sender. | ||
* @param _to The address of the recipient. | ||
* @param _tokenId The token id. | ||
*/ | ||
function _beforeTokenTransfer(address _from, address _to, uint256 _tokenId) internal virtual override(ERC721) { | ||
if (_from == mockAuctionAddress && _to != address(this)) { | ||
// Auction is over, and wrapped voucher is being transferred to voucher owner | ||
// If recipient is address(this), it means the auction was canceled and price updating can be skipped | ||
|
||
// If some token price is not know yet, update it now | ||
if (pendingTokenId != 0) updatePendingTokenPrice(); | ||
|
||
// Store current balance and set the pending token id | ||
price[_tokenId] = getCurrentBalance(_tokenId); | ||
pendingTokenId = _tokenId; | ||
} | ||
|
||
super._beforeTokenTransfer(_from, _to, _tokenId); | ||
} | ||
|
||
function updatePendingTokenPrice() internal { | ||
uint256 tokenId = pendingTokenId; | ||
price[tokenId] = getCurrentBalance(tokenId) - price[tokenId]; | ||
} | ||
|
||
/** | ||
* @notice Gets own token balance for the exchange token, associated with the token ID. | ||
* | ||
* @dev If the exchange token is not known, it is fetched from the protocol and cached for future use. | ||
* | ||
* @param _tokenId The token id. | ||
*/ | ||
function getCurrentBalance(uint256 _tokenId) internal returns (uint256) { | ||
address exchangeToken = cachedExchangeToken[_tokenId]; | ||
|
||
// If exchange token is not known, get it from the protocol. | ||
if (exchangeToken == address(0)) { | ||
uint256 offerId = _tokenId >> 128; // OfferId is the first 128 bits of the token ID. | ||
|
||
if (offerId == 0) { | ||
// pre v2.2.0. Token does not have offerId, so we need to get it from the protocol. | ||
// Get Boson exchange. Don't explicitly check if the exchange exists, since existance of the token implies it does. | ||
uint256 exchangeId = _tokenId & type(uint128).max; // ExchangeId is the last 128 bits of the token ID. | ||
(, BosonTypes.Exchange memory exchange, ) = IBosonExchangeHandler(protocolAddress).getExchange( | ||
exchangeId | ||
); | ||
offerId = exchange.offerId; | ||
} | ||
|
||
// Get Boson offer. Don't explicitly check if the offer exists, since existance of the token implies it does. | ||
(, BosonTypes.Offer memory offer, , , , ) = IBosonOfferHandler(protocolAddress).getOffer(offerId); | ||
exchangeToken = offer.exchangeToken; | ||
|
||
// If exchange token is 0, it means native token is used. In that case, use WETH. | ||
if (exchangeToken == address(0)) exchangeToken = wethAddress; | ||
cachedExchangeToken[_tokenId] = exchangeToken; | ||
} | ||
|
||
return IERC20(exchangeToken).balanceOf(address(this)); | ||
} | ||
|
||
/** | ||
* @notice Gets the Boson Voucher token name and adds "Wrapped" prefix. | ||
* | ||
* @dev Used only in the constructor. | ||
* | ||
* @param _voucherAddress Boson Voucher address | ||
*/ | ||
function getVoucherName(address _voucherAddress) internal view returns (string memory) { | ||
string memory name = IERC721Metadata(_voucherAddress).name(); | ||
return string.concat("Wrapped ", name); | ||
} | ||
|
||
/** | ||
* @notice Gets the the Boson Voucher symbol and adds "W" prefix. | ||
* | ||
* @dev Used only in the constructor. | ||
* | ||
* @param _voucherAddress Boson Voucher address | ||
*/ | ||
function getVoucherSymbol(address _voucherAddress) internal view returns (string memory) { | ||
string memory symbol = IERC721Metadata(_voucherAddress).symbol(); | ||
return string.concat("W", symbol); | ||
} | ||
|
||
/** | ||
* @dev See {IERC721Receiver-onERC721Received}. | ||
* | ||
* Always returns `IERC721Receiver.onERC721Received.selector`. | ||
*/ | ||
function onERC721Received(address, address, uint256, bytes calldata) public virtual override returns (bytes4) { | ||
return this.onERC721Received.selector; | ||
} | ||
|
||
function topUp() external payable {} | ||
} |
Oops, something went wrong.