From 1ce6b8776b449785195249b775862b8c215def52 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 30 Jun 2024 16:42:17 +0800 Subject: [PATCH] feat(billboard): remove unused and rename --- src/Billboard/Billboard.sol | 94 ++++++++++++++-------------- src/Billboard/BillboardRegistry.sol | 20 +++--- src/Billboard/IBillboard.sol | 49 ++++++++++----- src/Billboard/IBillboardRegistry.sol | 2 +- 4 files changed, 94 insertions(+), 71 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 1ce31e0..10e6d6e 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -13,7 +13,7 @@ contract Billboard is IBillboard { address public immutable admin; // tokenId => address => whitelisted - mapping(uint256 => mapping(address => bool)) public boardWhitelists; + mapping(uint256 => mapping(address => bool)) public boardWhitelist; constructor(address token_, address payable registry_, address admin_, string memory name_, string memory symbol_) { require(admin_ != address(0), "Zero address"); @@ -39,17 +39,17 @@ contract Billboard is IBillboard { } modifier isFromWhitelist(uint256 tokenId_) { - require(boardWhitelists[tokenId_][msg.sender], "Whitelist"); + require(boardWhitelist[tokenId_][msg.sender], "Whitelist"); _; } - modifier isFromBoardCreator(uint256 tokenId_) { + modifier isFromCreator(uint256 tokenId_) { IBillboardRegistry.Board memory _board = registry.getBoard(tokenId_); require(_board.creator == msg.sender, "Creator"); _; } - modifier isFromBoardTenant(uint256 tokenId_) { + modifier isFromTenant(uint256 tokenId_) { require(msg.sender == registry.ownerOf(tokenId_), "Tenant"); _; } @@ -68,13 +68,13 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function addToWhitelist(uint256 tokenId_, address value_) external isFromAdmin { - boardWhitelists[tokenId_][value_] = true; + function addToWhitelist(uint256 tokenId_, address account_) external isFromCreator(tokenId_) { + boardWhitelist[tokenId_][account_] = true; } /// @inheritdoc IBillboard - function removeFromWhitelist(uint256 tokenId_, address value_) external isFromAdmin { - boardWhitelists[tokenId_][value_] = false; + function removeFromWhitelist(uint256 tokenId_, address account_) external isFromCreator(tokenId_) { + boardWhitelist[tokenId_][account_] = false; } ////////////////////////////// @@ -82,8 +82,10 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function mintBoard(address to_, uint256 taxRate_, uint256 epochInterval_) external returns (uint256 tokenId) { - tokenId = registry.newBoard(to_, taxRate_, epochInterval_); + function mintBoard(uint256 taxRate_, uint256 epochInterval_) external returns (uint256 tokenId) { + require(epochInterval_ > 0, "Zero epoch interval"); + + tokenId = registry.newBoard(msg.sender, taxRate_, epochInterval_); } /// @inheritdoc IBillboard @@ -92,14 +94,13 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function setBoard( uint256 tokenId_, string calldata name_, string calldata description_, string calldata imageURI_, string calldata location_ - ) external isFromBoardCreator(tokenId_) { + ) external isFromCreator(tokenId_) { registry.setBoard(tokenId_, name_, description_, imageURI_, location_); } @@ -135,44 +136,47 @@ contract Billboard is IBillboard { require(_board.creator != address(0), "Board not found"); uint256 _endedAt = this.getBlockFromEpoch(epoch_ + 1, _board.epochInterval); + require(_endedAt >= block.number, "Auction ended"); + + IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, epoch_, msg.sender); - // clear auction if the auction is ended, - if (_endedAt >= block.number) { - _clearAuction(tokenId_, _board.creator, epoch_); - return; + uint256 _tax = calculateTax(tokenId_, price_); + + // create new bid if no bid exists + if (_bid.createdAt == 0) { + // transfer bid price and tax to the registry + SafeERC20.safeTransferFrom(registry.currency(), msg.sender, address(registry), price_ + _tax); + + // add new bid + registry.newBid(tokenId_, epoch_, msg.sender, price_, _tax, contentURI_, redirectURI_); } - // otherwise, create new bid or update bid + // update bid if exists else { - IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, epoch_, msg.sender); + require(price_ > _bid.price, "Price too low"); - uint256 _tax = calculateTax(tokenId_, price_); + // transfer diff amount to the registry + uint256 _priceDiff = price_ - _bid.price; + uint256 _taxDiff = _tax - _bid.tax; + SafeERC20.safeTransferFrom(registry.currency(), msg.sender, address(registry), _priceDiff + _taxDiff); - // create new bid - if (_bid.createdAt == 0) { - // transfer bid price and tax to the registry - SafeERC20.safeTransferFrom(registry.token(), msg.sender, address(registry), price_ + _tax); - - // add new bid - registry.newBid(tokenId_, epoch_, msg.sender, price_, _tax, contentURI_, redirectURI_); - } - // update bid - else { - require(price_ > _bid.price, "Price too low"); - - // transfer diff amount to the registry - uint256 _priceDiff = price_ - _bid.price; - uint256 _taxDiff = _tax - _bid.tax; - SafeERC20.safeTransferFrom(registry.token(), msg.sender, address(registry), _priceDiff + _taxDiff); - - if (hasURIs) { - registry.setBid(tokenId_, epoch_, msg.sender, price_, _tax, contentURI_, redirectURI_, true); - } else { - registry.setBid(tokenId_, epoch_, msg.sender, price_, _tax, "", "", false); - } + if (hasURIs) { + registry.setBid(tokenId_, epoch_, msg.sender, price_, _tax, contentURI_, redirectURI_, true); + } else { + registry.setBid(tokenId_, epoch_, msg.sender, price_, _tax, "", "", false); } } } + /// @inheritdoc IBillboard + function setBidURIs( + uint256 tokenId_, + uint256 epoch_, + string calldata contentURI_, + string calldata redirectURI_ + ) public { + registry.setBidURIs(tokenId_, epoch_, msg.sender, contentURI_, redirectURI_); + } + /// @inheritdoc IBillboard function clearAuction( uint256 tokenId_, @@ -223,7 +227,7 @@ contract Billboard is IBillboard { if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) - registry.transferTokenByOperator(_prevOwner, _highestBid.price); + registry.transferCurrencyByOperator(_prevOwner, _highestBid.price); // transfer bid tax to board creator's tax treasury (uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(boardCreator_); @@ -308,18 +312,16 @@ contract Billboard is IBillboard { registry.setBidWithdrawn(tokenId_, epoch_, msg.sender, true); // transfer bid price and tax back to the bidder - registry.transferTokenByOperator(msg.sender, amount); + registry.transferCurrencyByOperator(msg.sender, amount); } /// @inheritdoc IBillboard function getEpochFromBlock(uint256 block_, uint256 epochInterval_) public pure returns (uint256 epoch) { - // TODO: check overflow and underflow return block_ / epochInterval_; } /// @inheritdoc IBillboard function getBlockFromEpoch(uint256 epoch_, uint256 epochInterval_) public pure returns (uint256 blockNumber) { - // TODO: check overflow and underflow return epoch_ * epochInterval_; } @@ -349,7 +351,7 @@ contract Billboard is IBillboard { registry.setTaxTreasury(msg.sender, _taxAccumulated, _taxAccumulated); // transfer tax to the owner - registry.transferTokenByOperator(msg.sender, amount); + registry.transferCurrencyByOperator(msg.sender, amount); // emit TaxWithdrawn registry.emitTaxWithdrawn(msg.sender, amount); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index ebd73be..2dda923 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -13,8 +13,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address public operator; - // token to be used for auction - IERC20 public immutable token; + // currency to be used for auction + IERC20 public immutable currency; // tokenId => Board mapping(uint256 => Board) public boards; @@ -34,11 +34,16 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ////////////////////////////// /// Constructor ////////////////////////////// - constructor(address token_, address operator_, string memory name_, string memory symbol_) ERC721(name_, symbol_) { + constructor( + address currency_, + address operator_, + string memory name_, + string memory symbol_ + ) ERC721(name_, symbol_) { require(operator_ != address(0), "Zero address"); - require(token_ != address(0), "Zero address"); + require(currency_ != address(0), "Zero address"); operator = operator_; - token = IERC20(token_); + currency = IERC20(currency_); } ////////////////////////////// @@ -205,6 +210,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { string calldata redirectURI_ ) external isFromOperator { Bid memory _bid = bids[tokenId_][epoch_][bidder_]; + require(_bid.createdAt != 0, "Bid not found"); _bid.contentURI = contentURI_; _bid.redirectURI = redirectURI_; @@ -249,9 +255,9 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function transferTokenByOperator(address to_, uint256 amount_) external isFromOperator { + function transferCurrencyByOperator(address to_, uint256 amount_) external isFromOperator { require(to_ != address(0), "Zero address"); - require(token.transfer(to_, amount_), "Failed token transfer"); + require(currency.transfer(to_, amount_), "Failed token transfer"); } ////////////////////////////// diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 5ed81f3..c9915d0 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -8,19 +8,20 @@ import "./IBillboardRegistry.sol"; * @notice The on-chain billboard system transforms platform attention into NFT billboards based on Harberger tax auctions. Empowering creators with a fair share of tax revenue through quadratic voting. * * ## Billboard - * - User (whitelisted) can mint a billboard: call `mintBoard`. - * - Owner of a billboard can set the AD data of a billboard: call `setBoardName`, `setBoardDescription` and `setBoardLocation`. - * - Tenant of a billboard can set the AD data of a billboard: call `setBoardContentURI` and `setBoardRedirectURI`. + * - User can mint a billboard: `mintBoard`. + * - Creator, who mints the billboard, can set the metadata: `setBoard`. + * - Tenant, who wins the auction, can set the AD data: `setBidURIs`. * * ## Auction & Bid - * - User needs to call `approve` on currency (USDT) contract before starting. - * - User can place a bid on a billboard: call `placeBid`. - * - User can clear auction on a billboard: call `clearAuction`. - * - User can withdraw bid from a billboard: call `withdrawBid`. + * - Creator can set a epoch interval when `mintBoard`. + * - User needs to call `approve` on currency (e.g. USDT) contract before starting. + * - User can place a bid on a billboard: `placeBid`. + * - User can clear auction on a billboard: `clearAuction`. + * - User can withdraw a bid: `withdrawBid`. * * ## Tax - * - Admin of this contract can set global tax rate: call `setTaxRate`. - * - Owner of a billbaord can withdraw tax: call `withdrawTax`. + * - Creator can set a tax rate when `mintBoard`. + * - Creator can withdraw tax: `withdrawTax`. * * @dev This contract holds the logic, while read from and write into {BillboardRegistry}, which is the storage contact. * @dev This contract use the {BillboardRegistry} contract for storage, and can be updated by transfering ownership to a new implementation contract. @@ -45,17 +46,17 @@ interface IBillboard { * @notice Add address to whitelist. * * @param tokenId_ Token ID. - * @param address_ Address of user will be added into whitelist. + * @param account_ Address of user will be added into whitelist. */ - function addToWhitelist(uint256 tokenId_, address address_) external; + function addToWhitelist(uint256 tokenId_, address account_) external; /** * @notice Remove address from whitelist. * * @param tokenId_ Token ID. - * @param address_ Address of user will be removed from whitelist. + * @param account_ Address of user will be removed from whitelist. */ - function removeFromWhitelist(uint256 tokenId_, address address_) external; + function removeFromWhitelist(uint256 tokenId_, address account_) external; ////////////////////////////// /// Board @@ -64,13 +65,12 @@ interface IBillboard { /** * @notice Mint a new board (NFT). * - * @param to_ Address of the board owner. - * @param taxRate_ Tax rate of the new board. - * @param epochInterval_ Epoch interval of the new board. + * @param taxRate_ Tax rate per epoch. (e.g. 1024 for 10.24% per epoch) + * @param epochInterval_ Epoch interval in blocks (e.g. 100 for 100 blocks). * * @return tokenId Token ID of the new board. */ - function mintBoard(address to_, uint256 taxRate_, uint256 epochInterval_) external returns (uint256 tokenId); + function mintBoard(uint256 taxRate_, uint256 epochInterval_) external returns (uint256 tokenId); /** * @notice Get metadata of a board . @@ -158,6 +158,21 @@ interface IBillboard { string calldata redirectURI_ ) external payable; + /** + * @notice Set the content URI and redirect URI of a board. + * + * @param tokenId_ Token ID of a board. + * @param epoch_ Epoch. + * @param contentURI_ Content URI of a board. + * @param redirectURI_ Redirect URI of a board. + */ + function setBidURIs( + uint256 tokenId_, + uint256 epoch_, + string calldata contentURI_, + string calldata redirectURI_ + ) external; + /** * @notice Get bid of a board auction. * diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 4237a3f..546a761 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -310,7 +310,7 @@ interface IBillboardRegistry is IERC721 { * @param to_ Address of a receiver. * @param amount_ Amount. */ - function transferTokenByOperator(address to_, uint256 amount_) external; + function transferCurrencyByOperator(address to_, uint256 amount_) external; ////////////////////////////// /// Event emission