Skip to content

Commit

Permalink
feat(billboard): remove unused and rename
Browse files Browse the repository at this point in the history
  • Loading branch information
robertu7 committed Jun 30, 2024
1 parent 4bed635 commit 1ce6b87
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 71 deletions.
94 changes: 48 additions & 46 deletions src/Billboard/Billboard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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");
_;
}
Expand All @@ -68,22 +68,24 @@ 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;
}

//////////////////////////////
/// Board
//////////////////////////////

/// @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
Expand All @@ -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_);
}

Expand Down Expand Up @@ -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_,
Expand Down Expand Up @@ -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_);
Expand Down Expand Up @@ -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_;
}

Expand Down Expand Up @@ -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);
Expand Down
20 changes: 13 additions & 7 deletions src/Billboard/BillboardRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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_);
}

//////////////////////////////
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -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");
}

//////////////////////////////
Expand Down
49 changes: 32 additions & 17 deletions src/Billboard/IBillboard.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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 .
Expand Down Expand Up @@ -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.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Billboard/IBillboardRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 1ce6b87

Please sign in to comment.