From 1d3e54bc91ec86dd85acaa96f07d6d40b24413e4 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Wed, 1 Nov 2023 00:12:52 +0800 Subject: [PATCH 01/55] Create the first version of Billboard contracts. --- .gas-snapshot | 220 ++++++++++++------------ src/Billboard/Billboard.sol | 156 +++++++++++++++++ src/Billboard/BillboardAuction.sol | 149 +++++++++++++++++ src/Billboard/BillboardRegistry.sol | 241 +++++++++++++++++++++++++++ src/Billboard/IBillboard.sol | 178 ++++++++++++++++++++ src/Billboard/IBillboardAuction.sol | 138 +++++++++++++++ src/Billboard/IBillboardRegistry.sol | 145 ++++++++++++++++ 7 files changed, 1117 insertions(+), 110 deletions(-) create mode 100644 src/Billboard/Billboard.sol create mode 100644 src/Billboard/BillboardAuction.sol create mode 100644 src/Billboard/BillboardRegistry.sol create mode 100644 src/Billboard/IBillboard.sol create mode 100644 src/Billboard/IBillboardAuction.sol create mode 100644 src/Billboard/IBillboardRegistry.sol diff --git a/.gas-snapshot b/.gas-snapshot index fda7a48..04b30dd 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,113 +1,113 @@ -CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12244) -CurationTest:testCannotCurateERC20EmptyURI() (gas: 15838) -CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21671) -CurationTest:testCannotCurateERC20SelfCuration() (gas: 16082) -CurationTest:testCannotCurateERC20ZeroAddress() (gas: 15950) -CurationTest:testCannotCurateNativeTokenCurateZeroAmount() (gas: 10008) -CurationTest:testCannotCurateNativeTokenEmptyURI() (gas: 16508) -CurationTest:testCannotCurateNativeTokenSelfCuration() (gas: 16763) -CurationTest:testCannotCurateNativeTokenToContractRejector() (gas: 28604) -CurationTest:testCannotCurateNativeTokenZeroAddress() (gas: 16528) -CurationTest:testERC20Curation() (gas: 59976) -CurationTest:testNativeTokenCuration() (gas: 60127) -CurationTest:testNativeTokenCurationToContractAcceptor() (gas: 37508) -LogbookTest:testClaim() (gas: 134763) -LogbookTest:testDonate(uint96) (runs: 256, μ: 155493, ~: 156942) -LogbookTest:testDonateWithCommission(uint96,uint96) (runs: 256, μ: 152152, ~: 140464) -LogbookTest:testFork(uint96,string) (runs: 256, μ: 446796, ~: 451347) -LogbookTest:testForkRecursively(uint8,uint96) (runs: 256, μ: 4224034, ~: 1016125) -LogbookTest:testForkWithCommission(uint96,string,uint256) (runs: 256, μ: 542623, ~: 257710) -LogbookTest:testMulticall() (gas: 285685) -LogbookTest:testPublicSale() (gas: 202868) -LogbookTest:testPublish(string) (runs: 256, μ: 264518, ~: 264648) -LogbookTest:testPublishEn1000() (gas: 243576) -LogbookTest:testPublishEn140() (gas: 221340) -LogbookTest:testPublishEn200() (gas: 222925) -LogbookTest:testPublishEn2000() (gas: 270119) -LogbookTest:testPublishEn300() (gas: 225383) -LogbookTest:testPublishEn50() (gas: 218821) -LogbookTest:testPublishEn500() (gas: 230367) -LogbookTest:testPublishEn5000() (gas: 348595) -LogbookTest:testPublishZh100() (gas: 224601) -LogbookTest:testPublishZh20() (gas: 218803) -LogbookTest:testPublishZh200() (gas: 231171) -LogbookTest:testPublishZh2000() (gas: 371254) -LogbookTest:testPublishZh50() (gas: 221251) -LogbookTest:testPublishZh500() (gas: 251055) -LogbookTest:testPublishZh5000() (gas: 607789) -LogbookTest:testSetDescription() (gas: 140859) -LogbookTest:testSetForkPrice() (gas: 153948) -LogbookTest:testSetTitle() (gas: 168804) -LogbookTest:testSplitRoyalty(uint8,uint8,uint96) (runs: 256, μ: 2065544, ~: 637605) -LogbookTest:testWithdraw() (gas: 7296693) -LogbookNFTSVGTest:testTokenURI(uint8,uint8,uint16) (runs: 256, μ: 2026391, ~: 1315240) -SnapperTest:testCannotInitRegionByNotOwner() (gas: 11390) -SnapperTest:testCannotReInitRegion() (gas: 14423) -SnapperTest:testCannotTakeSnapshotBeforeInit() (gas: 15792) -SnapperTest:testCannotTakeSnapshotByNotOwner() (gas: 12528) -SnapperTest:testCannotTakeSnapshotWrongLastBlock() (gas: 49279) -SnapperTest:testCannotTakeSnapshotWrongSnapshotBlock() (gas: 24049) -SnapperTest:testInitRegion(uint256) (runs: 256, μ: 114604, ~: 114604) -SnapperTest:testTakeSnapshot() (gas: 47962) -ACLManagerTest:testCannotGrantACLManagerRole() (gas: 12231) -ACLManagerTest:testCannotGrantRoleByNonACLManager() (gas: 17403) -ACLManagerTest:testCannotGrantRoleToZeroAddress() (gas: 12220) -ACLManagerTest:testCannotRenounceRoleByACLManager() (gas: 12081) -ACLManagerTest:testCannotRenounceRoleByAttacker() (gas: 12371) -ACLManagerTest:testCannotTransferRoleByAttacker() (gas: 12498) -ACLManagerTest:testCannotTransferRoleToZeroAddress() (gas: 12218) -ACLManagerTest:testGrantRole() (gas: 23547) -ACLManagerTest:testRenounceRole() (gas: 27841) -ACLManagerTest:testRoles() (gas: 15393) -ACLManagerTest:testTransferRole() (gas: 21528) -TheSpaceTest:testBatchBid() (gas: 690679) -TheSpaceTest:testBatchSetPixels(uint16,uint8) (runs: 256, μ: 369115, ~: 370766) -TheSpaceTest:testBidDefaultedToken() (gas: 409339) -TheSpaceTest:testBidExistingToken() (gas: 354974) -TheSpaceTest:testBidNewToken() (gas: 301167) -TheSpaceTest:testCanTransferFromIfSettleTax() (gas: 355017) -TheSpaceTest:testCannotBidExceedAllowance() (gas: 60907) -TheSpaceTest:testCannotBidOutBoundTokens() (gas: 260493) -TheSpaceTest:testCannotBidPriceTooLow() (gas: 341680) -TheSpaceTest:testCannotGetTaxWithNonExistingToken() (gas: 16426) -TheSpaceTest:testCannotGetTokenURIInLogicContract() (gas: 296920) -TheSpaceTest:testCannotSetColorByAttacker() (gas: 302856) -TheSpaceTest:testCannotSetConfigByAttacker() (gas: 12078) -TheSpaceTest:testCannotSetPixel(uint256) (runs: 256, μ: 312359, ~: 312359) -TheSpaceTest:testCannotSetPriceByNonOwner() (gas: 302932) -TheSpaceTest:testCannotSetTokenImageURIByNonACLManager() (gas: 11887) -TheSpaceTest:testCannotSetTotalSupplyByAttacker() (gas: 11883) -TheSpaceTest:testCannotTransferFromIfDefault() (gas: 394091) -TheSpaceTest:testCannotUpgradeByAttacker() (gas: 11564) -TheSpaceTest:testCollectableTax() (gas: 333312) -TheSpaceTest:testDefault() (gas: 390517) +ACLManagerTest:testCannotGrantACLManagerRole() (gas: 188) +ACLManagerTest:testCannotGrantRoleByNonACLManager() (gas: 165) +ACLManagerTest:testCannotGrantRoleToZeroAddress() (gas: 142) +ACLManagerTest:testCannotRenounceRoleByACLManager() (gas: 164) +ACLManagerTest:testCannotRenounceRoleByAttacker() (gas: 165) +ACLManagerTest:testCannotTransferRoleByAttacker() (gas: 143) +ACLManagerTest:testCannotTransferRoleToZeroAddress() (gas: 166) +ACLManagerTest:testGrantRole() (gas: 186) +ACLManagerTest:testRenounceRole() (gas: 143) +ACLManagerTest:testRoles() (gas: 15288) +ACLManagerTest:testTransferRole() (gas: 187) +CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) +CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) +CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) +CurationTest:testCannotCurateERC20SelfCuration() (gas: 16031) +CurationTest:testCannotCurateERC20ZeroAddress() (gas: 15899) +CurationTest:testCannotCurateNativeTokenCurateZeroAmount() (gas: 9958) +CurationTest:testCannotCurateNativeTokenEmptyURI() (gas: 16468) +CurationTest:testCannotCurateNativeTokenSelfCuration() (gas: 16713) +CurationTest:testCannotCurateNativeTokenToContractRejector() (gas: 28554) +CurationTest:testCannotCurateNativeTokenZeroAddress() (gas: 16488) +CurationTest:testERC20Curation() (gas: 59908) +CurationTest:testNativeTokenCuration() (gas: 60085) +CurationTest:testNativeTokenCurationToContractAcceptor() (gas: 37466) +LogbookNFTSVGTest:testTokenURI(uint8,uint8,uint16) (runs: 256, μ: 2035888, ~: 1310779) +LogbookTest:testClaim() (gas: 135608) +LogbookTest:testDonate(uint96) (runs: 256, μ: 155485, ~: 156936) +LogbookTest:testDonateWithCommission(uint96,uint96) (runs: 256, μ: 150646, ~: 140444) +LogbookTest:testFork(uint96,string) (runs: 256, μ: 450748, ~: 453928) +LogbookTest:testForkRecursively(uint8,uint96) (runs: 256, μ: 4403316, ~: 1014389) +LogbookTest:testForkWithCommission(uint96,string,uint256) (runs: 256, μ: 497254, ~: 257636) +LogbookTest:testMulticall() (gas: 284999) +LogbookTest:testPublicSale() (gas: 204837) +LogbookTest:testPublish(string) (runs: 256, μ: 264065, ~: 263590) +LogbookTest:testPublishEn1000() (gas: 243477) +LogbookTest:testPublishEn140() (gas: 221241) +LogbookTest:testPublishEn200() (gas: 222826) +LogbookTest:testPublishEn2000() (gas: 270020) +LogbookTest:testPublishEn300() (gas: 225284) +LogbookTest:testPublishEn50() (gas: 218722) +LogbookTest:testPublishEn500() (gas: 230268) +LogbookTest:testPublishEn5000() (gas: 348496) +LogbookTest:testPublishZh100() (gas: 224502) +LogbookTest:testPublishZh20() (gas: 218704) +LogbookTest:testPublishZh200() (gas: 231104) +LogbookTest:testPublishZh2000() (gas: 371155) +LogbookTest:testPublishZh50() (gas: 221152) +LogbookTest:testPublishZh500() (gas: 250956) +LogbookTest:testPublishZh5000() (gas: 607690) +LogbookTest:testSetDescription() (gas: 140760) +LogbookTest:testSetForkPrice() (gas: 153925) +LogbookTest:testSetTitle() (gas: 168680) +LogbookTest:testSplitRoyalty(uint8,uint8,uint96) (runs: 256, μ: 1862299, ~: 636792) +LogbookTest:testWithdraw() (gas: 7284400) +SnapperTest:testCannotInitRegionByNotOwner() (gas: 11365) +SnapperTest:testCannotReInitRegion() (gas: 14373) +SnapperTest:testCannotTakeSnapshotBeforeInit() (gas: 15717) +SnapperTest:testCannotTakeSnapshotByNotOwner() (gas: 12478) +SnapperTest:testCannotTakeSnapshotWrongLastBlock() (gas: 49242) +SnapperTest:testCannotTakeSnapshotWrongSnapshotBlock() (gas: 23899) +SnapperTest:testInitRegion(uint256) (runs: 256, μ: 114408, ~: 114408) +SnapperTest:testTakeSnapshot() (gas: 47831) +TheSpaceTest:testBatchBid() (gas: 690308) +TheSpaceTest:testBatchSetPixels(uint16,uint8) (runs: 256, μ: 368737, ~: 370338) +TheSpaceTest:testBidDefaultedToken() (gas: 409416) +TheSpaceTest:testBidExistingToken() (gas: 355023) +TheSpaceTest:testBidNewToken() (gas: 301184) +TheSpaceTest:testCanTransferFromIfSettleTax() (gas: 355069) +TheSpaceTest:testCannotBidExceedAllowance() (gas: 60910) +TheSpaceTest:testCannotBidOutBoundTokens() (gas: 260482) +TheSpaceTest:testCannotBidPriceTooLow() (gas: 341674) +TheSpaceTest:testCannotGetTaxWithNonExistingToken() (gas: 16401) +TheSpaceTest:testCannotGetTokenURIInLogicContract() (gas: 298473) +TheSpaceTest:testCannotSetColorByAttacker() (gas: 302848) +TheSpaceTest:testCannotSetConfigByAttacker() (gas: 12053) +TheSpaceTest:testCannotSetPixel(uint256) (runs: 256, μ: 312357, ~: 312357) +TheSpaceTest:testCannotSetPriceByNonOwner() (gas: 302924) +TheSpaceTest:testCannotSetTokenImageURIByNonACLManager() (gas: 11862) +TheSpaceTest:testCannotSetTotalSupplyByAttacker() (gas: 11858) +TheSpaceTest:testCannotTransferFromIfDefault() (gas: 394147) +TheSpaceTest:testCannotUpgradeByAttacker() (gas: 11539) +TheSpaceTest:testCollectableTax() (gas: 333364) +TheSpaceTest:testDefault() (gas: 390575) TheSpaceTest:testGetConfig() (gas: 14302) -TheSpaceTest:testGetExistingPixel() (gas: 309403) -TheSpaceTest:testGetNonExistingPixel() (gas: 60251) -TheSpaceTest:testGetNonExistingPrice() (gas: 19524) -TheSpaceTest:testGetOwner() (gas: 346900) +TheSpaceTest:testGetExistingPixel() (gas: 309428) +TheSpaceTest:testGetNonExistingPixel() (gas: 60258) +TheSpaceTest:testGetNonExistingPrice() (gas: 19529) +TheSpaceTest:testGetOwner() (gas: 346931) TheSpaceTest:testGetOwnerOfNonExistingToken() (gas: 13346) -TheSpaceTest:testGetPixelsByOwnerWithNoPixels() (gas: 24265) -TheSpaceTest:testGetPixelsByOwnerWithOnePixel() (gas: 319489) -TheSpaceTest:testGetPixelsPageByOwnerWithPixels() (gas: 586574) -TheSpaceTest:testGetPrice() (gas: 297984) -TheSpaceTest:testGetTax() (gas: 375340) -TheSpaceTest:testGetTokenImageURI() (gas: 14407) -TheSpaceTest:testGetTokenURI() (gas: 331148) -TheSpaceTest:testSetColor() (gas: 328831) -TheSpaceTest:testSetMintTax() (gas: 269213) -TheSpaceTest:testSetPixel(uint256) (runs: 256, μ: 398774, ~: 398774) -TheSpaceTest:testSetPrice(uint256) (runs: 256, μ: 302135, ~: 302135) -TheSpaceTest:testSetPriceByOperator(uint256) (runs: 256, μ: 352082, ~: 352082) -TheSpaceTest:testSetPriceTooHigh() (gas: 312001) -TheSpaceTest:testSetTaxRate() (gas: 345387) -TheSpaceTest:testSetTokenImageURI() (gas: 353533) -TheSpaceTest:testSetTotalSupply(uint256) (runs: 256, μ: 349634, ~: 349641) -TheSpaceTest:testSetTreasuryShare() (gas: 381733) -TheSpaceTest:testSettleTax() (gas: 336899) -TheSpaceTest:testTaxCalculation() (gas: 397345) -TheSpaceTest:testTokenShouldBeDefaulted() (gas: 322983) +TheSpaceTest:testGetPixelsByOwnerWithNoPixels() (gas: 24283) +TheSpaceTest:testGetPixelsByOwnerWithOnePixel() (gas: 319322) +TheSpaceTest:testGetPixelsPageByOwnerWithPixels() (gas: 585976) +TheSpaceTest:testGetPrice() (gas: 298001) +TheSpaceTest:testGetTax() (gas: 375416) +TheSpaceTest:testGetTokenImageURI() (gas: 14307) +TheSpaceTest:testGetTokenURI() (gas: 330962) +TheSpaceTest:testSetColor() (gas: 328848) +TheSpaceTest:testSetMintTax() (gas: 269237) +TheSpaceTest:testSetPixel(uint256) (runs: 256, μ: 398816, ~: 398816) +TheSpaceTest:testSetPrice(uint256) (runs: 256, μ: 302152, ~: 302152) +TheSpaceTest:testSetPriceByOperator(uint256) (runs: 256, μ: 352105, ~: 352105) +TheSpaceTest:testSetPriceTooHigh() (gas: 312004) +TheSpaceTest:testSetTaxRate() (gas: 345451) +TheSpaceTest:testSetTokenImageURI() (gas: 353313) +TheSpaceTest:testSetTotalSupply(uint256) (runs: 256, μ: 349701, ~: 349708) +TheSpaceTest:testSetTreasuryShare() (gas: 381788) +TheSpaceTest:testSettleTax() (gas: 336965) +TheSpaceTest:testTaxCalculation() (gas: 397405) +TheSpaceTest:testTokenShouldBeDefaulted() (gas: 323029) TheSpaceTest:testTotalSupply() (gas: 7613) -TheSpaceTest:testUpgradeTo() (gas: 3215589) -TheSpaceTest:testWithdrawTreasury() (gas: 352594) -TheSpaceTest:testWithdrawUBI() (gas: 375731) +TheSpaceTest:testUpgradeTo() (gas: 3215197) +TheSpaceTest:testWithdrawTreasury() (gas: 352672) +TheSpaceTest:testWithdrawUBI() (gas: 375819) \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol new file mode 100644 index 0000000..1c08381 --- /dev/null +++ b/src/Billboard/Billboard.sol @@ -0,0 +1,156 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "./BillboardAuction.sol"; +import "./BillboardRegistry.sol"; +import "./IBillboard.sol"; +import "./IBillboardAuction.sol"; +import "./IBillboardRegistry.sol"; + +contract Billboard is IBillboard { + address public admin; + + BillboardAuction public auction; + + BillboardRegistry public registry; + + constructor() { + admin = msg.sender; + } + + ////////////////////////////// + /// Modifiers + ////////////////////////////// + + modifier isValidAddress(address value_) { + if (value_ == address(0)) { + revert InvalidAddress(); + } + _; + } + + modifier isAdmin(address value_) { + if (admin == address(0)) { + revert AdminNotFound(); + } + if (value_ == address(0)) { + revert InvalidAddress(); + } + if (value_ == admin) { + revert Unauthorized("admin"); + } + _; + } + + ////////////////////////////// + /// Upgradability + ////////////////////////////// + + /// @inheritdoc IBillboard + function upgradeAuction(address contract_) external isValidAddress(contract_) isAdmin(msg.sender) { + auction = BillboardAuction(contract_); + } + + /// @inheritdoc IBillboard + function upgradeRegistry(address contract_) external isValidAddress(contract_) isAdmin(msg.sender) { + registry = BillboardRegistry(contract_); + } + + /// @inheritdoc IBillboard + function setIsOpened(bool value_) external isAdmin(msg.sender) { + registry.setIsOpened(value_, msg.sender); + auction.setIsOpened(value_, msg.sender); + } + + ////////////////////////////// + /// Board + ////////////////////////////// + + /// @inheritdoc IBillboard + function mintBoard(address to_) external isValidAddress(to_) { + uint256 tokenId = registry.mint(to_, msg.sender); + auction.initTreasury(tokenId); + } + + /// @inheritdoc IBillboard + function getBoard(uint256 tokenId_) external view returns (IBillboardRegistry.Board memory board) { + return registry.getBoard(tokenId_); + } + + /// @inheritdoc IBillboard + function setBoardName(uint256 tokenId_, string memory name_) external { + registry.setBoardName(tokenId_, name_, msg.sender); + } + + /// @inheritdoc IBillboard + function setBoardDescription(uint256 tokenId_, string memory description_) external { + registry.setBoardDescription(tokenId_, description_, msg.sender); + } + + /// @inheritdoc IBillboard + function setBoardLocation(uint256 tokenId_, string memory location_) external { + registry.setBoardLocation(tokenId_, location_, msg.sender); + } + + /// @inheritdoc IBillboard + function setBoardContentURI(uint256 tokenId_, string memory uri_) external { + registry.setBoardContentURI(tokenId_, uri_, msg.sender); + } + + /// @inheritdoc IBillboard + function setBoardRedirectLink(uint256 tokenId_, string memory redirectLink_) external { + registry.setBoardRedirectLink(tokenId_, redirectLink_, msg.sender); + } + + ////////////////////////////// + /// Auction + ////////////////////////////// + + /// @inheritdoc IBillboard + function setTaxRate(uint256 taxRate_) external isAdmin(msg.sender) { + auction.setTaxRate(taxRate_, msg.sender); + } + + /// @inheritdoc IBillboard + function getTaxRate() external view returns (uint256 taxRate) { + return auction.taxRate(); + } + + /// @inheritdoc IBillboard + function placeBid(uint256 tokenId_, uint256 amount_) external { + auction.placeBid(tokenId_, amount_, msg.sender); + } + + /// @inheritdoc IBillboard + function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardAuction.Bid memory bid) { + return auction.getBid(tokenId_, bidder_); + } + + /// @inheritdoc IBillboard + function getBidsByBoard( + uint256 tokenId_, + uint256 limit_, + uint256 offset_ + ) + external + view + returns ( + uint256 total, + uint256 limit, + uint256 offset, + IBillboardAuction.Bid[] memory bids + ) + { + return auction.getBidsByBoard(tokenId_, limit_, offset_); + } + + /// @inheritdoc IBillboard + function clearAuction(uint256 tokenId_) external { + auction.clearAuction(tokenId_); + } + + /// @inheritdoc IBillboard + function withdraw(uint256 tokenId_) external { + auction.withdraw(tokenId_, msg.sender); + } +} diff --git a/src/Billboard/BillboardAuction.sol b/src/Billboard/BillboardAuction.sol new file mode 100644 index 0000000..8afb79f --- /dev/null +++ b/src/Billboard/BillboardAuction.sol @@ -0,0 +1,149 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "./IBillboardAuction.sol"; + +contract BillboardAuction is IBillboardAuction { + bool public isOpened = false; + + address public admin; + + address public operator; + + uint256 public taxRate; + + mapping(uint256 => Auction) public auctions; + + mapping(uint256 => address[]) public bidders; + + mapping(uint256 => mapping(address => Bid)) public currentBids; + + mapping(uint256 => Bid) public currentHighestBids; + + mapping(uint256 => uint256) public lockedTaxations; + + mapping(uint256 => Treasury) public treasuries; + + constructor( + address admin_, + address operator_, + uint256 taxRate_ + ) { + admin = admin_; + operator = operator_; + taxRate = taxRate_; + } + + ////////////////////////////// + /// Modifier + ////////////////////////////// + + modifier isValidAddress(address value_) { + if (value_ == address(0)) { + revert InvalidAddress(); + } + _; + } + + modifier isAdmin(address value_) { + if (admin == address(0)) { + revert AdminNotFound(); + } + if (value_ == address(0)) { + revert InvalidAddress(); + } + if (value_ != admin) { + revert Unauthorzied("admin"); + } + _; + } + + modifier isFromOperator() { + if (operator == address(0)) { + revert OperatorNotFound(); + } + if (msg.sender == address(0)) { + revert InvalidAddress(); + } + if (msg.sender != operator) { + revert Unauthorzied("operator"); + } + _; + } + + /// @inheritdoc IBillboardAuction + function setIsOpened(bool value_, address sender_) external isAdmin(sender_) isFromOperator { + isOpened = value_; + } + + /// @inheritdoc IBillboardAuction + function setTaxRate(uint256 taxRate_, address sender_) external isAdmin(sender_) isFromOperator { + taxRate = taxRate_; + } + + /// @inheritdoc IBillboardAuction + function initTreasury(uint256 tokenId_) external isFromOperator { + // TODO + } + + /// @inheritdoc IBillboardAuction + function placeBid( + uint256 tokenId_, + uint256 amount_, + address sender_ + ) external isFromOperator isAdmin(sender_) { + // TODO + } + + /// @inheritdoc IBillboardAuction + function getBid(uint256 tokenId_, address bidder_) external view isValidAddress(bidder_) returns (Bid memory bid) { + return currentBids[tokenId_][bidder_]; + } + + /// @inheritdoc IBillboardAuction + function getBidsByBoard( + uint256 tokenId_, + uint256 limit_, + uint256 offset_ + ) + external + view + returns ( + uint256 total, + uint256 limit, + uint256 offset, + Bid[] memory bids + ) + { + // TODO + } + + /// @inheritdoc IBillboardAuction + function initAuction(uint256 tokenId_) external isFromOperator { + // TODO + } + + /// @inheritdoc IBillboardAuction + function getAuction(uint256 tokenId_) external view returns (Auction memory auction) { + return auctions[tokenId_]; + } + + /// @inheritdoc IBillboardAuction + function clearAuction(uint256 tokenId_) external { + // TODO + } + + /** + * @notice Refund to bidders who are not winning auction of a board. + * + * @param tokenId_ Token ID of a board. + */ + function _refund(uint256 tokenId_) internal { + // TODO + } + + /// @inheritdoc IBillboardAuction + function withdraw(uint256 tokenId_, address sender_) external { + // TODO + } +} diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol new file mode 100644 index 0000000..7d9e4ed --- /dev/null +++ b/src/Billboard/BillboardRegistry.sol @@ -0,0 +1,241 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import "@openzeppelin/contracts/utils/Counters.sol"; + +import "./IBillboardRegistry.sol"; + +contract BillboardRegistry is IBillboardRegistry, ERC721 { + using Counters for Counters.Counter; + + Counters.Counter private tokenIds; + + bool public isOpened = false; + + address public admin; + + address public operator; + + mapping(uint256 => Board) public boards; + + constructor( + address admin_, + address operator_, + string memory name_, + string memory symbol_ + ) ERC721(name_, symbol_) { + admin = admin_; + operator = operator_; + } + + ////////////////////////////// + /// Modifier + ////////////////////////////// + + modifier isValidAddress(address value_) { + if (value_ == address(0)) { + revert InvalidAddress(); + } + _; + } + + modifier isValidBoard(uint256 tokenId_) { + uint256 latestId = tokenIds.current(); + + if (tokenId_ < 1 || tokenId_ > latestId) { + revert InvalidBoardId(); + } + if (!_exists(tokenId_)) { + revert BoardNotFound(); + } + _; + } + + modifier isBoardOwner(uint256 tokenId_, address value_) { + if (value_ != boards[tokenId_].owner) { + revert Unauthorized("board owner"); + } + _; + } + + modifier isBoardTenant(uint256 tokenId_, address value_) { + if (value_ != _ownerOf(tokenId_)) { + revert Unauthorized("board tenant"); + } + _; + } + + modifier isAdmin(address value_) { + if (admin == address(0)) { + revert AdminNotFound(); + } + if (value_ == address(0)) { + revert InvalidAddress(); + } + if (value_ != admin) { + revert Unauthorized("admin"); + } + _; + } + + modifier isFromOperator() { + if (operator == address(0)) { + revert OperatorNotFound(); + } + if (msg.sender == address(0)) { + revert InvalidAddress(); + } + if (msg.sender != operator) { + revert Unauthorized("operator"); + } + _; + } + + /// @inheritdoc IBillboardRegistry + function setIsOpened(bool value_, address sender_) external isAdmin(sender_) isFromOperator { + isOpened = value_; + } + + /// @inheritdoc IBillboardRegistry + function mint(address to_, address sender_) external isValidAddress(to_) isFromOperator returns (uint256 tokenId) { + if (isOpened == false && sender_ != admin) { + revert Unauthorized("minter"); + } + + tokenIds.increment(); + uint256 newBoardId = tokenIds.current(); + + _safeMint(to_, newBoardId); + + Board memory newBoard = Board({ + owner: to_, + tenant: to_, + lastHighestBidPrice: 0, + name: "", + description: "", + contentURI: "", + redirectLink: "", + location: "" + }); + boards[newBoardId] = newBoard; + + emit Mint(newBoardId, to_); + + return newBoardId; + } + + /// @inheritdoc IBillboardRegistry + function getBoard(uint256 tokenId_) external view isValidBoard(tokenId_) returns (Board memory board) { + return boards[tokenId_]; + } + + /// @inheritdoc IBillboardRegistry + function setBoardName( + uint256 tokenId_, + string memory name_, + address sender_ + ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + boards[tokenId_].name = name_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardDescription( + uint256 tokenId_, + string memory description_, + address sender_ + ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + boards[tokenId_].description = description_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardLocation( + uint256 tokenId_, + string memory location_, + address sender_ + ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + boards[tokenId_].location = location_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardContentURI( + uint256 tokenId_, + string memory uri_, + address sender_ + ) external isValidBoard(tokenId_) isBoardTenant(tokenId_, sender_) { + boards[tokenId_].contentURI = uri_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardRedirectLink( + uint256 tokenId_, + string memory redirectLink_, + address sender_ + ) external isValidBoard(tokenId_) isBoardTenant(tokenId_, sender_) { + boards[tokenId_].redirectLink = redirectLink_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) + external + isValidBoard(tokenId_) + isFromOperator + { + boards[tokenId_].lastHighestBidPrice = price_; + } + + ////////////////////////////// + /// ERC721 Overrides + ////////////////////////////// + + /** + * @notice See {IERC721-tokenURI}. + */ + function tokenURI(uint256 tokenId_) + public + view + override(ERC721) + isValidBoard(tokenId_) + returns (string memory uri) + { + return boards[tokenId_].contentURI; + } + + /** + * @notice See {IERC721-isApprovedForAll}. + */ + function isApprovedForAll(address owner_, address operator_) public view override(ERC721, IERC721) returns (bool) { + if (operator_ == operator) { + return true; + } + + return super.isApprovedForAll(owner_, operator_); + } + + /** + * @notice See {IERC721-transferFrom}. + */ + function transferFrom( + address from_, + address to_, + uint256 tokenId_ + ) public override(ERC721, IERC721) isValidBoard(tokenId_) { + safeTransferFrom(from_, to_, tokenId_, ""); + } + + /** + * @notice See {IERC721-safeTransferFrom}. + */ + function safeTransferFrom( + address from_, + address to_, + uint256 tokenId_, + bytes memory data_ + ) public override(ERC721, IERC721) isValidAddress(from_) isValidAddress(to_) isValidBoard(tokenId_) { + if (!_isApprovedOrOwner(msg.sender, tokenId_)) { + revert Unauthorized("not owner nor approved"); + } + _safeTransfer(from_, to_, tokenId_, data_); + boards[tokenId_].tenant = to_; + } +} diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol new file mode 100644 index 0000000..a78ec0c --- /dev/null +++ b/src/Billboard/IBillboard.sol @@ -0,0 +1,178 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "./IBillboardAuction.sol"; +import "./IBillboardRegistry.sol"; + +interface IBillboard { + ////////////////////////////// + /// Error + ////////////////////////////// + + error AdminNotFound(); + + error InvalidAddress(); + + error Unauthorized(string type_); + + ////////////////////////////// + /// Upgradability + ////////////////////////////// + + /** + * @notice Switch the auction logic contract to another one. + * + * @param contract_ Address of new auction logic contract. + */ + function upgradeAuction(address contract_) external; + + /** + * @notice Switch the registry logic contract to another one. + * + * @param contract_ Address of new registry logic contract. + */ + function upgradeRegistry(address contract_) external; + + /** + * @notice Toggle for operation access. + * + * @param value_ Value of access state. + */ + function setIsOpened(bool value_) external; + + ////////////////////////////// + /// Board + ////////////////////////////// + + /** + * @notice Mint a new board (NFT). + * + * @param to_ Address of the new board receiver. + */ + function mintBoard(address to_) external; + + /** + * @notice Get a board data. + * + * @param tokenId_ Token ID of a board. + * + * @return board Board data. + */ + function getBoard(uint256 tokenId_) external view returns (IBillboardRegistry.Board memory board); + + /** + * @notice Set the name of a board. + * + * @param tokenId_ Token ID of a board. + * @param name_ Board name. + */ + function setBoardName(uint256 tokenId_, string memory name_) external; + + /** + * @notice Set the description of a board. + * + * @param tokenId_ Token ID of a board. + * @param description_ Board description. + */ + function setBoardDescription(uint256 tokenId_, string memory description_) external; + + /** + * @notice Set the location of a board. + * + * @param tokenId_ Token ID of a board. + * @param location_ Digital address where a board located. + */ + function setBoardLocation(uint256 tokenId_, string memory location_) external; + + /** + * @notice Set the content URI of a board. + * + * @param tokenId_ Token ID of a board. + * @param uri_ Content URI of a board. + */ + function setBoardContentURI(uint256 tokenId_, string memory uri_) external; + + /** + * @notice Set the redirect link of a board when users clicking. + * + * @param tokenId_ Token ID of a board. + * @param redirectLink_ Redirect link of a board. + */ + function setBoardRedirectLink(uint256 tokenId_, string memory redirectLink_) external; + + ////////////////////////////// + /// Auction + ////////////////////////////// + + /** + * @notice Set the global tax rate. + * + * @param taxRate_ Tax rate. + */ + function setTaxRate(uint256 taxRate_) external; + + /** + * @notice Get the global tax rate. + * + * @return taxRate Tax rate. + */ + function getTaxRate() external view returns (uint256 taxRate); + + /** + * @notice Place bid for a board. + * + * @param tokenId_ Token ID of a board. + * @param amount_ Amount of a bid. + */ + function placeBid(uint256 tokenId_, uint256 amount_) external; + + /** + * @notice Get a bid of a board. + * + * @param tokenId_ Token ID of a board. + * @param bidder_ Address of a bidder. + * + * @return bid Bid of a board. + */ + function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardAuction.Bid memory bid); + + /** + * @notice Get bids of a board. + * + * @param tokenId_ Token ID of a board. + * @param limit_ Limit of returned bids. + * @param offset_ Offset of returned bids. + * + * @return total Total number of bids. + * @return limit Limit of returned bids. + * @return offset Offset of returned bids. + * @return bids Bids of a board. + */ + function getBidsByBoard( + uint256 tokenId_, + uint256 limit_, + uint256 offset_ + ) + external + view + returns ( + uint256 total, + uint256 limit, + uint256 offset, + IBillboardAuction.Bid[] memory bids + ); + + /** + * @notice Clear a board auction. + * + * @param tokenId_ Token ID of a board. + */ + function clearAuction(uint256 tokenId_) external; + + /** + * @notice Withdraw accumulated taxation of a board. + * + * @param tokenId_ Token ID of a board. + */ + function withdraw(uint256 tokenId_) external; +} diff --git a/src/Billboard/IBillboardAuction.sol b/src/Billboard/IBillboardAuction.sol new file mode 100644 index 0000000..b9bb057 --- /dev/null +++ b/src/Billboard/IBillboardAuction.sol @@ -0,0 +1,138 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +interface IBillboardAuction { + ////////////////////////////// + /// Error + ////////////////////////////// + + error AdminNotFound(); + + error AuctionNotFound(); + + error InvalidAddress(); + + error OperatorNotFound(); + + error Unauthorzied(string type_); + + ////////////////////////////// + /// Struct + ////////////////////////////// + + struct Auction { + uint256 startBlock; + uint256 endBlock; + } + + struct Bid { + uint256 atBlock; + uint256 amount; + } + + struct Treasury { + address owner; + uint256 amount; + } + + /** + * @notice Toggle for operation access. + * + * @param value_ Value of access state. + * @param sender_ Address of user who wants to set. + */ + function setIsOpened(bool value_, address sender_) external; + + /** + * @notice Set the global tax rate. + * + * @param taxRate_ Tax rate. + * @param sender_ Address of user who wants to set. + */ + function setTaxRate(uint256 taxRate_, address sender_) external; + + /** + * @notice Initialize a treasury when a new board minted. + * + * @param tokenId_ Token ID of a board. + */ + function initTreasury(uint256 tokenId_) external; + + /** + * @notice Place bid for a board. + * + * @param tokenId_ Token ID of a board. + * @param amount_ Amount of a bid. + * @param sender_ Address of user who wants to bid. + */ + function placeBid( + uint256 tokenId_, + uint256 amount_, + address sender_ + ) external; + + /** + * @notice Place bid for a board. + * + * @param tokenId_ Token ID of a board. + * @param bidder_ Address of a bidder. + * + * @return bid Bid of a board. + */ + function getBid(uint256 tokenId_, address bidder_) external view returns (Bid memory bid); + + /** + * @notice Get bids of a board. + * + * @param tokenId_ Token ID of a board. + * @param limit_ Limit of returned bids. + * @param offset_ Offset of returned bids. + * + * @return total Total number of bids. + * @return limit Limit of returned bids. + * @return offset Offset of returned bids. + * @return bids Bids of a board. + */ + function getBidsByBoard( + uint256 tokenId_, + uint256 limit_, + uint256 offset_ + ) + external + view + returns ( + uint256 total, + uint256 limit, + uint256 offset, + Bid[] memory bids + ); + + /** + * @notice Initialize a new auction of a board. + * + * @param tokenId_ Token ID of a board. + */ + function initAuction(uint256 tokenId_) external; + + /** + * @notice Get the current auction of a board if it exists. + * + * @param tokenId_ Token ID of a board. + */ + function getAuction(uint256 tokenId_) external view returns (Auction memory auction); + + /** + * @notice Clear a board auction. + * + * @param tokenId_ Token ID of a board. + */ + function clearAuction(uint256 tokenId_) external; + + /** + * @notice Withdraw accumulated taxation of a board. + * + * @param tokenId_ Token ID of a board. + * @param sender_ Address of user wants to withdraw. + */ + function withdraw(uint256 tokenId_, address sender_) external; +} diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol new file mode 100644 index 0000000..65e608e --- /dev/null +++ b/src/Billboard/IBillboardRegistry.sol @@ -0,0 +1,145 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; + +interface IBillboardRegistry is IERC721 { + ////////////////////////////// + /// Error + ////////////////////////////// + + error AdminNotFound(); + + error BoardNotFound(); + + error InvalidBoardId(); + + error InvalidAddress(); + + error OperatorNotFound(); + + error Unauthorized(string type_); + + ////////////////////////////// + /// Event + ////////////////////////////// + + event Mint(uint256 indexed tokenId_, address to_); + + event Transfer(uint256 indexed tokenId_, address from_, address to_); + + ////////////////////////////// + /// Struct + ////////////////////////////// + + struct Board { + address owner; + address tenant; + uint256 lastHighestBidPrice; + string name; + string description; + string location; + string contentURI; + string redirectLink; + } + + /** + * @notice Toggle for operation access. + * + * @param value_ Value of access state. + * @param sender_ Address of user who wants to set. + */ + function setIsOpened(bool value_, address sender_) external; + + /** + * @notice Mint a new board (NFT). + * + * @param to_ Address of the new board receiver. + * @param sender_ Address of user who wants to mint. + * + * @return tokenId Token ID of the new board. + */ + function mint(address to_, address sender_) external returns (uint256 tokenId); + + /** + * @notice Get a board data. + * + * @param tokenId_ Token ID of a board. + * + * @return board Board data. + */ + function getBoard(uint256 tokenId_) external view returns (Board memory board); + + /** + * @notice Set the name of a board. + * + * @param tokenId_ Token ID of a board. + * @param name_ Board name. + * @param sender_ Address of user who wants to set. + */ + function setBoardName( + uint256 tokenId_, + string memory name_, + address sender_ + ) external; + + /** + * @notice Set the description of a board. + * + * @param tokenId_ Token ID of a board. + * @param description_ Board description. + * @param sender_ Address of user who wants to set. + */ + function setBoardDescription( + uint256 tokenId_, + string memory description_, + address sender_ + ) external; + + /** + * @notice Set the location of a board. + * + * @param tokenId_ Token ID of a board. + * @param location_ Digital address where a board located. + * @param sender_ Address of user who wants to set. + */ + function setBoardLocation( + uint256 tokenId_, + string memory location_, + address sender_ + ) external; + + /** + * @notice Set the content URI of a board. + * + * @param tokenId_ Token ID of a board. + * @param uri_ Content URI of a board. + * @param sender_ Address of user who wants to set. + */ + function setBoardContentURI( + uint256 tokenId_, + string memory uri_, + address sender_ + ) external; + + /** + * @notice Set the redirect link of a board when users clicking. + * + * @param tokenId_ Token ID of a board. + * @param redirectLink_ Redirect link when users clicking. + * @param sender_ Address of user who wants to set. + */ + function setBoardRedirectLink( + uint256 tokenId_, + string memory redirectLink_, + address sender_ + ) external; + + /** + * @notice Update the last highest bid price of a board. + * + * @param tokenId_ Token ID of a board. + * @param price_ Bid price. + */ + function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) external; +} From 38780e51aebc1316fa80a718ed2a76a348c8fab6 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:20:32 +0800 Subject: [PATCH 02/55] Fix typos. --- .gas-snapshot | 123 +++------------------------- src/Billboard/Billboard.sol | 11 ++- src/Billboard/BillboardAuction.sol | 4 +- src/Billboard/IBillboardAuction.sol | 2 +- 4 files changed, 23 insertions(+), 117 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 04b30dd..81e75c9 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,113 +1,10 @@ -ACLManagerTest:testCannotGrantACLManagerRole() (gas: 188) -ACLManagerTest:testCannotGrantRoleByNonACLManager() (gas: 165) -ACLManagerTest:testCannotGrantRoleToZeroAddress() (gas: 142) -ACLManagerTest:testCannotRenounceRoleByACLManager() (gas: 164) -ACLManagerTest:testCannotRenounceRoleByAttacker() (gas: 165) -ACLManagerTest:testCannotTransferRoleByAttacker() (gas: 143) -ACLManagerTest:testCannotTransferRoleToZeroAddress() (gas: 166) -ACLManagerTest:testGrantRole() (gas: 186) -ACLManagerTest:testRenounceRole() (gas: 143) -ACLManagerTest:testRoles() (gas: 15288) -ACLManagerTest:testTransferRole() (gas: 187) -CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) -CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) -CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) -CurationTest:testCannotCurateERC20SelfCuration() (gas: 16031) -CurationTest:testCannotCurateERC20ZeroAddress() (gas: 15899) -CurationTest:testCannotCurateNativeTokenCurateZeroAmount() (gas: 9958) -CurationTest:testCannotCurateNativeTokenEmptyURI() (gas: 16468) -CurationTest:testCannotCurateNativeTokenSelfCuration() (gas: 16713) -CurationTest:testCannotCurateNativeTokenToContractRejector() (gas: 28554) -CurationTest:testCannotCurateNativeTokenZeroAddress() (gas: 16488) -CurationTest:testERC20Curation() (gas: 59908) -CurationTest:testNativeTokenCuration() (gas: 60085) -CurationTest:testNativeTokenCurationToContractAcceptor() (gas: 37466) -LogbookNFTSVGTest:testTokenURI(uint8,uint8,uint16) (runs: 256, μ: 2035888, ~: 1310779) -LogbookTest:testClaim() (gas: 135608) -LogbookTest:testDonate(uint96) (runs: 256, μ: 155485, ~: 156936) -LogbookTest:testDonateWithCommission(uint96,uint96) (runs: 256, μ: 150646, ~: 140444) -LogbookTest:testFork(uint96,string) (runs: 256, μ: 450748, ~: 453928) -LogbookTest:testForkRecursively(uint8,uint96) (runs: 256, μ: 4403316, ~: 1014389) -LogbookTest:testForkWithCommission(uint96,string,uint256) (runs: 256, μ: 497254, ~: 257636) -LogbookTest:testMulticall() (gas: 284999) -LogbookTest:testPublicSale() (gas: 204837) -LogbookTest:testPublish(string) (runs: 256, μ: 264065, ~: 263590) -LogbookTest:testPublishEn1000() (gas: 243477) -LogbookTest:testPublishEn140() (gas: 221241) -LogbookTest:testPublishEn200() (gas: 222826) -LogbookTest:testPublishEn2000() (gas: 270020) -LogbookTest:testPublishEn300() (gas: 225284) -LogbookTest:testPublishEn50() (gas: 218722) -LogbookTest:testPublishEn500() (gas: 230268) -LogbookTest:testPublishEn5000() (gas: 348496) -LogbookTest:testPublishZh100() (gas: 224502) -LogbookTest:testPublishZh20() (gas: 218704) -LogbookTest:testPublishZh200() (gas: 231104) -LogbookTest:testPublishZh2000() (gas: 371155) -LogbookTest:testPublishZh50() (gas: 221152) -LogbookTest:testPublishZh500() (gas: 250956) -LogbookTest:testPublishZh5000() (gas: 607690) -LogbookTest:testSetDescription() (gas: 140760) -LogbookTest:testSetForkPrice() (gas: 153925) -LogbookTest:testSetTitle() (gas: 168680) -LogbookTest:testSplitRoyalty(uint8,uint8,uint96) (runs: 256, μ: 1862299, ~: 636792) -LogbookTest:testWithdraw() (gas: 7284400) -SnapperTest:testCannotInitRegionByNotOwner() (gas: 11365) -SnapperTest:testCannotReInitRegion() (gas: 14373) -SnapperTest:testCannotTakeSnapshotBeforeInit() (gas: 15717) -SnapperTest:testCannotTakeSnapshotByNotOwner() (gas: 12478) -SnapperTest:testCannotTakeSnapshotWrongLastBlock() (gas: 49242) -SnapperTest:testCannotTakeSnapshotWrongSnapshotBlock() (gas: 23899) -SnapperTest:testInitRegion(uint256) (runs: 256, μ: 114408, ~: 114408) -SnapperTest:testTakeSnapshot() (gas: 47831) -TheSpaceTest:testBatchBid() (gas: 690308) -TheSpaceTest:testBatchSetPixels(uint16,uint8) (runs: 256, μ: 368737, ~: 370338) -TheSpaceTest:testBidDefaultedToken() (gas: 409416) -TheSpaceTest:testBidExistingToken() (gas: 355023) -TheSpaceTest:testBidNewToken() (gas: 301184) -TheSpaceTest:testCanTransferFromIfSettleTax() (gas: 355069) -TheSpaceTest:testCannotBidExceedAllowance() (gas: 60910) -TheSpaceTest:testCannotBidOutBoundTokens() (gas: 260482) -TheSpaceTest:testCannotBidPriceTooLow() (gas: 341674) -TheSpaceTest:testCannotGetTaxWithNonExistingToken() (gas: 16401) -TheSpaceTest:testCannotGetTokenURIInLogicContract() (gas: 298473) -TheSpaceTest:testCannotSetColorByAttacker() (gas: 302848) -TheSpaceTest:testCannotSetConfigByAttacker() (gas: 12053) -TheSpaceTest:testCannotSetPixel(uint256) (runs: 256, μ: 312357, ~: 312357) -TheSpaceTest:testCannotSetPriceByNonOwner() (gas: 302924) -TheSpaceTest:testCannotSetTokenImageURIByNonACLManager() (gas: 11862) -TheSpaceTest:testCannotSetTotalSupplyByAttacker() (gas: 11858) -TheSpaceTest:testCannotTransferFromIfDefault() (gas: 394147) -TheSpaceTest:testCannotUpgradeByAttacker() (gas: 11539) -TheSpaceTest:testCollectableTax() (gas: 333364) -TheSpaceTest:testDefault() (gas: 390575) -TheSpaceTest:testGetConfig() (gas: 14302) -TheSpaceTest:testGetExistingPixel() (gas: 309428) -TheSpaceTest:testGetNonExistingPixel() (gas: 60258) -TheSpaceTest:testGetNonExistingPrice() (gas: 19529) -TheSpaceTest:testGetOwner() (gas: 346931) -TheSpaceTest:testGetOwnerOfNonExistingToken() (gas: 13346) -TheSpaceTest:testGetPixelsByOwnerWithNoPixels() (gas: 24283) -TheSpaceTest:testGetPixelsByOwnerWithOnePixel() (gas: 319322) -TheSpaceTest:testGetPixelsPageByOwnerWithPixels() (gas: 585976) -TheSpaceTest:testGetPrice() (gas: 298001) -TheSpaceTest:testGetTax() (gas: 375416) -TheSpaceTest:testGetTokenImageURI() (gas: 14307) -TheSpaceTest:testGetTokenURI() (gas: 330962) -TheSpaceTest:testSetColor() (gas: 328848) -TheSpaceTest:testSetMintTax() (gas: 269237) -TheSpaceTest:testSetPixel(uint256) (runs: 256, μ: 398816, ~: 398816) -TheSpaceTest:testSetPrice(uint256) (runs: 256, μ: 302152, ~: 302152) -TheSpaceTest:testSetPriceByOperator(uint256) (runs: 256, μ: 352105, ~: 352105) -TheSpaceTest:testSetPriceTooHigh() (gas: 312004) -TheSpaceTest:testSetTaxRate() (gas: 345451) -TheSpaceTest:testSetTokenImageURI() (gas: 353313) -TheSpaceTest:testSetTotalSupply(uint256) (runs: 256, μ: 349701, ~: 349708) -TheSpaceTest:testSetTreasuryShare() (gas: 381788) -TheSpaceTest:testSettleTax() (gas: 336965) -TheSpaceTest:testTaxCalculation() (gas: 397405) -TheSpaceTest:testTokenShouldBeDefaulted() (gas: 323029) -TheSpaceTest:testTotalSupply() (gas: 7613) -TheSpaceTest:testUpgradeTo() (gas: 3215197) -TheSpaceTest:testWithdrawTreasury() (gas: 352672) -TheSpaceTest:testWithdrawUBI() (gas: 375819) \ No newline at end of file +BillboardTest:testBid() (gas: 187) +BillboardTest:testBidByAttacker() (gas: 188) +BillboardTest:testClearAuction() (gas: 143) +BillboardTest:testClearAuctionByAttacker() (gas: 144) +BillboardTest:testMintBoard() (gas: 177730) +BillboardTest:testMintBoardByAttacker() (gas: 165) +BillboardTest:testSetIsOpened() (gas: 49024) +BillboardTest:testSetIsOpenedByAttacker() (gas: 12302) +BillboardTest:testUpgradeAuctionByAttacker() (gas: 14008) +BillboardTest:testUpgradeRegistryByAttacker() (gas: 13997) \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 1c08381..d24250e 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -36,7 +36,7 @@ contract Billboard is IBillboard { if (value_ == address(0)) { revert InvalidAddress(); } - if (value_ == admin) { + if (value_ != admin) { revert Unauthorized("admin"); } _; @@ -58,6 +58,13 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function setIsOpened(bool value_) external isAdmin(msg.sender) { + if (address(registry) == address(0)) { + revert InvalidAddress(); + } + if (address(auction) == address(0)) { + revert InvalidAddress(); + } + registry.setIsOpened(value_, msg.sender); auction.setIsOpened(value_, msg.sender); } @@ -147,6 +154,8 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { auction.clearAuction(tokenId_); + + // TODO update board data } /// @inheritdoc IBillboard diff --git a/src/Billboard/BillboardAuction.sol b/src/Billboard/BillboardAuction.sol index 8afb79f..4940df7 100644 --- a/src/Billboard/BillboardAuction.sol +++ b/src/Billboard/BillboardAuction.sol @@ -53,7 +53,7 @@ contract BillboardAuction is IBillboardAuction { revert InvalidAddress(); } if (value_ != admin) { - revert Unauthorzied("admin"); + revert Unauthorized("admin"); } _; } @@ -66,7 +66,7 @@ contract BillboardAuction is IBillboardAuction { revert InvalidAddress(); } if (msg.sender != operator) { - revert Unauthorzied("operator"); + revert Unauthorized("operator"); } _; } diff --git a/src/Billboard/IBillboardAuction.sol b/src/Billboard/IBillboardAuction.sol index b9bb057..322859d 100644 --- a/src/Billboard/IBillboardAuction.sol +++ b/src/Billboard/IBillboardAuction.sol @@ -14,7 +14,7 @@ interface IBillboardAuction { error OperatorNotFound(); - error Unauthorzied(string type_); + error Unauthorized(string type_); ////////////////////////////// /// Struct From 37baf4ad79507d6f9ae8d98600de4edbec824882 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Fri, 3 Nov 2023 14:22:36 +0800 Subject: [PATCH 03/55] Add test cases for Billboard. --- src/test/Billboard/BillboardTest.t.sol | 98 ++++++++++++++++++++++ src/test/Billboard/BillboardTestBase.t.sol | 48 +++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/test/Billboard/BillboardTest.t.sol create mode 100644 src/test/Billboard/BillboardTestBase.t.sol diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol new file mode 100644 index 0000000..1852a82 --- /dev/null +++ b/src/test/Billboard/BillboardTest.t.sol @@ -0,0 +1,98 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "./BillboardTestBase.t.sol"; + +contract BillboardTest is BillboardTestBase { + ////////////////////////////// + /// Upgradability + ////////////////////////////// + + function testUpgradeAuctionByAttacker() public { + vm.stopPrank(); + vm.prank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + operator.upgradeAuction(ZERO_ADDRESS); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.upgradeAuction(FAKE_CONTRACT); + } + + function testUpgradeRegistryByAttacker() public { + vm.stopPrank(); + vm.prank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + operator.upgradeRegistry(ZERO_ADDRESS); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.upgradeRegistry(FAKE_CONTRACT); + } + + function testSetIsOpened() public { + vm.stopPrank(); + vm.prank(ADMIN); + operator.setIsOpened(true); + + assertEq(true, auction.isOpened()); + assertEq(true, registry.isOpened()); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + auction.setIsOpened(true, ADMIN); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + registry.setIsOpened(true, ADMIN); + } + + function testSetIsOpenedByAttacker() public { + vm.stopPrank(); + vm.prank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.setIsOpened(true); + } + + ////////////////////////////// + /// Board + ////////////////////////////// + + function testMintBoard() public { + vm.stopPrank(); + + // mint + vm.prank(ADMIN); + operator.mintBoard(ADMIN); + assertEq(1, registry.balanceOf(ADMIN)); + + // get board & check data + IBillboardRegistry.Board memory board = operator.getBoard(1); + assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.tenant); + assertEq(0, board.lastHighestBidPrice); + assertEq("", board.name); + assertEq("", board.description); + assertEq("", board.location); + assertEq("", board.contentURI); + assertEq("", board.redirectLink); + + // set properties + + // get board & check data + } + + function testMintBoardByAttacker() public { + // mint + // set properties + // transfer + } + + ////////////////////////////// + /// Auction + ////////////////////////////// + + function testBid() public {} + + function testClearAuction() public {} + + function testBidByAttacker() public {} + + function testClearAuctionByAttacker() public {} +} diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol new file mode 100644 index 0000000..a3e3ca5 --- /dev/null +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -0,0 +1,48 @@ +//SPDX-License-Identifier: Apache-2.0 +pragma solidity ^0.8.20; + +import "forge-std/console2.sol"; +import "forge-std/Test.sol"; +import "forge-std/Vm.sol"; + +import {Billboard} from "../../Billboard/Billboard.sol"; +import {BillboardAuction} from "../../Billboard/BillboardAuction.sol"; +import {BillboardRegistry} from "../../Billboard/BillboardRegistry.sol"; +import {IBillboard} from "../../Billboard/IBillboard.sol"; +import {IBillboardRegistry} from "../../Billboard/IBillboardRegistry.sol"; + +contract BillboardTestBase is Test { + Billboard internal operator; + BillboardAuction internal auction; + BillboardRegistry internal registry; + + uint256 constant TAX_RATE = 1; + + address constant ZERO_ADDRESS = address(0); + /// Deployer and admin could be the same one + address constant ADMIN = address(100); + address constant ATTACKER = address(200); + address constant FAKE_CONTRACT = address(300); + + function setUp() public { + vm.startPrank(ADMIN); + + // deploy operator + operator = new Billboard(); + assertEq(ADMIN, operator.admin()); + address operatorAddress = address(operator); + + // deploy auction + auction = new BillboardAuction(ADMIN, operatorAddress, TAX_RATE); + assertEq(ADMIN, auction.admin()); + assertEq(operatorAddress, auction.operator()); + + // deploy registry + registry = new BillboardRegistry(ADMIN, operatorAddress, "BLBD", "BLBD"); + assertEq(ADMIN, registry.admin()); + assertEq(operatorAddress, registry.operator()); + + operator.upgradeAuction(address(auction)); + operator.upgradeRegistry(address(registry)); + } +} From 29971b518ee71bdc8af930588eeaaca95f655d28 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Fri, 3 Nov 2023 16:04:21 +0800 Subject: [PATCH 04/55] Add test cases realted to board settings. --- .gas-snapshot | 14 ++--- src/test/Billboard/BillboardTest.t.sol | 62 ++++++++++++++++++---- src/test/Billboard/BillboardTestBase.t.sol | 9 ++++ 3 files changed, 68 insertions(+), 17 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 81e75c9..37e518b 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,10 +1,12 @@ BillboardTest:testBid() (gas: 187) BillboardTest:testBidByAttacker() (gas: 188) -BillboardTest:testClearAuction() (gas: 143) +BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testMintBoard() (gas: 177730) -BillboardTest:testMintBoardByAttacker() (gas: 165) +BillboardTest:testMintBoard() (gas: 177764) +BillboardTest:testMintBoardByAttacker() (gas: 20039) +BillboardTest:testSetBoardProperties() (gas: 306443) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 194455) BillboardTest:testSetIsOpened() (gas: 49024) -BillboardTest:testSetIsOpenedByAttacker() (gas: 12302) -BillboardTest:testUpgradeAuctionByAttacker() (gas: 14008) -BillboardTest:testUpgradeRegistryByAttacker() (gas: 13997) \ No newline at end of file +BillboardTest:testSetIsOpenedByAttacker() (gas: 12368) +BillboardTest:testUpgradeAuctionByAttacker() (gas: 13997) +BillboardTest:testUpgradeRegistryByAttacker() (gas: 14063) \ No newline at end of file diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 1852a82..9dcb83e 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -10,7 +10,7 @@ contract BillboardTest is BillboardTestBase { function testUpgradeAuctionByAttacker() public { vm.stopPrank(); - vm.prank(ATTACKER); + vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); operator.upgradeAuction(ZERO_ADDRESS); @@ -20,7 +20,7 @@ contract BillboardTest is BillboardTestBase { function testUpgradeRegistryByAttacker() public { vm.stopPrank(); - vm.prank(ATTACKER); + vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); operator.upgradeRegistry(ZERO_ADDRESS); @@ -30,7 +30,7 @@ contract BillboardTest is BillboardTestBase { function testSetIsOpened() public { vm.stopPrank(); - vm.prank(ADMIN); + vm.startPrank(ADMIN); operator.setIsOpened(true); assertEq(true, auction.isOpened()); @@ -45,7 +45,7 @@ contract BillboardTest is BillboardTestBase { function testSetIsOpenedByAttacker() public { vm.stopPrank(); - vm.prank(ATTACKER); + vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); operator.setIsOpened(true); } @@ -56,9 +56,9 @@ contract BillboardTest is BillboardTestBase { function testMintBoard() public { vm.stopPrank(); + vm.startPrank(ADMIN); // mint - vm.prank(ADMIN); operator.mintBoard(ADMIN); assertEq(1, registry.balanceOf(ADMIN)); @@ -72,16 +72,56 @@ contract BillboardTest is BillboardTestBase { assertEq("", board.location); assertEq("", board.contentURI); assertEq("", board.redirectLink); + } - // set properties + function testMintBoardByAttacker() public { + vm.stopPrank(); + vm.startPrank(ATTACKER); - // get board & check data + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "minter")); + operator.mintBoard(ATTACKER); } - function testMintBoardByAttacker() public { - // mint - // set properties - // transfer + function testSetBoardProperties() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ADMIN); + + operator.setBoardName(1, "name"); + operator.setBoardDescription(1, "description"); + operator.setBoardLocation(1, "location"); + operator.setBoardContentURI(1, "contentURI"); + operator.setBoardRedirectLink(1, "redirect link"); + + IBillboardRegistry.Board memory board = operator.getBoard(1); + assertEq("name", board.name); + assertEq("description", board.description); + assertEq("location", board.location); + assertEq("contentURI", board.contentURI); + assertEq("redirect link", board.redirectLink); + } + + function testSetBoardProprtiesByAttacker() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardName(1, "name"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardDescription(1, "description"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardLocation(1, "location"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); + operator.setBoardContentURI(1, "contentURI"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); + operator.setBoardRedirectLink(1, "redirect link"); } ////////////////////////////// diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index a3e3ca5..ad91cd6 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -45,4 +45,13 @@ contract BillboardTestBase is Test { operator.upgradeAuction(address(auction)); operator.upgradeRegistry(address(registry)); } + + function _mintBoard() public { + vm.stopPrank(); + vm.startPrank(ADMIN); + + // mint + operator.mintBoard(ADMIN); + assertEq(1, registry.balanceOf(ADMIN)); + } } From e555872bf4ecd9f4d9158303e3e8a10b1ef8920c Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Sat, 4 Nov 2023 00:42:49 +0800 Subject: [PATCH 05/55] Add test cases realted to board settings. --- .gas-snapshot | 25 ++-- src/test/Billboard/BillboardTest.t.sol | 163 +++++++++++++++++++-- src/test/Billboard/BillboardTestBase.t.sol | 6 +- 3 files changed, 174 insertions(+), 20 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 37e518b..5324a90 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,12 +1,19 @@ -BillboardTest:testBid() (gas: 187) +BillboardTest:testApprove() (gas: 232) +BillboardTest:testApproveByAttacker() (gas: 253) +BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testMintBoard() (gas: 177764) -BillboardTest:testMintBoardByAttacker() (gas: 20039) -BillboardTest:testSetBoardProperties() (gas: 306443) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 194455) -BillboardTest:testSetIsOpened() (gas: 49024) -BillboardTest:testSetIsOpenedByAttacker() (gas: 12368) -BillboardTest:testUpgradeAuctionByAttacker() (gas: 13997) -BillboardTest:testUpgradeRegistryByAttacker() (gas: 14063) \ No newline at end of file +BillboardTest:testGetTokenURI() (gas: 189047) +BillboardTest:testMintBoard() (gas: 177403) +BillboardTest:testMintBoardByAttacker() (gas: 19766) +BillboardTest:testSetBoardProperties() (gas: 306531) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 194543) +BillboardTest:testSetIsOpened() (gas: 48640) +BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) +BillboardTest:testSetTaxRate() (gas: 27454) +BillboardTest:testSetTaxRateByAttacker() (gas: 11992) +BillboardTest:testTransfer() (gas: 440479) +BillboardTest:testTransferByAttacker() (gas: 191146) +BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) +BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 9dcb83e..095eb40 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -9,8 +9,8 @@ contract BillboardTest is BillboardTestBase { ////////////////////////////// function testUpgradeAuctionByAttacker() public { - vm.stopPrank(); vm.startPrank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); operator.upgradeAuction(ZERO_ADDRESS); @@ -19,8 +19,8 @@ contract BillboardTest is BillboardTestBase { } function testUpgradeRegistryByAttacker() public { - vm.stopPrank(); vm.startPrank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); operator.upgradeRegistry(ZERO_ADDRESS); @@ -29,10 +29,9 @@ contract BillboardTest is BillboardTestBase { } function testSetIsOpened() public { - vm.stopPrank(); vm.startPrank(ADMIN); - operator.setIsOpened(true); + operator.setIsOpened(true); assertEq(true, auction.isOpened()); assertEq(true, registry.isOpened()); @@ -44,8 +43,8 @@ contract BillboardTest is BillboardTestBase { } function testSetIsOpenedByAttacker() public { - vm.stopPrank(); vm.startPrank(ATTACKER); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); operator.setIsOpened(true); } @@ -55,7 +54,6 @@ contract BillboardTest is BillboardTestBase { ////////////////////////////// function testMintBoard() public { - vm.stopPrank(); vm.startPrank(ADMIN); // mint @@ -75,7 +73,6 @@ contract BillboardTest is BillboardTestBase { } function testMintBoardByAttacker() public { - vm.stopPrank(); vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "minter")); @@ -91,14 +88,14 @@ contract BillboardTest is BillboardTestBase { operator.setBoardName(1, "name"); operator.setBoardDescription(1, "description"); operator.setBoardLocation(1, "location"); - operator.setBoardContentURI(1, "contentURI"); + operator.setBoardContentURI(1, "uri"); operator.setBoardRedirectLink(1, "redirect link"); IBillboardRegistry.Board memory board = operator.getBoard(1); assertEq("name", board.name); assertEq("description", board.description); assertEq("location", board.location); - assertEq("contentURI", board.contentURI); + assertEq("uri", board.contentURI); assertEq("redirect link", board.redirectLink); } @@ -118,16 +115,162 @@ contract BillboardTest is BillboardTestBase { operator.setBoardLocation(1, "location"); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - operator.setBoardContentURI(1, "contentURI"); + operator.setBoardContentURI(1, "uri"); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); operator.setBoardRedirectLink(1, "redirect link"); } + function testGetTokenURI() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ADMIN); + + operator.setBoardContentURI(1, "new uri"); + assertEq("new uri", registry.tokenURI(1)); + } + + function testTransfer() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ADMIN); + assertEq(ADMIN, registry.ownerOf(1)); + + // transfer board from admin to user_a + registry.transferFrom(ADMIN, USER_A, 1); + IBillboardRegistry.Board memory board = operator.getBoard(1); + assertEq(ADMIN, board.owner); + assertEq(USER_A, board.tenant); + assertEq(USER_A, registry.ownerOf(1)); + + vm.stopPrank(); + vm.startPrank(USER_A); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardName(1, "name by a"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardDescription(1, "description by a"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardLocation(1, "location by a"); + + operator.setBoardContentURI(1, "uri by a"); + operator.setBoardRedirectLink(1, "redirect link by a"); + + board = operator.getBoard(1); + assertEq("", board.name); + assertEq("", board.description); + assertEq("", board.location); + assertEq("uri by a", board.contentURI); + assertEq("redirect link by a", board.redirectLink); + + // transfer board from user_a to user_b + registry.safeTransferFrom(USER_A, USER_B, 1); + board = operator.getBoard(1); + assertEq(ADMIN, board.owner); + assertEq(USER_B, board.tenant); + assertEq(USER_B, registry.ownerOf(1)); + + vm.stopPrank(); + vm.startPrank(USER_B); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardName(1, "name by b"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardDescription(1, "description by b"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardLocation(1, "location by b"); + + operator.setBoardContentURI(1, "uri by b"); + operator.setBoardRedirectLink(1, "redirect link by b"); + + board = operator.getBoard(1); + assertEq("", board.name); + assertEq("", board.description); + assertEq("", board.location); + assertEq("uri by b", board.contentURI); + assertEq("redirect link by b", board.redirectLink); + + // transfer board from user_b to user_c by operator + vm.stopPrank(); + vm.startPrank(address(operator)); + + registry.transferFrom(USER_B, USER_C, 1); + board = operator.getBoard(1); + assertEq(ADMIN, board.owner); + assertEq(USER_C, board.tenant); + assertEq(USER_C, registry.ownerOf(1)); + + vm.stopPrank(); + vm.startPrank(USER_C); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardName(1, "name by b"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardDescription(1, "description by b"); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + operator.setBoardLocation(1, "location by b"); + + operator.setBoardContentURI(1, "uri by c"); + operator.setBoardRedirectLink(1, "redirect link by c"); + + board = operator.getBoard(1); + assertEq("", board.name); + assertEq("", board.description); + assertEq("", board.location); + assertEq("uri by c", board.contentURI); + assertEq("redirect link by c", board.redirectLink); + } + + function testTransferByAttacker() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); + registry.transferFrom(ADMIN, ATTACKER, 1); + + vm.stopPrank(); + vm.startPrank(ADMIN); + registry.transferFrom(ADMIN, USER_A, 1); + + vm.stopPrank(); + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); + registry.safeTransferFrom(USER_A, ATTACKER, 1); + } + + function testApprove() public {} + + function testApproveByAttacker() public {} + ////////////////////////////// /// Auction ////////////////////////////// + function testSetTaxRate() public { + vm.startPrank(ADMIN); + + operator.setTaxRate(2); + assertEq(2, operator.getTaxRate()); + } + + function testSetTaxRateByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.setTaxRate(2); + } + function testBid() public {} function testClearAuction() public {} diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index ad91cd6..9e6ed88 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -19,10 +19,14 @@ contract BillboardTestBase is Test { uint256 constant TAX_RATE = 1; address constant ZERO_ADDRESS = address(0); + address constant FAKE_CONTRACT = address(1); + /// Deployer and admin could be the same one address constant ADMIN = address(100); + address constant USER_A = address(101); + address constant USER_B = address(102); + address constant USER_C = address(103); address constant ATTACKER = address(200); - address constant FAKE_CONTRACT = address(300); function setUp() public { vm.startPrank(ADMIN); From 1981fed0da32ea5737e733426dc62f265512d090 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Sat, 4 Nov 2023 01:24:12 +0800 Subject: [PATCH 06/55] Add test cases realted to board settings. --- .gas-snapshot | 10 ++++----- src/test/Billboard/BillboardTest.t.sol | 28 ++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 5324a90..e2a184d 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,5 +1,5 @@ -BillboardTest:testApprove() (gas: 232) -BillboardTest:testApproveByAttacker() (gas: 253) +BillboardTest:testApprove() (gas: 195516) +BillboardTest:testApproveByAttacker() (gas: 165756) BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) @@ -7,13 +7,13 @@ BillboardTest:testClearAuctionByAttacker() (gas: 144) BillboardTest:testGetTokenURI() (gas: 189047) BillboardTest:testMintBoard() (gas: 177403) BillboardTest:testMintBoardByAttacker() (gas: 19766) -BillboardTest:testSetBoardProperties() (gas: 306531) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 194543) +BillboardTest:testSetBoardProperties() (gas: 301995) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 185007) BillboardTest:testSetIsOpened() (gas: 48640) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) BillboardTest:testSetTaxRate() (gas: 27454) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 440479) +BillboardTest:testTransfer() (gas: 411882) BillboardTest:testTransferByAttacker() (gas: 191146) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 095eb40..75a3866 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -249,9 +249,33 @@ contract BillboardTest is BillboardTestBase { registry.safeTransferFrom(USER_A, ATTACKER, 1); } - function testApprove() public {} + function testApprove() public { + _mintBoard(); + + vm.stopPrank(); + vm.startPrank(ADMIN); + + registry.approve(USER_A, 1); + assertEq(USER_A, registry.getApproved(1)); + + vm.stopPrank(); + vm.startPrank(USER_A); + registry.transferFrom(ADMIN, USER_A, 1); + + IBillboardRegistry.Board memory board = operator.getBoard(1); + assertEq(ADMIN, board.owner); + assertEq(USER_A, board.tenant); + } + + function testApproveByAttacker() public { + _mintBoard(); - function testApproveByAttacker() public {} + vm.stopPrank(); + vm.startPrank(USER_A); + + vm.expectRevert("ERC721: approve caller is not token owner or approved for all"); + registry.approve(USER_A, 1); + } ////////////////////////////// /// Auction From 4d884746549da0a837dbf1e6b14dd8d1a509c9c5 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:23:37 +0800 Subject: [PATCH 07/55] Change method setBoardRedirectLink to setBoardRedirectURI. --- .gas-snapshot | 18 +++++++++--------- src/Billboard/Billboard.sol | 4 ++-- src/Billboard/BillboardRegistry.sol | 8 ++++---- src/Billboard/IBillboard.sol | 6 +++--- src/Billboard/IBillboardRegistry.sol | 10 +++++----- src/test/Billboard/BillboardTest.t.sol | 20 ++++++++++---------- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e2a184d..9413069 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,19 +1,19 @@ -BillboardTest:testApprove() (gas: 195516) -BillboardTest:testApproveByAttacker() (gas: 165756) +BillboardTest:testApprove() (gas: 195494) +BillboardTest:testApproveByAttacker() (gas: 165734) BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testGetTokenURI() (gas: 189047) -BillboardTest:testMintBoard() (gas: 177403) +BillboardTest:testGetTokenURI() (gas: 189048) +BillboardTest:testMintBoard() (gas: 177381) BillboardTest:testMintBoardByAttacker() (gas: 19766) -BillboardTest:testSetBoardProperties() (gas: 301995) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 185007) -BillboardTest:testSetIsOpened() (gas: 48640) +BillboardTest:testSetBoardProperties() (gas: 302038) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 185050) +BillboardTest:testSetIsOpened() (gas: 48574) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) BillboardTest:testSetTaxRate() (gas: 27454) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 411882) -BillboardTest:testTransferByAttacker() (gas: 191146) +BillboardTest:testTransfer() (gas: 411967) +BillboardTest:testTransferByAttacker() (gas: 191124) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index d24250e..5476c50 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -105,8 +105,8 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function setBoardRedirectLink(uint256 tokenId_, string memory redirectLink_) external { - registry.setBoardRedirectLink(tokenId_, redirectLink_, msg.sender); + function setBoardRedirectURI(uint256 tokenId_, string memory redirectURI_) external { + registry.setBoardRedirectURI(tokenId_, redirectURI_, msg.sender); } ////////////////////////////// diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 7d9e4ed..9efc238 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -115,7 +115,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { name: "", description: "", contentURI: "", - redirectLink: "", + redirectURI: "", location: "" }); boards[newBoardId] = newBoard; @@ -167,12 +167,12 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setBoardRedirectLink( + function setBoardRedirectURI( uint256 tokenId_, - string memory redirectLink_, + string memory redirectURI_, address sender_ ) external isValidBoard(tokenId_) isBoardTenant(tokenId_, sender_) { - boards[tokenId_].redirectLink = redirectLink_; + boards[tokenId_].redirectURI = redirectURI_; } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index a78ec0c..4e6e59f 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -93,12 +93,12 @@ interface IBillboard { function setBoardContentURI(uint256 tokenId_, string memory uri_) external; /** - * @notice Set the redirect link of a board when users clicking. + * @notice Set the redirect URI of a board when users clicking. * * @param tokenId_ Token ID of a board. - * @param redirectLink_ Redirect link of a board. + * @param redirectURI_ Redirect URI of a board. */ - function setBoardRedirectLink(uint256 tokenId_, string memory redirectLink_) external; + function setBoardRedirectURI(uint256 tokenId_, string memory redirectURI_) external; ////////////////////////////// /// Auction diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 65e608e..437cb62 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -40,7 +40,7 @@ interface IBillboardRegistry is IERC721 { string description; string location; string contentURI; - string redirectLink; + string redirectURI; } /** @@ -123,15 +123,15 @@ interface IBillboardRegistry is IERC721 { ) external; /** - * @notice Set the redirect link of a board when users clicking. + * @notice Set the redirect URI of a board when users clicking. * * @param tokenId_ Token ID of a board. - * @param redirectLink_ Redirect link when users clicking. + * @param redirectURI_ Redirect URI when users clicking. * @param sender_ Address of user who wants to set. */ - function setBoardRedirectLink( + function setBoardRedirectURI( uint256 tokenId_, - string memory redirectLink_, + string memory redirectURI_, address sender_ ) external; diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 75a3866..9fb8d5c 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -69,7 +69,7 @@ contract BillboardTest is BillboardTestBase { assertEq("", board.description); assertEq("", board.location); assertEq("", board.contentURI); - assertEq("", board.redirectLink); + assertEq("", board.redirectURI); } function testMintBoardByAttacker() public { @@ -89,14 +89,14 @@ contract BillboardTest is BillboardTestBase { operator.setBoardDescription(1, "description"); operator.setBoardLocation(1, "location"); operator.setBoardContentURI(1, "uri"); - operator.setBoardRedirectLink(1, "redirect link"); + operator.setBoardRedirectURI(1, "redirect URI"); IBillboardRegistry.Board memory board = operator.getBoard(1); assertEq("name", board.name); assertEq("description", board.description); assertEq("location", board.location); assertEq("uri", board.contentURI); - assertEq("redirect link", board.redirectLink); + assertEq("redirect URI", board.redirectURI); } function testSetBoardProprtiesByAttacker() public { @@ -118,7 +118,7 @@ contract BillboardTest is BillboardTestBase { operator.setBoardContentURI(1, "uri"); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - operator.setBoardRedirectLink(1, "redirect link"); + operator.setBoardRedirectURI(1, "redirect URI"); } function testGetTokenURI() public { @@ -158,14 +158,14 @@ contract BillboardTest is BillboardTestBase { operator.setBoardLocation(1, "location by a"); operator.setBoardContentURI(1, "uri by a"); - operator.setBoardRedirectLink(1, "redirect link by a"); + operator.setBoardRedirectURI(1, "redirect URI by a"); board = operator.getBoard(1); assertEq("", board.name); assertEq("", board.description); assertEq("", board.location); assertEq("uri by a", board.contentURI); - assertEq("redirect link by a", board.redirectLink); + assertEq("redirect URI by a", board.redirectURI); // transfer board from user_a to user_b registry.safeTransferFrom(USER_A, USER_B, 1); @@ -187,14 +187,14 @@ contract BillboardTest is BillboardTestBase { operator.setBoardLocation(1, "location by b"); operator.setBoardContentURI(1, "uri by b"); - operator.setBoardRedirectLink(1, "redirect link by b"); + operator.setBoardRedirectURI(1, "redirect URI by b"); board = operator.getBoard(1); assertEq("", board.name); assertEq("", board.description); assertEq("", board.location); assertEq("uri by b", board.contentURI); - assertEq("redirect link by b", board.redirectLink); + assertEq("redirect URI by b", board.redirectURI); // transfer board from user_b to user_c by operator vm.stopPrank(); @@ -219,14 +219,14 @@ contract BillboardTest is BillboardTestBase { operator.setBoardLocation(1, "location by b"); operator.setBoardContentURI(1, "uri by c"); - operator.setBoardRedirectLink(1, "redirect link by c"); + operator.setBoardRedirectURI(1, "redirect URI by c"); board = operator.getBoard(1); assertEq("", board.name); assertEq("", board.description); assertEq("", board.location); assertEq("uri by c", board.contentURI); - assertEq("redirect link by c", board.redirectLink); + assertEq("redirect URI by c", board.redirectURI); } function testTransferByAttacker() public { From ce5b45a0abc2580a891d00c7cd1a039f1ed1cdfe Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:46:37 +0800 Subject: [PATCH 08/55] Remove unnecessary address(0) checker since transaction will be failed. --- .gas-snapshot | 16 ++++++++-------- src/Billboard/Billboard.sol | 7 ------- src/Billboard/BillboardRegistry.sol | 5 ----- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 9413069..587370e 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,19 +1,19 @@ -BillboardTest:testApprove() (gas: 195494) +BillboardTest:testApprove() (gas: 194949) BillboardTest:testApproveByAttacker() (gas: 165734) BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testGetTokenURI() (gas: 189048) -BillboardTest:testMintBoard() (gas: 177381) +BillboardTest:testGetTokenURI() (gas: 188684) +BillboardTest:testMintBoard() (gas: 177200) BillboardTest:testMintBoardByAttacker() (gas: 19766) -BillboardTest:testSetBoardProperties() (gas: 302038) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 185050) -BillboardTest:testSetIsOpened() (gas: 48574) +BillboardTest:testSetBoardProperties() (gas: 300947) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 184150) +BillboardTest:testSetIsOpened() (gas: 48304) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) BillboardTest:testSetTaxRate() (gas: 27454) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 411967) -BillboardTest:testTransferByAttacker() (gas: 191124) +BillboardTest:testTransfer() (gas: 407259) +BillboardTest:testTransferByAttacker() (gas: 190220) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 5476c50..b9568ad 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -58,13 +58,6 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function setIsOpened(bool value_) external isAdmin(msg.sender) { - if (address(registry) == address(0)) { - revert InvalidAddress(); - } - if (address(auction) == address(0)) { - revert InvalidAddress(); - } - registry.setIsOpened(value_, msg.sender); auction.setIsOpened(value_, msg.sender); } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 9efc238..eb8673f 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -41,11 +41,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } modifier isValidBoard(uint256 tokenId_) { - uint256 latestId = tokenIds.current(); - - if (tokenId_ < 1 || tokenId_ > latestId) { - revert InvalidBoardId(); - } if (!_exists(tokenId_)) { revert BoardNotFound(); } From ec152ec79f4f01b037cfb5d209bf5998053d5d4d Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 21:59:46 +0800 Subject: [PATCH 09/55] Add basic assert for auction and registry upgradability. --- .gas-snapshot | 8 ++++---- src/test/Billboard/BillboardTestBase.t.sol | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 587370e..9a138d1 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,19 +1,19 @@ -BillboardTest:testApprove() (gas: 194949) +BillboardTest:testApprove() (gas: 195001) BillboardTest:testApproveByAttacker() (gas: 165734) BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) BillboardTest:testGetTokenURI() (gas: 188684) -BillboardTest:testMintBoard() (gas: 177200) +BillboardTest:testMintBoard() (gas: 177258) BillboardTest:testMintBoardByAttacker() (gas: 19766) -BillboardTest:testSetBoardProperties() (gas: 300947) +BillboardTest:testSetBoardProperties() (gas: 301005) BillboardTest:testSetBoardProprtiesByAttacker() (gas: 184150) BillboardTest:testSetIsOpened() (gas: 48304) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) BillboardTest:testSetTaxRate() (gas: 27454) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 407259) +BillboardTest:testTransfer() (gas: 407583) BillboardTest:testTransferByAttacker() (gas: 190220) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 9e6ed88..8c90848 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -46,8 +46,13 @@ contract BillboardTestBase is Test { assertEq(ADMIN, registry.admin()); assertEq(operatorAddress, registry.operator()); + // upgrade auction operator.upgradeAuction(address(auction)); + assertEq(address(auction), address(operator.auction())); + + // upgrade registry operator.upgradeRegistry(address(registry)); + assertEq(address(registry), address(operator.registry())); } function _mintBoard() public { From 7841bbe3dc7f36cb707dc6a34c80f29e832f9270 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 22:13:30 +0800 Subject: [PATCH 10/55] Rename Board property owner to creator. --- src/Billboard/BillboardRegistry.sol | 14 +++++------ src/Billboard/IBillboardRegistry.sol | 2 +- src/test/Billboard/BillboardTest.t.sol | 34 +++++++++++++------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index eb8673f..90bf5c9 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -47,9 +47,9 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _; } - modifier isBoardOwner(uint256 tokenId_, address value_) { - if (value_ != boards[tokenId_].owner) { - revert Unauthorized("board owner"); + modifier isBoardCreator(uint256 tokenId_, address value_) { + if (value_ != boards[tokenId_].creator) { + revert Unauthorized("board creator"); } _; } @@ -104,7 +104,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _safeMint(to_, newBoardId); Board memory newBoard = Board({ - owner: to_, + creator: to_, tenant: to_, lastHighestBidPrice: 0, name: "", @@ -130,7 +130,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory name_, address sender_ - ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { boards[tokenId_].name = name_; } @@ -139,7 +139,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory description_, address sender_ - ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { boards[tokenId_].description = description_; } @@ -148,7 +148,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory location_, address sender_ - ) external isValidBoard(tokenId_) isBoardOwner(tokenId_, sender_) { + ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { boards[tokenId_].location = location_; } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 437cb62..a6762d7 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -33,7 +33,7 @@ interface IBillboardRegistry is IERC721 { ////////////////////////////// struct Board { - address owner; + address creator; address tenant; uint256 lastHighestBidPrice; string name; diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 9fb8d5c..2273d10 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -62,7 +62,7 @@ contract BillboardTest is BillboardTestBase { // get board & check data IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.creator); assertEq(ADMIN, board.tenant); assertEq(0, board.lastHighestBidPrice); assertEq("", board.name); @@ -105,13 +105,13 @@ contract BillboardTest is BillboardTestBase { vm.stopPrank(); vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardName(1, "name"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardDescription(1, "description"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardLocation(1, "location"); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); @@ -141,20 +141,20 @@ contract BillboardTest is BillboardTestBase { // transfer board from admin to user_a registry.transferFrom(ADMIN, USER_A, 1); IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.creator); assertEq(USER_A, board.tenant); assertEq(USER_A, registry.ownerOf(1)); vm.stopPrank(); vm.startPrank(USER_A); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardName(1, "name by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardDescription(1, "description by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardLocation(1, "location by a"); operator.setBoardContentURI(1, "uri by a"); @@ -170,20 +170,20 @@ contract BillboardTest is BillboardTestBase { // transfer board from user_a to user_b registry.safeTransferFrom(USER_A, USER_B, 1); board = operator.getBoard(1); - assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.creator); assertEq(USER_B, board.tenant); assertEq(USER_B, registry.ownerOf(1)); vm.stopPrank(); vm.startPrank(USER_B); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardName(1, "name by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardDescription(1, "description by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardLocation(1, "location by b"); operator.setBoardContentURI(1, "uri by b"); @@ -202,20 +202,20 @@ contract BillboardTest is BillboardTestBase { registry.transferFrom(USER_B, USER_C, 1); board = operator.getBoard(1); - assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.creator); assertEq(USER_C, board.tenant); assertEq(USER_C, registry.ownerOf(1)); vm.stopPrank(); vm.startPrank(USER_C); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardName(1, "name by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardDescription(1, "description by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board owner")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); operator.setBoardLocation(1, "location by b"); operator.setBoardContentURI(1, "uri by c"); @@ -263,7 +263,7 @@ contract BillboardTest is BillboardTestBase { registry.transferFrom(ADMIN, USER_A, 1); IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.owner); + assertEq(ADMIN, board.creator); assertEq(USER_A, board.tenant); } From 5e989e9351585a6d649dd48c209a8773d177d57d Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 22:30:06 +0800 Subject: [PATCH 11/55] Remove unnecessary address validator from modifiers. --- .gas-snapshot | 22 +++++++++++----------- src/Billboard/BillboardAuction.sol | 3 --- src/Billboard/BillboardRegistry.sol | 3 --- 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 9a138d1..7b3fe98 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,19 +1,19 @@ -BillboardTest:testApprove() (gas: 195001) -BillboardTest:testApproveByAttacker() (gas: 165734) +BillboardTest:testApprove() (gas: 194731) +BillboardTest:testApproveByAttacker() (gas: 165464) BillboardTest:testBid() (gas: 143) BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testGetTokenURI() (gas: 188684) -BillboardTest:testMintBoard() (gas: 177258) -BillboardTest:testMintBoardByAttacker() (gas: 19766) -BillboardTest:testSetBoardProperties() (gas: 301005) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 184150) -BillboardTest:testSetIsOpened() (gas: 48304) +BillboardTest:testGetTokenURI() (gas: 188414) +BillboardTest:testMintBoard() (gas: 176988) +BillboardTest:testMintBoardByAttacker() (gas: 19631) +BillboardTest:testSetBoardProperties() (gas: 300735) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 183880) +BillboardTest:testSetIsOpened() (gas: 47764) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) -BillboardTest:testSetTaxRate() (gas: 27454) +BillboardTest:testSetTaxRate() (gas: 27319) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 407583) -BillboardTest:testTransferByAttacker() (gas: 190220) +BillboardTest:testTransfer() (gas: 407313) +BillboardTest:testTransferByAttacker() (gas: 189950) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/Billboard/BillboardAuction.sol b/src/Billboard/BillboardAuction.sol index 4940df7..0e87978 100644 --- a/src/Billboard/BillboardAuction.sol +++ b/src/Billboard/BillboardAuction.sol @@ -59,9 +59,6 @@ contract BillboardAuction is IBillboardAuction { } modifier isFromOperator() { - if (operator == address(0)) { - revert OperatorNotFound(); - } if (msg.sender == address(0)) { revert InvalidAddress(); } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 90bf5c9..a2cff2a 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -75,9 +75,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } modifier isFromOperator() { - if (operator == address(0)) { - revert OperatorNotFound(); - } if (msg.sender == address(0)) { revert InvalidAddress(); } From 7c28cf241db0716a5739108226cd873fe1246a95 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Tue, 7 Nov 2023 22:43:59 +0800 Subject: [PATCH 12/55] Add more test cases for transferring and minting. --- .gas-snapshot | 4 ++-- src/test/Billboard/BillboardTest.t.sol | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 7b3fe98..a552063 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -5,7 +5,7 @@ BillboardTest:testBidByAttacker() (gas: 188) BillboardTest:testClearAuction() (gas: 210) BillboardTest:testClearAuctionByAttacker() (gas: 144) BillboardTest:testGetTokenURI() (gas: 188414) -BillboardTest:testMintBoard() (gas: 176988) +BillboardTest:testMintBoard() (gas: 282572) BillboardTest:testMintBoardByAttacker() (gas: 19631) BillboardTest:testSetBoardProperties() (gas: 300735) BillboardTest:testSetBoardProprtiesByAttacker() (gas: 183880) @@ -13,7 +13,7 @@ BillboardTest:testSetIsOpened() (gas: 47764) BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) BillboardTest:testSetTaxRate() (gas: 27319) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 407313) +BillboardTest:testTransfer() (gas: 409630) BillboardTest:testTransferByAttacker() (gas: 189950) BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 2273d10..32ba717 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -70,6 +70,13 @@ contract BillboardTest is BillboardTestBase { assertEq("", board.location); assertEq("", board.contentURI); assertEq("", board.redirectURI); + + // mint again for checking id generator + operator.mintBoard(ADMIN); + assertEq(2, registry.balanceOf(ADMIN)); + board = operator.getBoard(2); + assertEq(ADMIN, board.creator); + assertEq(ADMIN, board.tenant); } function testMintBoardByAttacker() public { @@ -138,6 +145,10 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); assertEq(ADMIN, registry.ownerOf(1)); + // transfer board from admin to zero address + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + registry.transferFrom(ADMIN, ZERO_ADDRESS, 1); + // transfer board from admin to user_a registry.transferFrom(ADMIN, USER_A, 1); IBillboardRegistry.Board memory board = operator.getBoard(1); From fb23fb47817703a54ab56dd0091ec682bf1eba12 Mon Sep 17 00:00:00 2001 From: Zeck Li <11781254+zeckli@users.noreply.github.com> Date: Wed, 8 Nov 2023 01:20:24 +0800 Subject: [PATCH 13/55] Add white list for basic access control. --- .gas-snapshot | 40 ++++++++++--------- src/Billboard/Billboard.sol | 12 ++++++ src/Billboard/BillboardAuction.sol | 27 +++++++++++++ src/Billboard/BillboardRegistry.sol | 27 ++++++++++++- src/Billboard/IBillboard.sol | 14 +++++++ src/Billboard/IBillboardAuction.sol | 16 ++++++++ src/Billboard/IBillboardRegistry.sol | 16 ++++++++ src/test/Billboard/BillboardTest.t.sol | 55 +++++++++++++++++++++++++- 8 files changed, 186 insertions(+), 21 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index a552063..cdac718 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,19 +1,23 @@ -BillboardTest:testApprove() (gas: 194731) -BillboardTest:testApproveByAttacker() (gas: 165464) -BillboardTest:testBid() (gas: 143) -BillboardTest:testBidByAttacker() (gas: 188) -BillboardTest:testClearAuction() (gas: 210) -BillboardTest:testClearAuctionByAttacker() (gas: 144) -BillboardTest:testGetTokenURI() (gas: 188414) -BillboardTest:testMintBoard() (gas: 282572) -BillboardTest:testMintBoardByAttacker() (gas: 19631) -BillboardTest:testSetBoardProperties() (gas: 300735) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 183880) -BillboardTest:testSetIsOpened() (gas: 47764) -BillboardTest:testSetIsOpenedByAttacker() (gas: 11962) -BillboardTest:testSetTaxRate() (gas: 27319) +BillboardTest:testAddToWhitelist() (gas: 102721) +BillboardTest:testAddToWhitelistByAttacker() (gas: 11980) +BillboardTest:testApprove() (gas: 196706) +BillboardTest:testApproveByAttacker() (gas: 167482) +BillboardTest:testBid() (gas: 188) +BillboardTest:testBidByAttacker() (gas: 166) +BillboardTest:testClearAuction() (gas: 188) +BillboardTest:testClearAuctionByAttacker() (gas: 167) +BillboardTest:testGetTokenURI() (gas: 190476) +BillboardTest:testMintBoard() (gas: 284718) +BillboardTest:testMintBoardByAttacker() (gas: 21681) +BillboardTest:testRemoveToWhitelist() (gas: 72724) +BillboardTest:testRemoveToWhitelistByAttacker() (gas: 11981) +BillboardTest:testSetBoardProperties() (gas: 302887) +BillboardTest:testSetBoardProprtiesByAttacker() (gas: 186054) +BillboardTest:testSetIsOpened() (gas: 47920) +BillboardTest:testSetIsOpenedByAttacker() (gas: 11940) +BillboardTest:testSetTaxRate() (gas: 27363) BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 409630) -BillboardTest:testTransferByAttacker() (gas: 189950) -BillboardTest:testUpgradeAuctionByAttacker() (gas: 13591) -BillboardTest:testUpgradeRegistryByAttacker() (gas: 13657) \ No newline at end of file +BillboardTest:testTransfer() (gas: 411852) +BillboardTest:testTransferByAttacker() (gas: 192057) +BillboardTest:testUpgradeAuctionByAttacker() (gas: 13636) +BillboardTest:testUpgradeRegistryByAttacker() (gas: 13635) \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index b9568ad..cf026e1 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -62,6 +62,18 @@ contract Billboard is IBillboard { auction.setIsOpened(value_, msg.sender); } + /// @inheritdoc IBillboard + function addToWhitelist(address value_) external isAdmin(msg.sender) { + registry.addToWhitelist(value_, msg.sender); + auction.addToWhitelist(value_, msg.sender); + } + + /// @inheritdoc IBillboard + function removeFromWhitelist(address value_) external isAdmin(msg.sender) { + registry.removeFromWhitelist(value_, msg.sender); + auction.removeFromWhitelist(value_, msg.sender); + } + ////////////////////////////// /// Board ////////////////////////////// diff --git a/src/Billboard/BillboardAuction.sol b/src/Billboard/BillboardAuction.sol index 0e87978..4cfa0a2 100644 --- a/src/Billboard/BillboardAuction.sol +++ b/src/Billboard/BillboardAuction.sol @@ -12,6 +12,8 @@ contract BillboardAuction is IBillboardAuction { uint256 public taxRate; + mapping(address => bool) public whitelist; + mapping(uint256 => Auction) public auctions; mapping(uint256 => address[]) public bidders; @@ -32,6 +34,7 @@ contract BillboardAuction is IBillboardAuction { admin = admin_; operator = operator_; taxRate = taxRate_; + whitelist[admin_] = true; } ////////////////////////////// @@ -73,6 +76,26 @@ contract BillboardAuction is IBillboardAuction { isOpened = value_; } + /// @inheritdoc IBillboardAuction + function addToWhitelist(address value_, address sender_) + external + isValidAddress(value_) + isAdmin(sender_) + isFromOperator + { + whitelist[value_] = true; + } + + /// @inheritdoc IBillboardAuction + function removeFromWhitelist(address value_, address sender_) + external + isValidAddress(value_) + isAdmin(sender_) + isFromOperator + { + delete whitelist[value_]; + } + /// @inheritdoc IBillboardAuction function setTaxRate(uint256 taxRate_, address sender_) external isAdmin(sender_) isFromOperator { taxRate = taxRate_; @@ -89,6 +112,10 @@ contract BillboardAuction is IBillboardAuction { uint256 amount_, address sender_ ) external isFromOperator isAdmin(sender_) { + if (isOpened == false && whitelist[sender_] != true) { + revert Unauthorized("bidder"); + } + // TODO } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index a2cff2a..0a0fbbc 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -17,6 +17,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address public operator; + mapping(address => bool) public whitelist; + mapping(uint256 => Board) public boards; constructor( @@ -27,6 +29,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ) ERC721(name_, symbol_) { admin = admin_; operator = operator_; + whitelist[admin_] = true; } ////////////////////////////// @@ -89,10 +92,30 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { isOpened = value_; } + /// @inheritdoc IBillboardRegistry + function addToWhitelist(address value_, address sender_) + external + isValidAddress(value_) + isAdmin(sender_) + isFromOperator + { + whitelist[value_] = true; + } + + /// @inheritdoc IBillboardRegistry + function removeFromWhitelist(address value_, address sender_) + external + isValidAddress(value_) + isAdmin(sender_) + isFromOperator + { + delete whitelist[value_]; + } + /// @inheritdoc IBillboardRegistry function mint(address to_, address sender_) external isValidAddress(to_) isFromOperator returns (uint256 tokenId) { - if (isOpened == false && sender_ != admin) { - revert Unauthorized("minter"); + if (isOpened == false && whitelist[sender_] != true) { + revert Unauthorized("creator"); } tokenIds.increment(); diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 4e6e59f..e781084 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -40,6 +40,20 @@ interface IBillboard { */ function setIsOpened(bool value_) external; + /** + * @notice Add address to white list. + * + * @param value_ Address of user will be added into white list. + */ + function addToWhitelist(address value_) external; + + /** + * @notice Remove address from white list. + * + * @param value_ Address of user will be removed from white list. + */ + function removeFromWhitelist(address value_) external; + ////////////////////////////// /// Board ////////////////////////////// diff --git a/src/Billboard/IBillboardAuction.sol b/src/Billboard/IBillboardAuction.sol index 322859d..9dee33c 100644 --- a/src/Billboard/IBillboardAuction.sol +++ b/src/Billboard/IBillboardAuction.sol @@ -43,6 +43,22 @@ interface IBillboardAuction { */ function setIsOpened(bool value_, address sender_) external; + /** + * @notice Add address to white list. + * + * @param value_ Address of user will be added into white list. + * @param sender_ Address of user who wants to update white list. + */ + function addToWhitelist(address value_, address sender_) external; + + /** + * @notice Remove address from white list. + * + * @param value_ Address of user will be removed from white list. + * @param sender_ Address of user who wants to update white list. + */ + function removeFromWhitelist(address value_, address sender_) external; + /** * @notice Set the global tax rate. * diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index a6762d7..2d42f74 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -51,6 +51,22 @@ interface IBillboardRegistry is IERC721 { */ function setIsOpened(bool value_, address sender_) external; + /** + * @notice Add address to white list. + * + * @param value_ Address of user will be added into white list. + * @param sender_ Address of user who wants to update white list. + */ + function addToWhitelist(address value_, address sender_) external; + + /** + * @notice Remove address from white list. + * + * @param value_ Address of user will be removed from white list. + * @param sender_ Address of user who wants to update white list. + */ + function removeFromWhitelist(address value_, address sender_) external; + /** * @notice Mint a new board (NFT). * diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 32ba717..26cf9fd 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -49,6 +49,59 @@ contract BillboardTest is BillboardTestBase { operator.setIsOpened(true); } + function testAddToWhitelist() public { + vm.startPrank(ADMIN); + + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + operator.addToWhitelist(ZERO_ADDRESS); + + operator.addToWhitelist(USER_A); + assertEq(registry.whitelist(USER_A), true); + assertEq(registry.whitelist(USER_B), false); + assertEq(auction.whitelist(USER_A), true); + assertEq(auction.whitelist(USER_B), false); + + // not allow bypassing operator + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + registry.addToWhitelist(USER_A, ADMIN); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + auction.addToWhitelist(USER_A, ADMIN); + } + + function testAddToWhitelistByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.addToWhitelist(USER_A); + } + + function testRemoveToWhitelist() public { + vm.startPrank(ADMIN); + + operator.addToWhitelist(USER_A); + assertEq(registry.whitelist(USER_A), true); + + vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + operator.removeFromWhitelist(ZERO_ADDRESS); + + operator.removeFromWhitelist(USER_A); + assertEq(registry.whitelist(USER_A), false); + assertEq(auction.whitelist(USER_A), false); + + // not allow bypassing operator + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + registry.removeFromWhitelist(USER_A, ADMIN); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + auction.removeFromWhitelist(USER_A, ADMIN); + } + + function testRemoveToWhitelistByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.removeFromWhitelist(USER_B); + } + ////////////////////////////// /// Board ////////////////////////////// @@ -82,7 +135,7 @@ contract BillboardTest is BillboardTestBase { function testMintBoardByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "minter")); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); operator.mintBoard(ATTACKER); } From 6428a1644bf1f55cd868e4d0502f3148d6043a77 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sat, 11 Nov 2023 23:18:55 +0800 Subject: [PATCH 14/55] feat(billboard): revise interface --- .gitignore | 2 + .husky/pre-commit | 4 +- src/Billboard/Billboard.sol | 38 ++---- src/Billboard/BillboardAuction.sol | 173 ------------------------ src/Billboard/BillboardRegistry.sol | 68 ++++------ src/Billboard/IBillboard.sol | 124 ++++++++++++++--- src/Billboard/IBillboardAuction.sol | 154 --------------------- src/Billboard/IBillboardRegistry.sol | 193 ++++++++++++++++++--------- 8 files changed, 270 insertions(+), 486 deletions(-) delete mode 100644 src/Billboard/BillboardAuction.sol delete mode 100644 src/Billboard/IBillboardAuction.sol diff --git a/.gitignore b/.gitignore index 1f9dc5e..0af2550 100644 --- a/.gitignore +++ b/.gitignore @@ -121,3 +121,5 @@ out/ .env.* !.env.*.example + +TODO \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index 8ebc7dd..dc41503 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,4 +1,6 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npx lint-staged && make snapshot && git add .gas-snapshot \ No newline at end of file +npx lint-staged + +# && make snapshot && git add .gas-snapshot \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index cf026e1..52c3e37 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -1,17 +1,13 @@ //SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import "./BillboardAuction.sol"; import "./BillboardRegistry.sol"; import "./IBillboard.sol"; -import "./IBillboardAuction.sol"; import "./IBillboardRegistry.sol"; contract Billboard is IBillboard { address public admin; - BillboardAuction public auction; - BillboardRegistry public registry; constructor() { @@ -30,12 +26,6 @@ contract Billboard is IBillboard { } modifier isAdmin(address value_) { - if (admin == address(0)) { - revert AdminNotFound(); - } - if (value_ == address(0)) { - revert InvalidAddress(); - } if (value_ != admin) { revert Unauthorized("admin"); } @@ -46,11 +36,6 @@ contract Billboard is IBillboard { /// Upgradability ////////////////////////////// - /// @inheritdoc IBillboard - function upgradeAuction(address contract_) external isValidAddress(contract_) isAdmin(msg.sender) { - auction = BillboardAuction(contract_); - } - /// @inheritdoc IBillboard function upgradeRegistry(address contract_) external isValidAddress(contract_) isAdmin(msg.sender) { registry = BillboardRegistry(contract_); @@ -59,19 +44,16 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function setIsOpened(bool value_) external isAdmin(msg.sender) { registry.setIsOpened(value_, msg.sender); - auction.setIsOpened(value_, msg.sender); } /// @inheritdoc IBillboard function addToWhitelist(address value_) external isAdmin(msg.sender) { registry.addToWhitelist(value_, msg.sender); - auction.addToWhitelist(value_, msg.sender); } /// @inheritdoc IBillboard function removeFromWhitelist(address value_) external isAdmin(msg.sender) { registry.removeFromWhitelist(value_, msg.sender); - auction.removeFromWhitelist(value_, msg.sender); } ////////////////////////////// @@ -81,7 +63,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external isValidAddress(to_) { uint256 tokenId = registry.mint(to_, msg.sender); - auction.initTreasury(tokenId); + registry.initTreasury(tokenId); } /// @inheritdoc IBillboard @@ -120,22 +102,22 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function setTaxRate(uint256 taxRate_) external isAdmin(msg.sender) { - auction.setTaxRate(taxRate_, msg.sender); + registry.setTaxRate(taxRate_, msg.sender); } /// @inheritdoc IBillboard function getTaxRate() external view returns (uint256 taxRate) { - return auction.taxRate(); + return registry.taxRate(); } /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external { - auction.placeBid(tokenId_, amount_, msg.sender); + registry.placeBid(tokenId_, amount_, msg.sender); } /// @inheritdoc IBillboard - function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardAuction.Bid memory bid) { - return auction.getBid(tokenId_, bidder_); + function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid) { + return registry.getBid(tokenId_, bidder_); } /// @inheritdoc IBillboard @@ -150,21 +132,21 @@ contract Billboard is IBillboard { uint256 total, uint256 limit, uint256 offset, - IBillboardAuction.Bid[] memory bids + IBillboardRegistry.Bid[] memory bids ) { - return auction.getBidsByBoard(tokenId_, limit_, offset_); + return registry.getBidsByBoard(tokenId_, limit_, offset_); } /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { - auction.clearAuction(tokenId_); + registry.clearAuction(tokenId_); // TODO update board data } /// @inheritdoc IBillboard function withdraw(uint256 tokenId_) external { - auction.withdraw(tokenId_, msg.sender); + registry.withdraw(tokenId_, msg.sender); } } diff --git a/src/Billboard/BillboardAuction.sol b/src/Billboard/BillboardAuction.sol deleted file mode 100644 index 4cfa0a2..0000000 --- a/src/Billboard/BillboardAuction.sol +++ /dev/null @@ -1,173 +0,0 @@ -//SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.20; - -import "./IBillboardAuction.sol"; - -contract BillboardAuction is IBillboardAuction { - bool public isOpened = false; - - address public admin; - - address public operator; - - uint256 public taxRate; - - mapping(address => bool) public whitelist; - - mapping(uint256 => Auction) public auctions; - - mapping(uint256 => address[]) public bidders; - - mapping(uint256 => mapping(address => Bid)) public currentBids; - - mapping(uint256 => Bid) public currentHighestBids; - - mapping(uint256 => uint256) public lockedTaxations; - - mapping(uint256 => Treasury) public treasuries; - - constructor( - address admin_, - address operator_, - uint256 taxRate_ - ) { - admin = admin_; - operator = operator_; - taxRate = taxRate_; - whitelist[admin_] = true; - } - - ////////////////////////////// - /// Modifier - ////////////////////////////// - - modifier isValidAddress(address value_) { - if (value_ == address(0)) { - revert InvalidAddress(); - } - _; - } - - modifier isAdmin(address value_) { - if (admin == address(0)) { - revert AdminNotFound(); - } - if (value_ == address(0)) { - revert InvalidAddress(); - } - if (value_ != admin) { - revert Unauthorized("admin"); - } - _; - } - - modifier isFromOperator() { - if (msg.sender == address(0)) { - revert InvalidAddress(); - } - if (msg.sender != operator) { - revert Unauthorized("operator"); - } - _; - } - - /// @inheritdoc IBillboardAuction - function setIsOpened(bool value_, address sender_) external isAdmin(sender_) isFromOperator { - isOpened = value_; - } - - /// @inheritdoc IBillboardAuction - function addToWhitelist(address value_, address sender_) - external - isValidAddress(value_) - isAdmin(sender_) - isFromOperator - { - whitelist[value_] = true; - } - - /// @inheritdoc IBillboardAuction - function removeFromWhitelist(address value_, address sender_) - external - isValidAddress(value_) - isAdmin(sender_) - isFromOperator - { - delete whitelist[value_]; - } - - /// @inheritdoc IBillboardAuction - function setTaxRate(uint256 taxRate_, address sender_) external isAdmin(sender_) isFromOperator { - taxRate = taxRate_; - } - - /// @inheritdoc IBillboardAuction - function initTreasury(uint256 tokenId_) external isFromOperator { - // TODO - } - - /// @inheritdoc IBillboardAuction - function placeBid( - uint256 tokenId_, - uint256 amount_, - address sender_ - ) external isFromOperator isAdmin(sender_) { - if (isOpened == false && whitelist[sender_] != true) { - revert Unauthorized("bidder"); - } - - // TODO - } - - /// @inheritdoc IBillboardAuction - function getBid(uint256 tokenId_, address bidder_) external view isValidAddress(bidder_) returns (Bid memory bid) { - return currentBids[tokenId_][bidder_]; - } - - /// @inheritdoc IBillboardAuction - function getBidsByBoard( - uint256 tokenId_, - uint256 limit_, - uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - Bid[] memory bids - ) - { - // TODO - } - - /// @inheritdoc IBillboardAuction - function initAuction(uint256 tokenId_) external isFromOperator { - // TODO - } - - /// @inheritdoc IBillboardAuction - function getAuction(uint256 tokenId_) external view returns (Auction memory auction) { - return auctions[tokenId_]; - } - - /// @inheritdoc IBillboardAuction - function clearAuction(uint256 tokenId_) external { - // TODO - } - - /** - * @notice Refund to bidders who are not winning auction of a board. - * - * @param tokenId_ Token ID of a board. - */ - function _refund(uint256 tokenId_) internal { - // TODO - } - - /// @inheritdoc IBillboardAuction - function withdraw(uint256 tokenId_, address sender_) external { - // TODO - } -} diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 0a0fbbc..742d626 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -9,18 +9,26 @@ import "./IBillboardRegistry.sol"; contract BillboardRegistry is IBillboardRegistry, ERC721 { using Counters for Counters.Counter; - Counters.Counter private tokenIds; - + // access control bool public isOpened = false; - address public admin; - address public operator; - mapping(address => bool) public whitelist; + Counters.Counter private _tokenIds; + + // tokenId => Board mapping(uint256 => Board) public boards; + // tokenId => auctionId => Auction + mapping(uint256 => mapping(uint256 => Auction)) public boardAuctions; + + // tokenId => lastAuctionId + mapping(uint256 => uint256) public lastBoardAuctionId; + + // board creator => TaxTreasury + mapping(address => TaxTreasury) public taxTreasury; + constructor( address admin_, address operator_, @@ -43,13 +51,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _; } - modifier isValidBoard(uint256 tokenId_) { - if (!_exists(tokenId_)) { - revert BoardNotFound(); - } - _; - } - modifier isBoardCreator(uint256 tokenId_, address value_) { if (value_ != boards[tokenId_].creator) { revert Unauthorized("board creator"); @@ -65,12 +66,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } modifier isAdmin(address value_) { - if (admin == address(0)) { - revert AdminNotFound(); - } - if (value_ == address(0)) { - revert InvalidAddress(); - } if (value_ != admin) { revert Unauthorized("admin"); } @@ -78,9 +73,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } modifier isFromOperator() { - if (msg.sender == address(0)) { - revert InvalidAddress(); - } if (msg.sender != operator) { revert Unauthorized("operator"); } @@ -118,8 +110,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { revert Unauthorized("creator"); } - tokenIds.increment(); - uint256 newBoardId = tokenIds.current(); + _tokenIds.increment(); + uint256 newBoardId = _tokenIds.current(); _safeMint(to_, newBoardId); @@ -141,7 +133,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function getBoard(uint256 tokenId_) external view isValidBoard(tokenId_) returns (Board memory board) { + function getBoard(uint256 tokenId_) external view returns (Board memory board) { return boards[tokenId_]; } @@ -150,7 +142,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory name_, address sender_ - ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { + ) external isBoardCreator(tokenId_, sender_) { boards[tokenId_].name = name_; } @@ -159,7 +151,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory description_, address sender_ - ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { + ) external isBoardCreator(tokenId_, sender_) { boards[tokenId_].description = description_; } @@ -168,7 +160,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory location_, address sender_ - ) external isValidBoard(tokenId_) isBoardCreator(tokenId_, sender_) { + ) external isBoardCreator(tokenId_, sender_) { boards[tokenId_].location = location_; } @@ -177,7 +169,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory uri_, address sender_ - ) external isValidBoard(tokenId_) isBoardTenant(tokenId_, sender_) { + ) external isBoardTenant(tokenId_, sender_) { boards[tokenId_].contentURI = uri_; } @@ -186,16 +178,12 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, string memory redirectURI_, address sender_ - ) external isValidBoard(tokenId_) isBoardTenant(tokenId_, sender_) { + ) external isBoardTenant(tokenId_, sender_) { boards[tokenId_].redirectURI = redirectURI_; } /// @inheritdoc IBillboardRegistry - function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) - external - isValidBoard(tokenId_) - isFromOperator - { + function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) external isFromOperator { boards[tokenId_].lastHighestBidPrice = price_; } @@ -206,13 +194,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /** * @notice See {IERC721-tokenURI}. */ - function tokenURI(uint256 tokenId_) - public - view - override(ERC721) - isValidBoard(tokenId_) - returns (string memory uri) - { + function tokenURI(uint256 tokenId_) public view override(ERC721) returns (string memory uri) { return boards[tokenId_].contentURI; } @@ -234,7 +216,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address from_, address to_, uint256 tokenId_ - ) public override(ERC721, IERC721) isValidBoard(tokenId_) { + ) public override(ERC721, IERC721) { safeTransferFrom(from_, to_, tokenId_, ""); } @@ -246,7 +228,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address to_, uint256 tokenId_, bytes memory data_ - ) public override(ERC721, IERC721) isValidAddress(from_) isValidAddress(to_) isValidBoard(tokenId_) { + ) public override(ERC721, IERC721) isValidAddress(from_) isValidAddress(to_) { if (!_isApprovedOrOwner(msg.sender, tokenId_)) { revert Unauthorized("not owner nor approved"); } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index e781084..0703df1 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -1,7 +1,6 @@ //SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import "./IBillboardAuction.sol"; import "./IBillboardRegistry.sol"; interface IBillboard { @@ -19,13 +18,6 @@ interface IBillboard { /// Upgradability ////////////////////////////// - /** - * @notice Switch the auction logic contract to another one. - * - * @param contract_ Address of new auction logic contract. - */ - function upgradeAuction(address contract_) external; - /** * @notice Switch the registry logic contract to another one. * @@ -33,6 +25,10 @@ interface IBillboard { */ function upgradeRegistry(address contract_) external; + ////////////////////////////// + /// Access control + ////////////////////////////// + /** * @notice Toggle for operation access. * @@ -119,18 +115,36 @@ interface IBillboard { ////////////////////////////// /** - * @notice Set the global tax rate. + * @notice Get last cleared auction of a board. * - * @param taxRate_ Tax rate. + * @param tokenId_ Token ID of a board. */ - function setTaxRate(uint256 taxRate_) external; + function getAuction(uint256 tokenId_) external view returns (IBillboardRegistry.Auction memory auction); /** - * @notice Get the global tax rate. + * @notice Get auction of a board by auction ID. * - * @return taxRate Tax rate. + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of a board. */ - function getTaxRate() external view returns (uint256 taxRate); + function getAuction(uint256 tokenId_, uint256 auctionId_) + external + view + returns (IBillboardRegistry.Auction memory auction); + + /** + * @notice Clear a board auction. + * + * 1. update Board.auctionId + * 2. update Auction.startAt, endAt + * 3. update Bid.isWon + * 4. transfer bid price to last Auction.higghestBidder + * 5. transfer bid tax to TaxTreasury + * ... + * + * @param tokenId_ Token ID of a board. + */ + function clearAuction(uint256 tokenId_) external; /** * @notice Place bid for a board. @@ -141,17 +155,32 @@ interface IBillboard { function placeBid(uint256 tokenId_, uint256 amount_) external; /** - * @notice Get a bid of a board. + * @notice Get bid of a board auction. * * @param tokenId_ Token ID of a board. * @param bidder_ Address of a bidder. * * @return bid Bid of a board. */ - function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardAuction.Bid memory bid); + function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid); /** - * @notice Get bids of a board. + * @notice Get bid of a board auction by auction ID. + * + * @param tokenId_ Token ID of a board. + * @param bidder_ Address of a bidder. + * @param auctionId_ Auction ID of a board. + * + * @return bid Bid of a board. + */ + function getBid( + uint256 tokenId_, + address bidder_, + uint256 auctionId_ + ) external view returns (IBillboardRegistry.Bid memory bid); + + /** + * @notice Get bids of a board auction. * * @param tokenId_ Token ID of a board. * @param limit_ Limit of returned bids. @@ -173,20 +202,73 @@ interface IBillboard { uint256 total, uint256 limit, uint256 offset, - IBillboardAuction.Bid[] memory bids + IBillboardRegistry.Bid[] memory bids ); /** - * @notice Clear a board auction. + * @notice Get bids of a board auction by auction ID. * * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of a board. + * @param limit_ Limit of returned bids. + * @param offset_ Offset of returned bids. + * + * @return total Total number of bids. + * @return limit Limit of returned bids. + * @return offset Offset of returned bids. + * @return bids Bids of a board. */ - function clearAuction(uint256 tokenId_) external; + function getBidsByBoard( + uint256 tokenId_, + uint256 auctionId_, + uint256 limit_, + uint256 offset_ + ) + external + view + returns ( + uint256 total, + uint256 limit, + uint256 offset, + IBillboardRegistry.Bid[] memory bids + ); + + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// + + /** + * @notice Set the global tax rate. + * + * @param taxRate_ Tax rate. + */ + function setTaxRate(uint256 taxRate_) external; + + /** + * @notice Get the global tax rate. + * + * @return taxRate Tax rate. + */ + function getTaxRate() external view returns (uint256 taxRate); /** * @notice Withdraw accumulated taxation of a board. * * @param tokenId_ Token ID of a board. + * @param owner_ Address of a treasury owner. */ - function withdraw(uint256 tokenId_) external; + function withdrawTax(uint256 tokenId_, address owner_) external; + + /** + * @notice Withdraw bid that were not won by auction id; + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of a board. + * @param bidder_ Address of a auction bidder. + */ + function withdrawBid( + uint256 tokenId_, + uint256 auctionId_, + address bidder_ + ) external; } diff --git a/src/Billboard/IBillboardAuction.sol b/src/Billboard/IBillboardAuction.sol deleted file mode 100644 index 9dee33c..0000000 --- a/src/Billboard/IBillboardAuction.sol +++ /dev/null @@ -1,154 +0,0 @@ -//SPDX-License-Identifier: Apache-2.0 -pragma solidity ^0.8.20; - -interface IBillboardAuction { - ////////////////////////////// - /// Error - ////////////////////////////// - - error AdminNotFound(); - - error AuctionNotFound(); - - error InvalidAddress(); - - error OperatorNotFound(); - - error Unauthorized(string type_); - - ////////////////////////////// - /// Struct - ////////////////////////////// - - struct Auction { - uint256 startBlock; - uint256 endBlock; - } - - struct Bid { - uint256 atBlock; - uint256 amount; - } - - struct Treasury { - address owner; - uint256 amount; - } - - /** - * @notice Toggle for operation access. - * - * @param value_ Value of access state. - * @param sender_ Address of user who wants to set. - */ - function setIsOpened(bool value_, address sender_) external; - - /** - * @notice Add address to white list. - * - * @param value_ Address of user will be added into white list. - * @param sender_ Address of user who wants to update white list. - */ - function addToWhitelist(address value_, address sender_) external; - - /** - * @notice Remove address from white list. - * - * @param value_ Address of user will be removed from white list. - * @param sender_ Address of user who wants to update white list. - */ - function removeFromWhitelist(address value_, address sender_) external; - - /** - * @notice Set the global tax rate. - * - * @param taxRate_ Tax rate. - * @param sender_ Address of user who wants to set. - */ - function setTaxRate(uint256 taxRate_, address sender_) external; - - /** - * @notice Initialize a treasury when a new board minted. - * - * @param tokenId_ Token ID of a board. - */ - function initTreasury(uint256 tokenId_) external; - - /** - * @notice Place bid for a board. - * - * @param tokenId_ Token ID of a board. - * @param amount_ Amount of a bid. - * @param sender_ Address of user who wants to bid. - */ - function placeBid( - uint256 tokenId_, - uint256 amount_, - address sender_ - ) external; - - /** - * @notice Place bid for a board. - * - * @param tokenId_ Token ID of a board. - * @param bidder_ Address of a bidder. - * - * @return bid Bid of a board. - */ - function getBid(uint256 tokenId_, address bidder_) external view returns (Bid memory bid); - - /** - * @notice Get bids of a board. - * - * @param tokenId_ Token ID of a board. - * @param limit_ Limit of returned bids. - * @param offset_ Offset of returned bids. - * - * @return total Total number of bids. - * @return limit Limit of returned bids. - * @return offset Offset of returned bids. - * @return bids Bids of a board. - */ - function getBidsByBoard( - uint256 tokenId_, - uint256 limit_, - uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - Bid[] memory bids - ); - - /** - * @notice Initialize a new auction of a board. - * - * @param tokenId_ Token ID of a board. - */ - function initAuction(uint256 tokenId_) external; - - /** - * @notice Get the current auction of a board if it exists. - * - * @param tokenId_ Token ID of a board. - */ - function getAuction(uint256 tokenId_) external view returns (Auction memory auction); - - /** - * @notice Clear a board auction. - * - * @param tokenId_ Token ID of a board. - */ - function clearAuction(uint256 tokenId_) external; - - /** - * @notice Withdraw accumulated taxation of a board. - * - * @param tokenId_ Token ID of a board. - * @param sender_ Address of user wants to withdraw. - */ - function withdraw(uint256 tokenId_, address sender_) external; -} diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 2d42f74..4e1b890 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -24,9 +24,15 @@ interface IBillboardRegistry is IERC721 { /// Event ////////////////////////////// - event Mint(uint256 indexed tokenId_, address to_); - - event Transfer(uint256 indexed tokenId_, address from_, address to_); + // TODO + // mint & transfer (no need, inherted from ERC721) + // set board (name, uris, etc.) + // set tax rate + // new auction + // clear auction + // new bid + // withdraw bid + // withdraw tax ////////////////////////////// /// Struct @@ -34,8 +40,7 @@ interface IBillboardRegistry is IERC721 { struct Board { address creator; - address tenant; - uint256 lastHighestBidPrice; + uint256 auctionId; // last cleared auction ID string name; string description; string location; @@ -43,119 +48,175 @@ interface IBillboardRegistry is IERC721 { string redirectURI; } - /** - * @notice Toggle for operation access. - * - * @param value_ Value of access state. - * @param sender_ Address of user who wants to set. - */ - function setIsOpened(bool value_, address sender_) external; + struct Auction { + uint256 tokenId; + uint256 startAt; // timestamp + uint256 endAt; // timestamp + address highestBidder; + address[] bidders; + mapping(address => Bid) bids; + } - /** - * @notice Add address to white list. - * - * @param value_ Address of user will be added into white list. - * @param sender_ Address of user who wants to update white list. - */ - function addToWhitelist(address value_, address sender_) external; + struct Bid { + address bidder; + uint256 price; + uint256 tax; + uint256 auctionId; + uint256 placedAt; // timestamp + bool isWon; + bool isWithdrawn; + } - /** - * @notice Remove address from white list. - * - * @param value_ Address of user will be removed from white list. - * @param sender_ Address of user who wants to update white list. - */ - function removeFromWhitelist(address value_, address sender_) external; + struct TaxTreasury { + address owner; + uint256 accumulated; + uint256 withdrawn; + } + + ////////////////////////////// + /// Board + ////////////////////////////// /** * @notice Mint a new board (NFT). * * @param to_ Address of the new board receiver. - * @param sender_ Address of user who wants to mint. * * @return tokenId Token ID of the new board. */ - function mint(address to_, address sender_) external returns (uint256 tokenId); + function mintBoard(address to_) external returns (uint256 tokenId); /** - * @notice Get a board data. + * @notice Set the name, description and location of a board. * * @param tokenId_ Token ID of a board. - * - * @return board Board data. + * @param name_ Board name. + * @param description_ Board description. + * @param location_ Digital address where a board located. */ - function getBoard(uint256 tokenId_) external view returns (Board memory board); + function setBoard( + uint256 tokenId_, + string memory name_, + string memory description_, + string memory location_ + ) external; /** - * @notice Set the name of a board. + * @notice Set the content URI and redirect URI of a board. * * @param tokenId_ Token ID of a board. - * @param name_ Board name. - * @param sender_ Address of user who wants to set. + * @param contentUri_ Content URI of a board. + * @param redirectURI_ Redirect URI when users clicking. */ - function setBoardName( + function setBoard( uint256 tokenId_, - string memory name_, - address sender_ + string memory contentUri_, + string memory redirectUri_ ) external; + ////////////////////////////// + /// Auction + ////////////////////////////// + /** - * @notice Set the description of a board. + * @notice Create new auction * * @param tokenId_ Token ID of a board. - * @param description_ Board description. - * @param sender_ Address of user who wants to set. + * @param startAt_ Start time of an auction. + * @param endAt_ End time of an auction. */ - function setBoardDescription( + function newAuction( uint256 tokenId_, - string memory description_, - address sender_ - ) external; + uint256 startAt_, + uint256 endAt_ + ) external returns (uint256 auctionId_); /** - * @notice Set the location of a board. + * @notice Set the data of an auction * * @param tokenId_ Token ID of a board. - * @param location_ Digital address where a board located. - * @param sender_ Address of user who wants to set. + * @param auctionId_ Token ID of a board. + * @param startAt_ Start time of an auction. + * @param endAt_ End time of an auction. */ - function setBoardLocation( + function setAuction( uint256 tokenId_, - string memory location_, - address sender_ + uint256 auctionId_, + uint256 startAt_, + uint256 endAt_ ) external; /** - * @notice Set the content URI of a board. + * @notice Create new bid and add it to auction + * + * 1. Create new bid: `new Bid()` + * 2. Add bid to auction: + * - `auction.bids[bidder] = bid` + * - `auction.bidders.push(bidder)` + * - if any `auction.highestBidder = bidder` * * @param tokenId_ Token ID of a board. - * @param uri_ Content URI of a board. - * @param sender_ Address of user who wants to set. + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of an auction. + * @param price_ Price of a bid. + * @param tax_ Tax of a bid. */ - function setBoardContentURI( + function newBid( uint256 tokenId_, - string memory uri_, - address sender_ + uint256 auctionId_, + address bidder_, + uint256 price_, + uint256 tax_ ) external; /** - * @notice Set the redirect URI of a board when users clicking. + * @notice Set the data of a bid * * @param tokenId_ Token ID of a board. - * @param redirectURI_ Redirect URI when users clicking. - * @param sender_ Address of user who wants to set. + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of an auction. + * @param isWon_ Whether a bid is won. */ - function setBoardRedirectURI( + function setBid( uint256 tokenId_, - string memory redirectURI_, - address sender_ + uint256 auctionId_, + address bidder_, + bool isWon, + bool isWithdrawn ) external; /** - * @notice Update the last highest bid price of a board. + * @notice Transfer amount of bid price to current board owner (last auction highest bidder) * * @param tokenId_ Token ID of a board. - * @param price_ Bid price. + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of the highest bid. + * @param to_ Address of a receiver. */ - function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) external; + function transferBidAmount( + uint256 tokenId_, + uint256 auctionId_, + address bidder_, + address to_ + ) external; + + /** + * @notice Set the global tax rate. + * + * @param taxRate_ Tax rate. + */ + function setTaxRate(uint256 taxRate_) external; + + /** + * @notice Set the tax treasury. + * + * @param owner_ Address of a treasury owner. + * @param accumulated_ Accumulated tax. + * @param withdrawn_ Withdrawn tax. + */ + function setTaxTreasury( + address owner_, + uint256 accumulated_, + uint256 withdrawn_ + ) external; } From b19e8b652d40dbcf0f603669777e13ce537df494 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 12 Nov 2023 11:53:37 +0800 Subject: [PATCH 15/55] feat(billboard): impls of BillboardRegistry --- .prettierrc | 1 + package-lock.json | 8595 +++++++++++--------------- package.json | 22 +- src/Billboard/Billboard.sol | 63 +- src/Billboard/BillboardRegistry.sol | 180 +- src/Billboard/IBillboard.sol | 36 +- src/Billboard/IBillboardRegistry.sol | 68 +- src/Curation/Curation.sol | 7 +- src/Curation/ICuration.sol | 7 +- src/Logbook/ILogbook.sol | 6 +- src/Logbook/Logbook.sol | 20 +- src/Snapper/Snapper.sol | 6 +- src/TheSpace/ACLManager.sol | 6 +- src/TheSpace/ITheSpace.sol | 17 +- src/TheSpace/ITheSpaceRegistry.sol | 43 +- src/TheSpace/SpaceToken.sol | 8 +- src/TheSpace/TheSpace.sol | 38 +- src/TheSpace/TheSpaceRegistry.sol | 49 +- src/test/Curation/Curation.t.sol | 12 +- src/test/Curation/USDT.sol | 2 +- src/test/Logbook/Logbook.t.sol | 12 +- src/test/Logbook/LogbookNFTSVG.t.sol | 6 +- src/test/TheSpace/BaseTheSpace.t.sol | 12 +- src/test/TheSpace/TheSpace.t.sol | 16 +- 24 files changed, 3913 insertions(+), 5319 deletions(-) diff --git a/.prettierrc b/.prettierrc index a3b7506..3a174cc 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,7 @@ { "tabWidth": 2, "printWidth": 120, + "plugins": ["prettier-plugin-solidity"], "overrides": [ { "files": "*.sol", diff --git a/package-lock.json b/package-lock.json index 41a5fb4..3e05b0f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,754 +9,234 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "@openzeppelin/contracts": "^4.5.0" + "@openzeppelin/contracts": "^5.0.0" }, "devDependencies": { - "@types/node": "^17.0.21", - "ethers": "^5.6.1", - "ganache": "^7.0.3", - "husky": "^7.0.4", - "lint-staged": "^12.3.5", - "prettier": "^2.5.1", - "prettier-plugin-solidity": "^1.0.0-beta.19", - "solc-0.8": "npm:solc@^0.8.12", - "solhint": "^3.3.7", - "solhint-plugin-prettier": "^0.0.5", - "solidity-docgen": "^0.5.16" + "@types/node": "^20.9.0", + "ethers": "^6.8.1", + "husky": "^8.0.3", + "lint-staged": "^15.1.0", + "prettier": "^3.0.3", + "prettier-plugin-solidity": "^1.2.0", + "solc-0.8": "npm:solc@^0.8.23", + "solhint": "^4.0.0", + "solhint-plugin-prettier": "^0.1.0", + "solidity-docgen": "^0.5.17" } }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", + "dev": true + }, "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@ethersproject/abi": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.0.tgz", - "integrity": "sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" - } - }, - "node_modules/@ethersproject/abstract-provider": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", - "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0" - } - }, - "node_modules/@ethersproject/abstract-signer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", - "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0" - } - }, - "node_modules/@ethersproject/address": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", - "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.0" - } - }, - "node_modules/@ethersproject/base64": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", - "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0" - } - }, - "node_modules/@ethersproject/basex": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", - "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/properties": "^5.6.0" - } - }, - "node_modules/@ethersproject/bignumber": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", - "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "bn.js": "^4.11.9" - } - }, - "node_modules/@ethersproject/bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.0.tgz", - "integrity": "sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.6.0" - } - }, - "node_modules/@ethersproject/constants": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", - "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.6.0" - } - }, - "node_modules/@ethersproject/contracts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", - "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abi": "^5.6.0", - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0" + "node": ">=4" } }, - "node_modules/@ethersproject/hash": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", - "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/hdnode": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", - "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" - } - }, - "node_modules/@ethersproject/json-wallets": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", - "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "node_modules/@ethersproject/keccak256": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", - "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "js-sha3": "0.8.0" + "engines": { + "node": ">=0.8.0" } }, - "node_modules/@ethersproject/logger": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", - "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ] - }, - "node_modules/@ethersproject/networks": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.0.tgz", - "integrity": "sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ==", + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.6.0" + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/pbkdf2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", - "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/sha2": "^5.6.0" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/properties": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", - "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/logger": "^5.6.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@ethersproject/providers": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.1.tgz", - "integrity": "sha512-w8Wx15nH+aVDvnoKCyI1f3x0B5idmk/bDJXMEUqCfdO8Eadd0QpDx9lDMTMmenhOmf9vufLJXjpSm24D3ZnVpg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "node_modules/@ethersproject/random": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", - "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0" + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@ethersproject/rlp": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", - "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0" + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "hash.js": "1.1.7" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/signing-key": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.0.tgz", - "integrity": "sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==", + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "bn.js": "^4.11.9", - "elliptic": "6.5.4", - "hash.js": "1.1.7" + "engines": { + "node": ">=0.8.0" } }, - "node_modules/@ethersproject/solidity": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", - "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/strings": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", - "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/@ethersproject/transactions": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", - "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0" + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@ethersproject/units": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", - "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@ethersproject/wallet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", - "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "dependencies": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/json-wallets": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" - } - }, - "node_modules/@ethersproject/web": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", - "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, "dependencies": { - "@ethersproject/base64": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@ethersproject/wordlists": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", - "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", + "node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], "dependencies": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/@nodelib/fs.scandir": { @@ -795,17 +275,18 @@ } }, "node_modules/@oclif/command": { - "version": "1.8.16", - "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.16.tgz", - "integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==", + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.36.tgz", + "integrity": "sha512-/zACSgaYGtAQRzc7HjzrlIs14FuEYAZrMOEwicRoUnZVyRunG4+t5iSEeQu0Xy2bgbCD0U1SP/EdeNZSTXRwjQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { "@oclif/config": "^1.18.2", - "@oclif/errors": "^1.3.5", + "@oclif/errors": "^1.3.6", "@oclif/help": "^1.0.1", - "@oclif/parser": "^3.8.6", + "@oclif/parser": "^3.8.17", "debug": "^4.1.1", - "semver": "^7.3.2" + "semver": "^7.5.4" }, "engines": { "node": ">=12.0.0" @@ -815,60 +296,354 @@ } }, "node_modules/@oclif/config": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.3.tgz", - "integrity": "sha512-sBpko86IrTscc39EvHUhL+c++81BVTsIZ3ETu/vG+cCdi0N6vb2DoahR67A9FI2CGnxRRHjnTfa3m6LulwNATA==", + "version": "1.18.17", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.17.tgz", + "integrity": "sha512-k77qyeUvjU8qAJ3XK3fr/QVAqsZO8QOBuESnfeM5HHtPNLSyfVcwiMM2zveSW5xRdLSG3MfV8QnLVkuyCL2ENg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { - "@oclif/errors": "^1.3.5", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", + "@oclif/errors": "^1.3.6", + "@oclif/parser": "^3.8.17", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-wsl": "^2.1.1", - "tslib": "^2.3.1" + "tslib": "^2.6.1" }, "engines": { "node": ">=8.0.0" } }, + "node_modules/@oclif/config/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/@oclif/core": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz", + "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==", + "dev": true, + "dependencies": { + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", + "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", + "indent-string": "^4.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", + "widest-line": "^3.1.0", + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@oclif/core/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/core/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@oclif/core/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@oclif/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@oclif/core/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@oclif/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@oclif/core/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@oclif/core/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/core/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@oclif/core/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/@oclif/core/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/core/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/@oclif/core/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@oclif/core/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@oclif/errors": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.5.tgz", - "integrity": "sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.6.tgz", + "integrity": "sha512-fYaU4aDceETd89KXP+3cLyg9EHZsLD3RxF2IU9yxahhBpspWjkWi3Dy3bTgcwZ3V47BgxQaGapzJWDM33XIVDQ==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "dependencies": { + "clean-stack": "^3.0.0", + "fs-extra": "^8.1", + "indent-string": "^4.0.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@oclif/errors/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@oclif/errors/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@oclif/errors/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "clean-stack": "^3.0.0", - "fs-extra": "^8.1", - "indent-string": "^4.0.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=8.0.0" + "node": ">=7.0.0" } }, - "node_modules/@oclif/errors/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@oclif/errors/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@oclif/errors/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/@oclif/errors/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/@oclif/errors/node_modules/clean-stack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", - "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", + "node_modules/@oclif/errors/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "escape-string-regexp": "4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/@oclif/errors/node_modules/strip-ansi": { @@ -883,14 +658,32 @@ "node": ">=8" } }, + "node_modules/@oclif/errors/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@oclif/help": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oclif/help/-/help-1.0.1.tgz", - "integrity": "sha512-8rsl4RHL5+vBUAKBL6PFI3mj58hjPCp2VYyXD4TAa7IMStikFfOH2gtWmqLzIlxAED2EpD0dfYwo9JJxYsH7Aw==", + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@oclif/help/-/help-1.0.15.tgz", + "integrity": "sha512-Yt8UHoetk/XqohYX76DfdrUYLsPKMc5pgkzsZVHDyBSkLiGRzujVaGZdjr32ckVZU9q3a47IjhWxhip7Dz5W/g==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { - "@oclif/config": "1.18.2", - "@oclif/errors": "1.3.5", + "@oclif/config": "1.18.16", + "@oclif/errors": "1.3.6", "chalk": "^4.1.2", "indent-string": "^4.0.0", "lodash": "^4.17.21", @@ -904,17 +697,18 @@ } }, "node_modules/@oclif/help/node_modules/@oclif/config": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", - "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "version": "1.18.16", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.16.tgz", + "integrity": "sha512-VskIxVcN22qJzxRUq+raalq6Q3HUde7sokB7/xk5TqRZGEKRVbFeqdQBxDWwQeudiJEgcNiMvIFbMQ43dY37FA==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", + "@oclif/errors": "^1.3.6", + "@oclif/parser": "^3.8.16", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-wsl": "^2.1.1", - "tslib": "^2.0.0" + "tslib": "^2.6.1" }, "engines": { "node": ">=8.0.0" @@ -960,6 +754,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@oclif/help/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@oclif/help/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/@oclif/help/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1013,6 +825,12 @@ "node": ">=8" } }, + "node_modules/@oclif/help/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/@oclif/help/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -1034,15 +852,16 @@ "dev": true }, "node_modules/@oclif/parser": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.7.tgz", - "integrity": "sha512-b11xBmIUK+LuuwVGJpFs4LwQN2xj2cBWj2c4z1FtiXGrJ85h9xV6q+k136Hw0tGg1jQoRXuvuBnqQ7es7vO9/Q==", + "version": "3.8.17", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.17.tgz", + "integrity": "sha512-l04iSd0xoh/16TGVpXb81Gg3z7tlQGrEup16BrVLsZBK6SEYpYHRJZnM32BwZrHI97ZSFfuSwVlzoo6HdsaK8A==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "dependencies": { - "@oclif/errors": "^1.3.5", + "@oclif/errors": "^1.3.6", "@oclif/linewrap": "^1.0.0", "chalk": "^4.1.0", - "tslib": "^2.3.1" + "tslib": "^2.6.2" }, "engines": { "node": ">=8.0.0" @@ -1079,6 +898,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@oclif/parser/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@oclif/parser/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/@oclif/parser/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1091,176 +928,161 @@ "node": ">=8" } }, + "node_modules/@oclif/parser/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/@oclif/plugin-help": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", - "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "version": "5.2.20", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-5.2.20.tgz", + "integrity": "sha512-u+GXX/KAGL9S10LxAwNUaWdzbEBARJ92ogmM7g3gDVud2HioCmvWQCDohNRVZ9GYV9oKwZ/M8xwd6a1d95rEKQ==", "dev": true, "dependencies": { - "@oclif/command": "^1.8.15", - "@oclif/config": "1.18.2", - "@oclif/errors": "1.3.5", - "@oclif/help": "^1.0.1", - "chalk": "^4.1.2", - "indent-string": "^4.0.0", - "lodash": "^4.17.21", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0" + "@oclif/core": "^2.15.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, - "node_modules/@oclif/plugin-help/node_modules/@oclif/config": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", - "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", - "dev": true, - "dependencies": { - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-wsl": "^2.1.1", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=8.0.0" - } + "node_modules/@openzeppelin/contracts": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.0.tgz", + "integrity": "sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==" }, - "node_modules/@oclif/plugin-help/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12.22.0" } }, - "node_modules/@oclif/plugin-help/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", "dev": true, "dependencies": { - "color-convert": "^2.0.1" + "graceful-fs": "4.2.10" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12.22.0" } }, - "node_modules/@oclif/plugin-help/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=12" } }, - "node_modules/@oclif/plugin-help/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/@oclif/plugin-help/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/@prettier/sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.3.0.tgz", + "integrity": "sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==", "dev": true, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" + }, + "peerDependencies": { + "prettier": "^3.0.0" } }, - "node_modules/@oclif/plugin-help/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@oclif/plugin-help/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/@solidity-parser/parser": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "antlr4ts": "^0.5.0-alpha.4" } }, - "node_modules/@oclif/plugin-help/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "defer-to-connect": "^2.0.1" }, "engines": { - "node": ">=8" + "node": ">=14.16" } }, - "node_modules/@oclif/plugin-help/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/cli-progress": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.5.tgz", + "integrity": "sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" + "@types/node": "*" } }, - "node_modules/@openzeppelin/contracts": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz", - "integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==" + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true }, - "node_modules/@solidity-parser/parser": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.1.tgz", - "integrity": "sha512-eLjj2L6AuQjBB6s/ibwCAc0DwrR5Ge+ys+wgWo+bviU7fV2nTMQhU63CGaDKXg9iTmMxwhkyoggdIR7ZGRfMgw==", + "node_modules/@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, "dependencies": { - "antlr4ts": "^0.5.0-alpha.4" + "undici-types": "~5.26.4" } }, - "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true - }, "node_modules/acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1269,34 +1091,21 @@ "node": ">=0.4.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "engines": { + "node": ">=0.4.0" } }, "node_modules/aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=", + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", "dev": true }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1314,33 +1123,36 @@ } }, "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", "dev": true, "dependencies": { - "type-fest": "^0.21.3" + "type-fest": "^1.0.2" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, "engines": { "node": ">=12" @@ -1349,26 +1161,38 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", "dev": true }, + "node_modules/antlr4": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", + "dev": true, + "engines": { + "node": ">=16" + } + }, "node_modules/antlr4ts": { "version": "0.5.0-alpha.4", "resolved": "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz", "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", "dev": true }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "node_modules/array-union": { "version": "2.1.0", @@ -1394,24 +1218,18 @@ "node": ">=8" } }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true - }, - "node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1434,138 +1252,166 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } }, - "node_modules/caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "dependencies": { - "callsites": "^2.0.0" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=14.16" } }, - "node_modules/caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "caller-callsite": "^2.0.0" - }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "node_modules/cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" }, - "engines": { - "node": ">=4" + "bin": { + "cdl": "bin/cdl.js" } }, - "node_modules/chalk/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chalk/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "node_modules/clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "escape-string-regexp": "4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chalk/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/chalk/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, + "dependencies": { + "restore-cursor": "^4.0.0" + }, "engines": { - "node": ">=0.8.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", "dev": true, + "dependencies": { + "string-width": "^4.2.3" + }, "engines": { "node": ">=4" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "node_modules/cli-progress/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "node_modules/cli-progress/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "node_modules/cli-progress/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/cli-progress/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-progress/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "restore-cursor": "^3.1.0" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -1587,34 +1433,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "node_modules/command-exists": { @@ -1638,21 +1475,48 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "node_modules/cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "dependencies": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1668,9 +1532,9 @@ } }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1684,272 +1548,118 @@ } } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/emoji-regex": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", - "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", - "dev": true - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^6.14.0 || ^8.10.0 || >=9.10.0" - } - }, - "node_modules/eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=4.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true, "engines": { - "node": ">=4" + "node": ">=4.0.0" } }, - "node_modules/eslint/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/eslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "bin": { - "semver": "bin/semver" + "engines": { + "node": ">=0.3.1" } }, - "node_modules/eslint/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "dependencies": { - "shebang-regex": "^1.0.0" + "path-type": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/eslint/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "dev": true, + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/eslint/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "is-arrayish": "^0.2.1" } }, - "node_modules/espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - }, "engines": { - "node": ">=6.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/esprima": { @@ -1965,75 +1675,15 @@ "node": ">=4" } }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ethers": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.1.tgz", - "integrity": "sha512-qtl/2W+dwmUa5Z3JqwsbV3JEBZZHNARe5K/A2ePcNAuhJYnEKIgGOT/O9ouPwBijSqVoQnmQMzi5D48LFNOY2A==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.1.tgz", + "integrity": "sha512-iEKm6zox5h1lDn6scuRWdIdFJUCGg3+/aQWu0F4K0GVyEZiktFkqrJbRjTn1FlYEPz7RKA707D6g5Kdk6j7Ljg==", "dev": true, "funding": [ { "type": "individual", - "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + "url": "https://github.com/sponsors/ethers-io/" }, { "type": "individual", @@ -2041,75 +1691,53 @@ } ], "dependencies": { - "@ethersproject/abi": "5.6.0", - "@ethersproject/abstract-provider": "5.6.0", - "@ethersproject/abstract-signer": "5.6.0", - "@ethersproject/address": "5.6.0", - "@ethersproject/base64": "5.6.0", - "@ethersproject/basex": "5.6.0", - "@ethersproject/bignumber": "5.6.0", - "@ethersproject/bytes": "5.6.0", - "@ethersproject/constants": "5.6.0", - "@ethersproject/contracts": "5.6.0", - "@ethersproject/hash": "5.6.0", - "@ethersproject/hdnode": "5.6.0", - "@ethersproject/json-wallets": "5.6.0", - "@ethersproject/keccak256": "5.6.0", - "@ethersproject/logger": "5.6.0", - "@ethersproject/networks": "5.6.0", - "@ethersproject/pbkdf2": "5.6.0", - "@ethersproject/properties": "5.6.0", - "@ethersproject/providers": "5.6.1", - "@ethersproject/random": "5.6.0", - "@ethersproject/rlp": "5.6.0", - "@ethersproject/sha2": "5.6.0", - "@ethersproject/signing-key": "5.6.0", - "@ethersproject/solidity": "5.6.0", - "@ethersproject/strings": "5.6.0", - "@ethersproject/transactions": "5.6.0", - "@ethersproject/units": "5.6.0", - "@ethersproject/wallet": "5.6.0", - "@ethersproject/web": "5.6.0", - "@ethersproject/wordlists": "5.6.0" + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" } }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=16.17" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2123,9 +1751,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2144,52 +1772,43 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" } }, - "node_modules/figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=4" + "minimatch": "^5.0.1" } }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, - "engines": { - "node": ">=0.8.0" + "dependencies": { + "balanced-match": "^1.0.0" } }, - "node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "dependencies": { - "flat-cache": "^2.0.1" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=10" } }, "node_modules/fill-range": { @@ -2204,26 +1823,6 @@ "node": ">=8" } }, - "node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, "node_modules/follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", @@ -2240,294 +1839,55 @@ }, "peerDependenciesMeta": { "debug": { - "optional": true - } - } - }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/ganache": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.0.3.tgz", - "integrity": "sha512-1O4V38YkAFd2B1YfBevauEepxEtoN0iTTK02SUJPUIcLOnxwrR49lSDq7liKpUWLkoZCOC2Bkrz/+XJAmEoNAQ==", - "dev": true, - "hasShrinkwrap": true, - "dependencies": { - "@trufflesuite/bigint-buffer": "1.1.9", - "emittery": "0.10.0", - "keccak": "3.0.1", - "leveldown": "6.1.0", - "secp256k1": "4.0.2" - }, - "bin": { - "ganache": "dist/node/cli.js", - "ganache-cli": "dist/node/cli.js" - }, - "optionalDependencies": { - "bufferutil": "4.0.5", - "utf-8-validate": "5.0.7" - } - }, - "node_modules/ganache/node_modules/@trufflesuite/bigint-buffer": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz", - "integrity": "sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw==", - "dev": true, - "dependencies": { - "node-gyp-build": "4.3.0" - } - }, - "node_modules/ganache/node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "node_modules/ganache/node_modules/bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "node_modules/ganache/node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "node_modules/ganache/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/ganache/node_modules/bufferutil": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", - "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "dev": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - } - }, - "node_modules/ganache/node_modules/catering": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", - "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", - "dev": true, - "dependencies": { - "queue-tick": "^1.0.0" - } - }, - "node_modules/ganache/node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/ganache/node_modules/emittery": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", - "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", - "dev": true - }, - "node_modules/ganache/node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/ganache/node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/ganache/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "node_modules/ganache/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ganache/node_modules/is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, - "node_modules/ganache/node_modules/keccak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", - "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "dev": true, - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "node_modules/ganache/node_modules/leveldown": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", - "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", - "dev": true, - "dependencies": { - "abstract-leveldown": "^7.2.0", - "napi-macros": "~2.0.0", - "node-gyp-build": "^4.3.0" + "optional": true + } } }, - "node_modules/ganache/node_modules/leveldown/node_modules/abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", "dev": true, - "dependencies": { - "buffer": "^6.0.3", - "catering": "^2.0.0", - "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" + "engines": { + "node": ">= 14.17" } }, - "node_modules/ganache/node_modules/leveldown/node_modules/level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "dependencies": { - "catering": "^2.1.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" } }, - "node_modules/ganache/node_modules/leveldown/node_modules/level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", - "dev": true - }, - "node_modules/ganache/node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/ganache/node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "node_modules/ganache/node_modules/napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", - "dev": true - }, - "node_modules/ganache/node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "dev": true - }, - "node_modules/ganache/node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "dev": true - }, - "node_modules/ganache/node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "node_modules/ganache/node_modules/queue-tick": { + "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", - "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "node_modules/ganache/node_modules/secp256k1": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", - "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", - "dev": true, - "dependencies": { - "elliptic": "^6.5.2", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "node_modules/ganache/node_modules/utf-8-validate": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", - "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "optional": true, - "dependencies": { - "node-gyp-build": "^4.3.0" + "engines": { + "node": ">=8.0.0" } }, "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2565,15 +1925,6 @@ "node": ">= 6" } }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -2594,19 +1945,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, "engines": { - "node": ">= 4" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/handlebars": { @@ -2639,92 +2018,81 @@ "node": ">=8" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" } }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=16.17.0" } }, "node_modules/husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", "dev": true, "bin": { "husky": "lib/bin.js" }, "engines": { - "node": ">=12" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/typicode" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/indent-string": { @@ -2752,173 +2120,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "dependencies": { - "restore-cursor": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "dependencies": { - "mimic-fn": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "dependencies": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/inquirer/node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/string-width/node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/inquirer/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/strip-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/inquirer/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "node_modules/is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", @@ -2937,7 +2150,7 @@ "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" @@ -2964,48 +2177,127 @@ "is-extglob": "^2.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dev": true, + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.12.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/is-stream": { + "node_modules/jake/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "color-name": "~1.1.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "node_modules/jake/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "is-docker": "^2.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, "node_modules/js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -3019,22 +2311,27 @@ "dev": true }, "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "node_modules/json-schema-traverse": { @@ -3043,12 +2340,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, "node_modules/json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -3067,12 +2358,21 @@ "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -3082,298 +2382,130 @@ "graceful-fs": "^4.1.9" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "package-json": "^8.1.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, "engines": { "node": ">=10" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/lint-staged": { - "version": "12.3.5", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.5.tgz", - "integrity": "sha512-oOH36RUs1It7b9U/C7Nl/a0sLfoIBcMB8ramiB3nuJ6brBqzsWiUAFSR5DQ3yyP/OR7XKMpijtgKl2DV1lQ3lA==", - "dev": true, - "dependencies": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.16", - "commander": "^8.3.0", - "debug": "^4.3.3", - "execa": "^5.1.1", - "lilconfig": "2.0.4", - "listr2": "^4.0.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "object-inspect": "^1.12.0", - "string-argv": "^0.3.1", - "supports-color": "^9.2.1", - "yaml": "^1.10.2" + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", + "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", + "dev": true, + "dependencies": { + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "2.1.0", + "listr2": "7.0.2", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" }, "bin": { "lint-staged": "bin/lint-staged.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18.12.0" }, "funding": { "url": "https://opencollective.com/lint-staged" } }, - "node_modules/listr2": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.4.tgz", - "integrity": "sha512-vJOm5KD6uZXjSsrwajr+mNacIjf87gWvlBEltPWLbTkslUscWAzquyK4xfe9Zd4RDgO5nnwFyV06FC+uVR+5mg==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.4", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/listr2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/listr2/node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/listr2/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/listr2/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/listr2/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/listr2/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-update/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "node_modules/lint-staged/node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" + "node": ">=16" } }, - "node_modules/log-update/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/listr2": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", "dev": true, "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "cli-truncate": "^3.1.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^5.0.1", + "rfdc": "^1.3.0", + "wrap-ansi": "^8.1.0" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/log-update": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lru-cache": { @@ -3388,6 +2520,12 @@ "node": ">=10" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -3413,38 +2551,41 @@ } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/minimatch": { "version": "3.1.2", @@ -3464,35 +2605,35 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "node_modules/mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true + "node_modules/n": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/n/-/n-9.2.0.tgz", + "integrity": "sha512-R8mFN2OWwNVc+r1f9fDzcT34DnDwUIHskrpTesZ6SdluaXBBnRtTu5tlfaSPloBi1Z/eGJoPO9nhyawWPad5UQ==", + "dev": true, + "os": [ + "!win32" + ], + "bin": { + "n": "bin/n" + }, + "engines": { + "node": "*" + } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true + "node_modules/natural-orderby": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", + "integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==", + "dev": true, + "engines": { + "node": "*" + } }, "node_modules/neo-async": { "version": "2.6.2", @@ -3500,40 +2641,52 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", "dev": true, + "engines": { + "node": ">=12" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "dev": true, + "engines": { + "node": ">= 10" } }, "node_modules/once": { @@ -3546,37 +2699,20 @@ } }, "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "dependencies": { - "mimic-fn": "^2.1.0" + "mimic-fn": "^4.0.0" }, "engines": { - "node": ">=6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", @@ -3586,16 +2722,28 @@ "node": ">=0.10.0" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "dev": true, "dependencies": { - "aggregate-error": "^3.0.0" + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3613,26 +2761,59 @@ "node": ">=6" } }, - "node_modules/parent-module/node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, "engines": { - "node": ">=6" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "node_modules/password-prompt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", + "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==", "dev": true, "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "ansi-escapes": "^4.3.2", + "cross-spawn": "^7.0.3" + } + }, + "node_modules/password-prompt/node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/password-prompt/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/path-is-absolute": { @@ -3644,12 +2825,6 @@ "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -3680,25 +2855,40 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/prettier-linter-helpers": { @@ -3714,88 +2904,32 @@ } }, "node_modules/prettier-plugin-solidity": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", - "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.2.0.tgz", + "integrity": "sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.14.0", - "emoji-regex": "^10.0.0", - "escape-string-regexp": "^4.0.0", - "semver": "^7.3.5", - "solidity-comments-extractor": "^0.0.7", - "string-width": "^4.2.3" + "@solidity-parser/parser": "^0.16.2", + "semver": "^7.5.4", + "solidity-comments-extractor": "^0.0.7" }, "engines": { - "node": ">=12" + "node": ">=16" }, "peerDependencies": { - "prettier": "^2.3.0" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/prettier-plugin-solidity/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" + "prettier": ">=2.3.0" } }, - "node_modules/prettier-plugin-solidity/node_modules/string-width/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, - "node_modules/prettier-plugin-solidity/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -3821,13 +2955,67 @@ } ] }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", + "dev": true, + "dependencies": { + "esprima": "~4.0.0" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", "dev": true, + "dependencies": { + "rc": "1.2.8" + }, "engines": { - "node": ">=6.5.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/require-from-string": { @@ -3839,28 +3027,82 @@ "node": ">=0.10.0" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "node_modules/resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "engines": { "node": ">=4" } }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -3889,15 +3131,6 @@ "rimraf": "bin.js" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3921,31 +3154,10 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true - }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3979,10 +3191,16 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/slash": { "version": "3.0.0", @@ -4033,9 +3251,9 @@ }, "node_modules/solc-0.8": { "name": "solc", - "version": "0.8.12", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.12.tgz", - "integrity": "sha512-TU3anAhKWBQ/WrerJ9EcHrNwGOA1y5vIk5Flz7dBNamLDkX9VQTIwcKd3FiZsT0Ew8rSU7RTmJyGNHRGzP5TBA==", + "version": "0.8.23", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.23.tgz", + "integrity": "sha512-uqe69kFWfJc3cKdxj+Eg9CdW1CP3PLZDPeyJStQVWL8Q9jjjKD0VuRAKBFR8mrWiq5A7gJqERxJFYJsklrVsfA==", "dev": true, "dependencies": { "command-exists": "^1.2.8", @@ -4043,6 +3261,7 @@ "follow-redirects": "^1.12.1", "js-sha3": "0.8.0", "memorystream": "^0.3.1", + "n": "^9.2.0", "semver": "^5.5.0", "tmp": "0.0.33" }, @@ -4100,72 +3319,196 @@ } }, "node_modules/solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-4.0.0.tgz", + "integrity": "sha512-bFViMcFvhqVd/HK3Roo7xZXX5nbujS7Bxeg5vnZc9QvH0yCWCrQ38Yrn1pbAY9tlKROc6wFr+rK1mxYgYrjZgA==", "dev": true, "dependencies": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "semver": "^6.3.0" + "@solidity-parser/parser": "^0.16.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" }, "bin": { "solhint": "solhint.js" }, "optionalDependencies": { - "prettier": "^1.14.3" + "prettier": "^2.8.3" } }, "node_modules/solhint-plugin-prettier": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", - "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz", + "integrity": "sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==", "dev": true, "dependencies": { + "@prettier/sync": "^0.3.0", "prettier-linter-helpers": "^1.0.0" }, "peerDependencies": { - "prettier": "^1.15.0 || ^2.0.0", - "prettier-plugin-solidity": "^1.0.0-alpha.14" + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.0.0" } }, - "node_modules/solhint/node_modules/commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "node_modules/solhint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/solhint/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solhint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/solhint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/solhint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/solhint/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/solhint/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solhint/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/solhint/node_modules/prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "optional": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { - "node": ">=4" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/solhint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, - "node_modules/solhint/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "node_modules/solhint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/solidity-comments-extractor": { @@ -4175,21 +3518,21 @@ "dev": true }, "node_modules/solidity-docgen": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.5.16.tgz", - "integrity": "sha512-rFVpqSNnDGKvL68mPf4J9mEQIl+Ixy6bIz/YE6AgjBCPtrlm4KjWQhcBMQWc/LarSCenOpzhbG1tHqP9gf9kcg==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.5.17.tgz", + "integrity": "sha512-RX5SPLFL9z0ZVBcZ/o5l/TKXMgSjNhWdumLuuv+Dy1O/66sThpHYd0HVpzdwAjVff0Ajk76bYM2zZYiMnqBfng==", "dev": true, "dependencies": { "@oclif/command": "^1.8.0", "@oclif/config": "^1.17.0", "@oclif/errors": "^1.3.3", - "@oclif/plugin-help": "^3.2.0", + "@oclif/plugin-help": "^5.0.0", "globby": "^11.0.0", "handlebars": "^4.7.6", "json5": "^2.1.3", "lodash": "^4.17.15", "micromatch": "^4.0.2", - "minimatch": "^3.0.4", + "minimatch": "^5.0.0", "semver": "^7.3.2", "solc": "^0.6.7" }, @@ -4197,6 +3540,27 @@ "solidity-docgen": "dist/cli.js" } }, + "node_modules/solidity-docgen/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solidity-docgen/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4209,235 +3573,253 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", - "dev": true, - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=0.6.19" } }, - "node_modules/string-width/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, "dependencies": { - "ansi-regex": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "dependencies": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/supports-color": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz", - "integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", "dev": true, "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/table/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/table/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "node_modules/table": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=4" + "node": ">=10.0.0" } }, - "node_modules/table/node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/table/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/table/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/table/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/table/node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/table/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/table/node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/table/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/table/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "node_modules/tmp": { @@ -4464,28 +3846,59 @@ "node": ">=8.0" } }, - "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "dependencies": { - "prelude-ls": "~1.1.2" + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" }, - "engines": { - "node": ">= 0.8.0" + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true, "engines": { "node": ">=10" @@ -4494,6 +3907,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -4507,6 +3934,12 @@ "node": ">=0.8.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -4525,6 +3958,12 @@ "punycode": "^2.1.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4602,101 +4041,27 @@ "node": ">=8" } }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } + "dev": true }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { @@ -4705,25 +4070,13 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", "dev": true, "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", @@ -4745,440 +4098,189 @@ "dev": true }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 14" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" } } }, "dependencies": { + "@adraffy/ens-normalize": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", + "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", + "dev": true + }, "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "requires": { - "@babel/highlight": "^7.16.7" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } } }, - "@ethersproject/abi": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.0.tgz", - "integrity": "sha512-AhVByTwdXCc2YQ20v300w6KVHle9g2OFc28ZAFCPnJyEpkv1xKXjZcSTgWOlv1i+0dqlgF8RCF2Rn2KC1t+1Vg==", - "dev": true, - "requires": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" - } - }, - "@ethersproject/abstract-provider": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", - "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0" - } - }, - "@ethersproject/abstract-signer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", - "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0" - } - }, - "@ethersproject/address": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", - "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/rlp": "^5.6.0" - } - }, - "@ethersproject/base64": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", - "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0" - } - }, - "@ethersproject/basex": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", - "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/properties": "^5.6.0" - } - }, - "@ethersproject/bignumber": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", - "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "bn.js": "^4.11.9" - } - }, - "@ethersproject/bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.0.tgz", - "integrity": "sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/constants": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", - "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.6.0" - } - }, - "@ethersproject/contracts": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", - "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", - "dev": true, - "requires": { - "@ethersproject/abi": "^5.6.0", - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/transactions": "^5.6.0" - } - }, - "@ethersproject/hash": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", - "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" - } - }, - "@ethersproject/hdnode": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", - "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" - } - }, - "@ethersproject/json-wallets": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", - "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/pbkdf2": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "@ethersproject/keccak256": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", - "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "requires": { - "@ethersproject/bytes": "^5.6.0", - "js-sha3": "0.8.0" + "@jridgewell/trace-mapping": "0.3.9" } }, - "@ethersproject/logger": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", - "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==", + "@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true }, - "@ethersproject/networks": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.0.tgz", - "integrity": "sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/pbkdf2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", - "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/sha2": "^5.6.0" - } - }, - "@ethersproject/properties": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", - "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/providers": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.1.tgz", - "integrity": "sha512-w8Wx15nH+aVDvnoKCyI1f3x0B5idmk/bDJXMEUqCfdO8Eadd0QpDx9lDMTMmenhOmf9vufLJXjpSm24D3ZnVpg==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/basex": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/networks": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/web": "^5.6.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "@ethersproject/random": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", - "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/rlp": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", - "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0" - } - }, - "@ethersproject/sha2": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", - "integrity": "sha512-1tNWCPFLu1n3JM9t4/kytz35DkuF9MxqkGGEHNauEbaARdm2fafnOyw1s0tIQDPKF/7bkP1u3dbrmjpn5CelyA==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "hash.js": "1.1.7" - } - }, - "@ethersproject/signing-key": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.0.tgz", - "integrity": "sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "bn.js": "^4.11.9", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "@ethersproject/solidity": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", - "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/sha2": "^5.6.0", - "@ethersproject/strings": "^5.6.0" - } - }, - "@ethersproject/strings": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", - "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0" - } + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true }, - "@ethersproject/transactions": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", - "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", - "dev": true, - "requires": { - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/rlp": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0" - } - }, - "@ethersproject/units": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", - "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "requires": { - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/constants": "^5.6.0", - "@ethersproject/logger": "^5.6.0" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "@ethersproject/wallet": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", - "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.6.0", - "@ethersproject/abstract-signer": "^5.6.0", - "@ethersproject/address": "^5.6.0", - "@ethersproject/bignumber": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/hdnode": "^5.6.0", - "@ethersproject/json-wallets": "^5.6.0", - "@ethersproject/keccak256": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/random": "^5.6.0", - "@ethersproject/signing-key": "^5.6.0", - "@ethersproject/transactions": "^5.6.0", - "@ethersproject/wordlists": "^5.6.0" - } - }, - "@ethersproject/web": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", - "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", + "@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", "dev": true, "requires": { - "@ethersproject/base64": "^5.6.0", - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" + "@noble/hashes": "1.3.2" } }, - "@ethersproject/wordlists": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", - "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.6.0", - "@ethersproject/hash": "^5.6.0", - "@ethersproject/logger": "^5.6.0", - "@ethersproject/properties": "^5.6.0", - "@ethersproject/strings": "^5.6.0" - } + "@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "dev": true }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -5207,101 +4309,84 @@ } }, "@oclif/command": { - "version": "1.8.16", - "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.16.tgz", - "integrity": "sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w==", + "version": "1.8.36", + "resolved": "https://registry.npmjs.org/@oclif/command/-/command-1.8.36.tgz", + "integrity": "sha512-/zACSgaYGtAQRzc7HjzrlIs14FuEYAZrMOEwicRoUnZVyRunG4+t5iSEeQu0Xy2bgbCD0U1SP/EdeNZSTXRwjQ==", "dev": true, "requires": { "@oclif/config": "^1.18.2", - "@oclif/errors": "^1.3.5", + "@oclif/errors": "^1.3.6", "@oclif/help": "^1.0.1", - "@oclif/parser": "^3.8.6", + "@oclif/parser": "^3.8.17", "debug": "^4.1.1", - "semver": "^7.3.2" + "semver": "^7.5.4" } }, "@oclif/config": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.3.tgz", - "integrity": "sha512-sBpko86IrTscc39EvHUhL+c++81BVTsIZ3ETu/vG+cCdi0N6vb2DoahR67A9FI2CGnxRRHjnTfa3m6LulwNATA==", + "version": "1.18.17", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.17.tgz", + "integrity": "sha512-k77qyeUvjU8qAJ3XK3fr/QVAqsZO8QOBuESnfeM5HHtPNLSyfVcwiMM2zveSW5xRdLSG3MfV8QnLVkuyCL2ENg==", "dev": true, "requires": { - "@oclif/errors": "^1.3.5", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", + "@oclif/errors": "^1.3.6", + "@oclif/parser": "^3.8.17", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-wsl": "^2.1.1", - "tslib": "^2.3.1" - } - }, - "@oclif/errors": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.5.tgz", - "integrity": "sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ==", - "dev": true, - "requires": { - "clean-stack": "^3.0.0", - "fs-extra": "^8.1", - "indent-string": "^4.0.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" + "tslib": "^2.6.1" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true - }, - "clean-stack": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", - "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", - "dev": true, - "requires": { - "escape-string-regexp": "4.0.0" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } } } - }, - "@oclif/help": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oclif/help/-/help-1.0.1.tgz", - "integrity": "sha512-8rsl4RHL5+vBUAKBL6PFI3mj58hjPCp2VYyXD4TAa7IMStikFfOH2gtWmqLzIlxAED2EpD0dfYwo9JJxYsH7Aw==", + }, + "@oclif/core": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@oclif/core/-/core-2.15.0.tgz", + "integrity": "sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA==", "dev": true, "requires": { - "@oclif/config": "1.18.2", - "@oclif/errors": "1.3.5", + "@types/cli-progress": "^3.11.0", + "ansi-escapes": "^4.3.2", + "ansi-styles": "^4.3.0", + "cardinal": "^2.1.1", "chalk": "^4.1.2", + "clean-stack": "^3.0.1", + "cli-progress": "^3.12.0", + "debug": "^4.3.4", + "ejs": "^3.1.8", + "get-package-type": "^0.1.0", + "globby": "^11.1.0", + "hyperlinker": "^1.0.0", "indent-string": "^4.0.0", - "lodash": "^4.17.21", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "is-wsl": "^2.2.0", + "js-yaml": "^3.14.1", + "natural-orderby": "^2.0.3", + "object-treeify": "^1.1.33", + "password-prompt": "^1.1.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "supports-color": "^8.1.1", + "supports-hyperlinks": "^2.2.0", + "ts-node": "^10.9.1", + "tslib": "^2.5.0", "widest-line": "^3.1.0", - "wrap-ansi": "^6.2.0" + "wordwrap": "^1.0.0", + "wrap-ansi": "^7.0.0" }, "dependencies": { - "@oclif/config": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", - "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", - "is-wsl": "^2.1.1", - "tslib": "^2.0.0" + "type-fest": "^0.21.3" } }, "ansi-regex": { @@ -5319,6 +4404,15 @@ "color-convert": "^2.0.1" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -5327,8 +4421,34 @@ "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5341,6 +4461,27 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5361,19 +4502,22 @@ "ansi-regex": "^5.0.1" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true }, "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -5383,24 +4527,25 @@ } } }, - "@oclif/linewrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz", - "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==", - "dev": true - }, - "@oclif/parser": { - "version": "3.8.7", - "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.7.tgz", - "integrity": "sha512-b11xBmIUK+LuuwVGJpFs4LwQN2xj2cBWj2c4z1FtiXGrJ85h9xV6q+k136Hw0tGg1jQoRXuvuBnqQ7es7vO9/Q==", + "@oclif/errors": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@oclif/errors/-/errors-1.3.6.tgz", + "integrity": "sha512-fYaU4aDceETd89KXP+3cLyg9EHZsLD3RxF2IU9yxahhBpspWjkWi3Dy3bTgcwZ3V47BgxQaGapzJWDM33XIVDQ==", "dev": true, "requires": { - "@oclif/errors": "^1.3.5", - "@oclif/linewrap": "^1.0.0", - "chalk": "^4.1.0", - "tslib": "^2.3.1" + "clean-stack": "^3.0.0", + "fs-extra": "^8.1", + "indent-string": "^4.0.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -5410,37 +4555,74 @@ "color-convert": "^2.0.1" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "color-name": "~1.1.4" } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "has-flag": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, - "@oclif/plugin-help": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-3.3.1.tgz", - "integrity": "sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ==", + "@oclif/help": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@oclif/help/-/help-1.0.15.tgz", + "integrity": "sha512-Yt8UHoetk/XqohYX76DfdrUYLsPKMc5pgkzsZVHDyBSkLiGRzujVaGZdjr32ckVZU9q3a47IjhWxhip7Dz5W/g==", "dev": true, "requires": { - "@oclif/command": "^1.8.15", - "@oclif/config": "1.18.2", - "@oclif/errors": "1.3.5", - "@oclif/help": "^1.0.1", + "@oclif/config": "1.18.16", + "@oclif/errors": "1.3.6", "chalk": "^4.1.2", "indent-string": "^4.0.0", "lodash": "^4.17.21", @@ -5451,17 +4633,17 @@ }, "dependencies": { "@oclif/config": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.2.tgz", - "integrity": "sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA==", + "version": "1.18.16", + "resolved": "https://registry.npmjs.org/@oclif/config/-/config-1.18.16.tgz", + "integrity": "sha512-VskIxVcN22qJzxRUq+raalq6Q3HUde7sokB7/xk5TqRZGEKRVbFeqdQBxDWwQeudiJEgcNiMvIFbMQ43dY37FA==", "dev": true, "requires": { - "@oclif/errors": "^1.3.3", - "@oclif/parser": "^3.8.0", - "debug": "^4.1.1", - "globby": "^11.0.1", + "@oclif/errors": "^1.3.6", + "@oclif/parser": "^3.8.16", + "debug": "^4.3.4", + "globby": "^11.1.0", "is-wsl": "^2.1.1", - "tslib": "^2.0.0" + "tslib": "^2.6.1" } }, "ansi-regex": { @@ -5489,6 +4671,21 @@ "supports-color": "^7.1.0" } }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -5530,6 +4727,12 @@ "has-flag": "^4.0.0" } }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -5543,55 +4746,212 @@ } } }, + "@oclif/linewrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oclif/linewrap/-/linewrap-1.0.0.tgz", + "integrity": "sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw==", + "dev": true + }, + "@oclif/parser": { + "version": "3.8.17", + "resolved": "https://registry.npmjs.org/@oclif/parser/-/parser-3.8.17.tgz", + "integrity": "sha512-l04iSd0xoh/16TGVpXb81Gg3z7tlQGrEup16BrVLsZBK6SEYpYHRJZnM32BwZrHI97ZSFfuSwVlzoo6HdsaK8A==", + "dev": true, + "requires": { + "@oclif/errors": "^1.3.6", + "@oclif/linewrap": "^1.0.0", + "chalk": "^4.1.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + } + } + }, + "@oclif/plugin-help": { + "version": "5.2.20", + "resolved": "https://registry.npmjs.org/@oclif/plugin-help/-/plugin-help-5.2.20.tgz", + "integrity": "sha512-u+GXX/KAGL9S10LxAwNUaWdzbEBARJ92ogmM7g3gDVud2HioCmvWQCDohNRVZ9GYV9oKwZ/M8xwd6a1d95rEKQ==", + "dev": true, + "requires": { + "@oclif/core": "^2.15.0" + } + }, "@openzeppelin/contracts": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-4.5.0.tgz", - "integrity": "sha512-fdkzKPYMjrRiPK6K4y64e6GzULR7R7RwxSigHS8DDp7aWDeoReqsQI+cxHV1UuhAqX69L1lAaWDxenfP+xiqzA==" + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@openzeppelin/contracts/-/contracts-5.0.0.tgz", + "integrity": "sha512-bv2sdS6LKqVVMLI5+zqnNrNU/CA+6z6CmwFXm/MzmOPBRSO5reEJN7z0Gbzvs0/bv/MZZXNklubpwy3v2+azsw==" + }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "requires": { + "graceful-fs": "4.2.10" + } + }, + "@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@prettier/sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@prettier/sync/-/sync-0.3.0.tgz", + "integrity": "sha512-3dcmCyAxIcxy036h1I7MQU/uEEBq8oLwf1CE3xeze+MPlgkdlb/+w6rGR/1dhp6Hqi17fRS6nvwnOzkESxEkOw==", + "dev": true, + "requires": {} + }, + "@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", + "dev": true }, "@solidity-parser/parser": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.1.tgz", - "integrity": "sha512-eLjj2L6AuQjBB6s/ibwCAc0DwrR5Ge+ys+wgWo+bviU7fV2nTMQhU63CGaDKXg9iTmMxwhkyoggdIR7ZGRfMgw==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.16.2.tgz", + "integrity": "sha512-PI9NfoA3P8XK2VBkK5oIfRgKDsicwDZfkVq9ZTBCQYGOP1N2owgY2dyLGyU5/J/hQs8KRk55kdmvTLjy3Mu3vg==", "dev": true, "requires": { "antlr4ts": "^0.5.0-alpha.4" } }, - "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, - "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "@types/cli-progress": { + "version": "3.11.5", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.5.tgz", + "integrity": "sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==", "dev": true, - "requires": {} + "requires": { + "@types/node": "*" + } }, - "aes-js": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", - "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=", + "@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "@types/node": { + "version": "20.9.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.0.tgz", + "integrity": "sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==", "dev": true, "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "undici-types": "~5.26.4" } }, + "acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true + }, + "acorn-walk": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", + "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", + "dev": true + }, + "aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "dev": true + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -5605,30 +4965,36 @@ } }, "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", "dev": true, "requires": { - "type-fest": "^0.21.3" + "type-fest": "^1.0.2" } }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true }, "ansi-styles": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.0.tgz", - "integrity": "sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", "dev": true }, "antlr4": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.7.1.tgz", - "integrity": "sha512-haHyTW7Y9joE5MVs37P2lNYfU2RWBLfcRDD8OWldcdZm5TiCE91B5Xl1oWSwiDUSd4rlExpt2pu1fksYQjRBYQ==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.13.1.tgz", + "integrity": "sha512-kiXTspaRYvnIArgE97z5YVVf/cDVQABr3abFRR6mE7yesLMkgu4ujuyV/sgxafQ8wgve0DJQUJ38Z8tkgA2izA==", "dev": true }, "antlr4ts": { @@ -5637,14 +5003,17 @@ "integrity": "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, "array-union": { "version": "2.1.0", @@ -5664,24 +5033,18 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "bech32": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", - "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", - "dev": true - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5701,115 +5064,124 @@ "fill-range": "^7.0.1" } }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", "dev": true }, - "caller-callsite": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", - "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "requires": { - "callsites": "^2.0.0" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "dependencies": { + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + } } }, - "caller-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", - "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "cardinal": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-2.1.1.tgz", + "integrity": "sha512-JSr5eOgoEymtYHBjNWyjrMqet9Am2miJhlfKNdqLp6zoeAh0KN5dRAcxlecj5mAJrmQomgiOBj35xHLrFjqBpw==", "dev": true, "requires": { - "caller-callsite": "^2.0.0" + "ansicolors": "~0.3.2", + "redeyed": "~2.1.0" } }, - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "clean-stack": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-3.0.1.tgz", + "integrity": "sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "escape-string-regexp": "4.0.0" + } + }, + "cli-cursor": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", + "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", + "dev": true, + "requires": { + "restore-cursor": "^4.0.0" + } + }, + "cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "dev": true, + "requires": { + "string-width": "^4.2.3" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "has-flag": { + "is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" } } } }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, "cli-truncate": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-3.1.0.tgz", @@ -5820,31 +5192,25 @@ "string-width": "^5.0.0" } }, - "cli-width": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz", - "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==", - "dev": true - }, "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "requires": { - "color-name": "~1.1.4" + "color-name": "1.1.3" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "command-exists": { @@ -5865,18 +5231,34 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "cosmiconfig": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", - "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "requires": { - "import-fresh": "^2.0.0", - "is-directory": "^0.3.1", - "js-yaml": "^3.13.1", - "parse-json": "^4.0.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" } }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5889,18 +5271,47 @@ } }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" } }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + } + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, "dir-glob": { @@ -5912,40 +5323,25 @@ "path-type": "^4.0.0" } }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, "eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "ejs": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz", + "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==", "dev": true, "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" + "jake": "^10.8.5" } }, "emoji-regex": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.0.0.tgz", - "integrity": "sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, "error-ex": { @@ -5963,269 +5359,56 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "eslint": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.16.0.tgz", - "integrity": "sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.9.1", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^4.0.3", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^5.0.1", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob": "^7.1.2", - "globals": "^11.7.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^6.2.2", - "js-yaml": "^3.13.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.11", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.2", - "path-is-inside": "^1.0.2", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^5.5.1", - "strip-ansi": "^4.0.0", - "strip-json-comments": "^2.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "eslint-scope": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", - "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", - "dev": true, - "requires": { - "esrecurse": "^4.1.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.1.tgz", - "integrity": "sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A==", - "dev": true, - "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" - } - }, "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "ethers": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.1.tgz", + "integrity": "sha512-iEKm6zox5h1lDn6scuRWdIdFJUCGg3+/aQWu0F4K0GVyEZiktFkqrJbRjTn1FlYEPz7RKA707D6g5Kdk6j7Ljg==", "dev": true, "requires": { - "estraverse": "^5.2.0" + "@adraffy/ens-normalize": "1.10.0", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" }, "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", "dev": true } } }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, - "ethers": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.1.tgz", - "integrity": "sha512-qtl/2W+dwmUa5Z3JqwsbV3JEBZZHNARe5K/A2ePcNAuhJYnEKIgGOT/O9ouPwBijSqVoQnmQMzi5D48LFNOY2A==", - "dev": true, - "requires": { - "@ethersproject/abi": "5.6.0", - "@ethersproject/abstract-provider": "5.6.0", - "@ethersproject/abstract-signer": "5.6.0", - "@ethersproject/address": "5.6.0", - "@ethersproject/base64": "5.6.0", - "@ethersproject/basex": "5.6.0", - "@ethersproject/bignumber": "5.6.0", - "@ethersproject/bytes": "5.6.0", - "@ethersproject/constants": "5.6.0", - "@ethersproject/contracts": "5.6.0", - "@ethersproject/hash": "5.6.0", - "@ethersproject/hdnode": "5.6.0", - "@ethersproject/json-wallets": "5.6.0", - "@ethersproject/keccak256": "5.6.0", - "@ethersproject/logger": "5.6.0", - "@ethersproject/networks": "5.6.0", - "@ethersproject/pbkdf2": "5.6.0", - "@ethersproject/properties": "5.6.0", - "@ethersproject/providers": "5.6.1", - "@ethersproject/random": "5.6.0", - "@ethersproject/rlp": "5.6.0", - "@ethersproject/sha2": "5.6.0", - "@ethersproject/signing-key": "5.6.0", - "@ethersproject/solidity": "5.6.0", - "@ethersproject/strings": "5.6.0", - "@ethersproject/transactions": "5.6.0", - "@ethersproject/units": "5.6.0", - "@ethersproject/wallet": "5.6.0", - "@ethersproject/web": "5.6.0", - "@ethersproject/wordlists": "5.6.0" - } - }, "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", "dev": true, "requires": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" } }, "fast-deep-equal": { @@ -6241,9 +5424,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -6259,47 +5442,44 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "requires": { "reusify": "^1.0.4" } }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5" + "minimatch": "^5.0.1" }, "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } } } }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -6309,29 +5489,18 @@ "to-regex-range": "^5.0.1" } }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, "follow-redirects": { "version": "1.14.9", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", "dev": true }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, "fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -6349,264 +5518,16 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, - "ganache": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.0.3.tgz", - "integrity": "sha512-1O4V38YkAFd2B1YfBevauEepxEtoN0iTTK02SUJPUIcLOnxwrR49lSDq7liKpUWLkoZCOC2Bkrz/+XJAmEoNAQ==", - "dev": true, - "requires": { - "@trufflesuite/bigint-buffer": "1.1.9", - "bufferutil": "4.0.5", - "emittery": "0.10.0", - "keccak": "3.0.1", - "leveldown": "6.1.0", - "secp256k1": "4.0.2", - "utf-8-validate": "5.0.7" - }, - "dependencies": { - "@trufflesuite/bigint-buffer": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.9.tgz", - "integrity": "sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw==", - "dev": true, - "requires": { - "node-gyp-build": "4.3.0" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", - "dev": true - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", - "dev": true - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "bufferutil": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", - "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "dev": true, - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "catering": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", - "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", - "dev": true, - "requires": { - "queue-tick": "^1.0.0" - } - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "dev": true, - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "emittery": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", - "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", - "dev": true - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "dev": true, - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", - "dev": true - }, - "keccak": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz", - "integrity": "sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA==", - "dev": true, - "requires": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "leveldown": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", - "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", - "dev": true, - "requires": { - "abstract-leveldown": "^7.2.0", - "napi-macros": "~2.0.0", - "node-gyp-build": "^4.3.0" - }, - "dependencies": { - "abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", - "dev": true, - "requires": { - "buffer": "^6.0.3", - "catering": "^2.0.0", - "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" - } - }, - "level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", - "dev": true, - "requires": { - "catering": "^2.1.0" - } - }, - "level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", - "dev": true - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", - "dev": true - }, - "napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", - "dev": true - }, - "node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "dev": true - }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "queue-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", - "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==", - "dev": true - }, - "secp256k1": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz", - "integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==", - "dev": true, - "requires": { - "elliptic": "^6.5.2", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "utf-8-validate": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", - "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", - "dev": true, - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - } - } - }, "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", "dev": true }, "glob": { @@ -6632,12 +5553,6 @@ "is-glob": "^4.0.1" } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6650,20 +5565,39 @@ "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" + } + }, + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" }, "dependencies": { - "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true } } }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "handlebars": { @@ -6685,224 +5619,88 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "dev": true }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" } }, "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", "dev": true }, "husky": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.4.tgz", - "integrity": "sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", - "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", - "dev": true, - "requires": { - "caller-path": "^2.0.0", - "resolve-from": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", "dev": true }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "hyperlinker": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hyperlinker/-/hyperlinker-1.0.0.tgz", + "integrity": "sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ==", "dev": true }, - "inquirer": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", - "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", - "dev": true, - "requires": { - "ansi-escapes": "^3.2.0", - "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", - "cli-width": "^2.0.0", - "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", - "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", - "strip-ansi": "^5.1.0", - "through": "^2.3.6" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "dev": true, - "requires": { - "restore-cursor": "^2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", - "dev": true - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "dev": true, - "requires": { - "mimic-fn": "^1.0.0" - } - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "dev": true, - "requires": { - "onetime": "^2.0.0", - "signal-exit": "^3.0.2" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "requires": { - "tslib": "^1.9.0" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - } - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" } }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-docker": { @@ -6914,7 +5712,7 @@ "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-fullwidth-code-point": { @@ -6939,9 +5737,9 @@ "dev": true }, "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true }, "is-wsl": { @@ -6956,9 +5754,66 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", + "dev": true, + "requires": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "js-sha3": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", @@ -6972,19 +5827,24 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true }, "json-schema-traverse": { @@ -6993,12 +5853,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -7011,12 +5865,21 @@ "jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "requires": { "graceful-fs": "^4.1.6" } }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", @@ -7026,127 +5889,65 @@ "graceful-fs": "^4.1.9" } }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", "dev": true, "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" + "package-json": "^8.1.0" } }, "lilconfig": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz", - "integrity": "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, "lint-staged": { - "version": "12.3.5", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-12.3.5.tgz", - "integrity": "sha512-oOH36RUs1It7b9U/C7Nl/a0sLfoIBcMB8ramiB3nuJ6brBqzsWiUAFSR5DQ3yyP/OR7XKMpijtgKl2DV1lQ3lA==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.1.0.tgz", + "integrity": "sha512-ZPKXWHVlL7uwVpy8OZ7YQjYDAuO5X4kMh0XgZvPNxLcCCngd0PO5jKQyy3+s4TL2EnHoIXIzP1422f/l3nZKMw==", "dev": true, "requires": { - "cli-truncate": "^3.1.0", - "colorette": "^2.0.16", - "commander": "^8.3.0", - "debug": "^4.3.3", - "execa": "^5.1.1", - "lilconfig": "2.0.4", - "listr2": "^4.0.1", - "micromatch": "^4.0.4", - "normalize-path": "^3.0.0", - "object-inspect": "^1.12.0", - "string-argv": "^0.3.1", - "supports-color": "^9.2.1", - "yaml": "^1.10.2" + "chalk": "5.3.0", + "commander": "11.1.0", + "debug": "4.3.4", + "execa": "8.0.1", + "lilconfig": "2.1.0", + "listr2": "7.0.2", + "micromatch": "4.0.5", + "pidtree": "0.6.0", + "string-argv": "0.3.2", + "yaml": "2.3.4" + }, + "dependencies": { + "commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true + } } }, "listr2": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.4.tgz", - "integrity": "sha512-vJOm5KD6uZXjSsrwajr+mNacIjf87gWvlBEltPWLbTkslUscWAzquyK4xfe9Zd4RDgO5nnwFyV06FC+uVR+5mg==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-7.0.2.tgz", + "integrity": "sha512-rJysbR9GKIalhTbVL2tYbF2hVyDnrf7pFUZBwjPaMIdadYHmeT+EVi/Bu3qd7ETQPahTotg2WRCatXwRBW554g==", "dev": true, "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", + "cli-truncate": "^3.1.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^5.0.1", "rfdc": "^1.3.0", - "rxjs": "^7.5.4", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } + "wrap-ansi": "^8.1.0" } }, "lodash": { @@ -7155,89 +5956,31 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-5.0.1.tgz", + "integrity": "sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==", "dev": true, "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - } + "ansi-escapes": "^5.0.0", + "cli-cursor": "^4.0.0", + "slice-ansi": "^5.0.0", + "strip-ansi": "^7.0.1", + "wrap-ansi": "^8.0.1" } }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7247,6 +5990,12 @@ "yallist": "^4.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -7266,31 +6015,25 @@ "dev": true }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", "dev": true }, "minimatch": { @@ -7308,31 +6051,22 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "n": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/n/-/n-9.2.0.tgz", + "integrity": "sha512-R8mFN2OWwNVc+r1f9fDzcT34DnDwUIHskrpTesZ6SdluaXBBnRtTu5tlfaSPloBi1Z/eGJoPO9nhyawWPad5UQ==", "dev": true }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "natural-orderby": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/natural-orderby/-/natural-orderby-2.0.3.tgz", + "integrity": "sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q==", "dev": true }, "neo-async": { @@ -7341,31 +6075,33 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", "dev": true }, "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "requires": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" + }, + "dependencies": { + "path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true + } } }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", "dev": true }, "once": { @@ -7378,26 +6114,12 @@ } }, "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", "dev": true, "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" + "mimic-fn": "^4.0.0" } }, "os-tmpdir": { @@ -7406,13 +6128,22 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "dev": true, "requires": { - "aggregate-error": "^3.0.0" + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" } }, "parent-module": { @@ -7422,24 +6153,45 @@ "dev": true, "requires": { "callsites": "^3.0.0" - }, - "dependencies": { - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - } } }, "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { + "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "password-prompt": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", + "integrity": "sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw==", + "dev": true, + "requires": { + "ansi-escapes": "^4.3.2", + "cross-spawn": "^7.0.3" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } } }, "path-is-absolute": { @@ -7448,12 +6200,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -7472,16 +6218,22 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true + }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true }, "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", "dev": true }, "prettier-linter-helpers": { @@ -7494,71 +6246,26 @@ } }, "prettier-plugin-solidity": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.19.tgz", - "integrity": "sha512-xxRQ5ZiiZyUoMFLE9h7HnUDXI/daf1tnmL1msEdcKmyh7ZGQ4YklkYLC71bfBpYU2WruTb5/SFLUaEb3RApg5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.2.0.tgz", + "integrity": "sha512-fgxcUZpVAP+LlRfy5JI5oaAkXGkmsje2VJ5krv/YMm+rcTZbIUwFguSw5f+WFuttMjpDm6wB4UL7WVkArEfiVA==", "dev": true, "requires": { - "@solidity-parser/parser": "^0.14.0", - "emoji-regex": "^10.0.0", - "escape-string-regexp": "^4.0.0", - "semver": "^7.3.5", - "solidity-comments-extractor": "^0.0.7", - "string-width": "^4.2.3" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - } - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } + "@solidity-parser/parser": "^0.16.2", + "semver": "^7.5.4", + "solidity-comments-extractor": "^0.0.7" } }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "queue-microtask": { @@ -7567,32 +6274,109 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "redeyed": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/redeyed/-/redeyed-2.1.1.tgz", + "integrity": "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ==", + "dev": true, + "requires": { + "esprima": "~4.0.0" + } + }, + "registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "requires": { + "@pnpm/npm-conf": "^2.1.0" + } + }, + "registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, "require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } + }, "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", + "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, "requires": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" + }, + "dependencies": { + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } } }, "reusify": { @@ -7616,12 +6400,6 @@ "glob": "^7.1.3" } }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7631,31 +6409,10 @@ "queue-microtask": "^1.2.2" } }, - "rxjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.4.tgz", - "integrity": "sha512-h5M3Hk78r6wAheJF0a5YahB1yRQKCsZ4MsGdZ5O9ETbVtjPcScGfrMmoOq7EBsCRzd4BDkvDJ7ogP8Sz5tTFiQ==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "dev": true - }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -7677,9 +6434,9 @@ "dev": true }, "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true }, "slash": { @@ -7739,90 +6496,179 @@ "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", "dev": true, "requires": { - "graceful-fs": "^4.1.6" + "graceful-fs": "^4.1.6" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "solc-0.8": { + "version": "npm:solc@0.8.23", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.23.tgz", + "integrity": "sha512-uqe69kFWfJc3cKdxj+Eg9CdW1CP3PLZDPeyJStQVWL8Q9jjjKD0VuRAKBFR8mrWiq5A7gJqERxJFYJsklrVsfA==", + "dev": true, + "requires": { + "command-exists": "^1.2.8", + "commander": "^8.1.0", + "follow-redirects": "^1.12.1", + "js-sha3": "0.8.0", + "memorystream": "^0.3.1", + "n": "^9.2.0", + "semver": "^5.5.0", + "tmp": "0.0.33" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "solhint": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/solhint/-/solhint-4.0.0.tgz", + "integrity": "sha512-bFViMcFvhqVd/HK3Roo7xZXX5nbujS7Bxeg5vnZc9QvH0yCWCrQ38Yrn1pbAY9tlKROc6wFr+rK1mxYgYrjZgA==", + "dev": true, + "requires": { + "@solidity-parser/parser": "^0.16.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^10.0.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "latest-version": "^7.0.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "prettier": "^2.8.3", + "semver": "^7.5.2", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" } }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "solc-0.8": { - "version": "npm:solc@0.8.12", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.8.12.tgz", - "integrity": "sha512-TU3anAhKWBQ/WrerJ9EcHrNwGOA1y5vIk5Flz7dBNamLDkX9VQTIwcKd3FiZsT0Ew8rSU7RTmJyGNHRGzP5TBA==", - "dev": true, - "requires": { - "command-exists": "^1.2.8", - "commander": "^8.1.0", - "follow-redirects": "^1.12.1", - "js-sha3": "0.8.0", - "memorystream": "^0.3.1", - "semver": "^5.5.0", - "tmp": "0.0.33" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true - } - } - }, - "solhint": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/solhint/-/solhint-3.3.7.tgz", - "integrity": "sha512-NjjjVmXI3ehKkb3aNtRJWw55SUVJ8HMKKodwe0HnejA+k0d2kmhw7jvpa+MCTbcEgt8IWSwx0Hu6aCo/iYOZzQ==", - "dev": true, - "requires": { - "@solidity-parser/parser": "^0.14.1", - "ajv": "^6.6.1", - "antlr4": "4.7.1", - "ast-parents": "0.0.1", - "chalk": "^2.4.2", - "commander": "2.18.0", - "cosmiconfig": "^5.0.7", - "eslint": "^5.6.0", - "fast-diff": "^1.1.2", - "glob": "^7.1.3", - "ignore": "^4.0.6", - "js-yaml": "^3.12.0", - "lodash": "^4.17.11", - "prettier": "^1.14.3", - "semver": "^6.3.0" - }, - "dependencies": { + }, "commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", "dev": true }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, "prettier": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz", - "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==", + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "optional": true }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, "solhint-plugin-prettier": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.0.5.tgz", - "integrity": "sha512-7jmWcnVshIrO2FFinIvDQmhQpfpS2rRRn3RejiYgnjIE68xO2bvrYvjqVNfrio4xH9ghOqn83tKuTzLjEbmGIA==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/solhint-plugin-prettier/-/solhint-plugin-prettier-0.1.0.tgz", + "integrity": "sha512-SDOTSM6tZxZ6hamrzl3GUgzF77FM6jZplgL2plFBclj/OjKP8Z3eIPojKU73gRr0MvOS8ACZILn8a5g0VTz/Gw==", "dev": true, "requires": { + "@prettier/sync": "^0.3.0", "prettier-linter-helpers": "^1.0.0" } }, @@ -7833,23 +6679,43 @@ "dev": true }, "solidity-docgen": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.5.16.tgz", - "integrity": "sha512-rFVpqSNnDGKvL68mPf4J9mEQIl+Ixy6bIz/YE6AgjBCPtrlm4KjWQhcBMQWc/LarSCenOpzhbG1tHqP9gf9kcg==", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/solidity-docgen/-/solidity-docgen-0.5.17.tgz", + "integrity": "sha512-RX5SPLFL9z0ZVBcZ/o5l/TKXMgSjNhWdumLuuv+Dy1O/66sThpHYd0HVpzdwAjVff0Ajk76bYM2zZYiMnqBfng==", "dev": true, "requires": { "@oclif/command": "^1.8.0", "@oclif/config": "^1.17.0", "@oclif/errors": "^1.3.3", - "@oclif/plugin-help": "^3.2.0", + "@oclif/plugin-help": "^5.0.0", "globby": "^11.0.0", "handlebars": "^4.7.6", "json5": "^2.1.3", "lodash": "^4.17.15", "micromatch": "^4.0.2", - "minimatch": "^3.0.4", + "minimatch": "^5.0.0", "semver": "^7.3.2", "solc": "^0.6.7" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "source-map": { @@ -7861,13 +6727,13 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "string-argv": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz", - "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", "dev": true }, "string-width": { @@ -7879,147 +6745,161 @@ "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^6.0.1" } }, "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true }, "supports-color": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.2.1.tgz", - "integrity": "sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==", - "dev": true + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", + "integrity": "sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" } }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -8027,13 +6907,7 @@ "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "tmp": { @@ -8054,27 +6928,46 @@ "is-number": "^7.0.0" } }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "requires": { - "prelude-ls": "~1.1.2" + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" } }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "dev": true + }, "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", "dev": true }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "peer": true + }, "uglify-js": { "version": "3.15.2", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.15.2.tgz", @@ -8082,6 +6975,12 @@ "dev": true, "optional": true }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -8097,6 +6996,12 @@ "punycode": "^2.1.0" } }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -8155,12 +7060,6 @@ } } }, - "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true - }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -8168,63 +7067,14 @@ "dev": true }, "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - } + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" } }, "wrappy": { @@ -8233,19 +7083,10 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", "dev": true, "requires": {} }, @@ -8256,9 +7097,15 @@ "dev": true }, "yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true } } diff --git a/package.json b/package.json index 7c373e9..8c726d8 100644 --- a/package.json +++ b/package.json @@ -33,18 +33,18 @@ "*.sol": "solhint" }, "dependencies": { - "@openzeppelin/contracts": "^4.5.0" + "@openzeppelin/contracts": "^5.0.0" }, "devDependencies": { - "@types/node": "^17.0.21", - "ethers": "^5.6.1", - "husky": "^7.0.4", - "lint-staged": "^12.3.5", - "prettier": "^2.5.1", - "prettier-plugin-solidity": "^1.0.0-beta.19", - "solc-0.8": "npm:solc@^0.8.12", - "solhint": "^3.3.7", - "solhint-plugin-prettier": "^0.0.5", - "solidity-docgen": "^0.5.16" + "@types/node": "^20.9.0", + "ethers": "^6.8.1", + "husky": "^8.0.3", + "lint-staged": "^15.1.0", + "prettier": "^3.0.3", + "prettier-plugin-solidity": "^1.2.0", + "solc-0.8": "npm:solc@^0.8.23", + "solhint": "^4.0.0", + "solhint-plugin-prettier": "^0.1.0", + "solidity-docgen": "^0.5.17" } } diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 52c3e37..cc0234a 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -6,10 +6,13 @@ import "./IBillboard.sol"; import "./IBillboardRegistry.sol"; contract Billboard is IBillboard { - address public admin; - BillboardRegistry public registry; + // access control + bool public isOpened = false; + address public admin; + mapping(address => bool) public whitelist; + constructor() { admin = msg.sender; } @@ -25,13 +28,27 @@ contract Billboard is IBillboard { _; } - modifier isAdmin(address value_) { - if (value_ != admin) { + modifier isFromAdmin() { + if (msg.sender != admin) { revert Unauthorized("admin"); } _; } + modifier isFromBoardCreator(uint256 tokenId_) { + if (msg.sender != boards[tokenId_].creator) { + revert Unauthorized("board creator"); + } + _; + } + + modifier isFromBoardTenant(uint256 tokenId_) { + if (msg.sender != _ownerOf(tokenId_)) { + revert Unauthorized("board tenant"); + } + _; + } + ////////////////////////////// /// Upgradability ////////////////////////////// @@ -41,19 +58,19 @@ contract Billboard is IBillboard { registry = BillboardRegistry(contract_); } - /// @inheritdoc IBillboard - function setIsOpened(bool value_) external isAdmin(msg.sender) { - registry.setIsOpened(value_, msg.sender); + /// @inheritdoc IBillboardRegistry + function setIsOpened(bool value_, address sender_) external isAdmin(sender_) { + isOpened = value_; } - /// @inheritdoc IBillboard - function addToWhitelist(address value_) external isAdmin(msg.sender) { - registry.addToWhitelist(value_, msg.sender); + /// @inheritdoc IBillboardRegistry + function addToWhitelist(address value_, address sender_) external isAdmin(sender_) { + whitelist[value_] = true; } - /// @inheritdoc IBillboard - function removeFromWhitelist(address value_) external isAdmin(msg.sender) { - registry.removeFromWhitelist(value_, msg.sender); + /// @inheritdoc IBillboardRegistry + function removeFromWhitelist(address value_, address sender_) external isAdmin(sender_) { + whitelist[value_] = false; } ////////////////////////////// @@ -62,18 +79,17 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external isValidAddress(to_) { - uint256 tokenId = registry.mint(to_, msg.sender); - registry.initTreasury(tokenId); + registry.mint(to_, msg.sender); } /// @inheritdoc IBillboard function getBoard(uint256 tokenId_) external view returns (IBillboardRegistry.Board memory board) { - return registry.getBoard(tokenId_); + return registry.boards[tokenId_]; } /// @inheritdoc IBillboard - function setBoardName(uint256 tokenId_, string memory name_) external { - registry.setBoardName(tokenId_, name_, msg.sender); + function setBoardName(uint256 tokenId_, string memory name_) external isFromBoardCreator { + registry.setBoardName(tokenId_, name_); } /// @inheritdoc IBillboard @@ -125,16 +141,7 @@ contract Billboard is IBillboard { uint256 tokenId_, uint256 limit_, uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - IBillboardRegistry.Bid[] memory bids - ) - { + ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids) { return registry.getBidsByBoard(tokenId_, limit_, offset_); } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 742d626..5022c6e 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -10,13 +10,12 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { using Counters for Counters.Counter; // access control - bool public isOpened = false; - address public admin; address public operator; - mapping(address => bool) public whitelist; Counters.Counter private _tokenIds; + uint256 public taxRate; + // tokenId => Board mapping(uint256 => Board) public boards; @@ -30,48 +29,19 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { mapping(address => TaxTreasury) public taxTreasury; constructor( - address admin_, address operator_, string memory name_, - string memory symbol_ + string memory symbol_, + uint256 taxRate_ ) ERC721(name_, symbol_) { - admin = admin_; operator = operator_; - whitelist[admin_] = true; + taxRate = taxRate_; } ////////////////////////////// /// Modifier ////////////////////////////// - modifier isValidAddress(address value_) { - if (value_ == address(0)) { - revert InvalidAddress(); - } - _; - } - - modifier isBoardCreator(uint256 tokenId_, address value_) { - if (value_ != boards[tokenId_].creator) { - revert Unauthorized("board creator"); - } - _; - } - - modifier isBoardTenant(uint256 tokenId_, address value_) { - if (value_ != _ownerOf(tokenId_)) { - revert Unauthorized("board tenant"); - } - _; - } - - modifier isAdmin(address value_) { - if (value_ != admin) { - revert Unauthorized("admin"); - } - _; - } - modifier isFromOperator() { if (msg.sender != operator) { revert Unauthorized("operator"); @@ -80,111 +50,91 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setIsOpened(bool value_, address sender_) external isAdmin(sender_) isFromOperator { - isOpened = value_; + function mint(address to_) external isFromOperator returns (uint256 tokenId) { + _tokenIds.increment(); + uint256 newTokenId = _tokenIds.current(); + + _safeMint(to_, newTokenId); + + Board memory newBoard = Board({creator: to_}); + boards[newTokenId] = newBoard; + + // TODO + // emit Mint(newBoardId, to_); + + return newTokenId; } /// @inheritdoc IBillboardRegistry - function addToWhitelist(address value_, address sender_) - external - isValidAddress(value_) - isAdmin(sender_) - isFromOperator - { - whitelist[value_] = true; + function setBoard( + uint256 tokenId_, + string memory name_, + string memory description_, + string memory location_ + ) external isFromOperator { + boards[tokenId_].name = name_; + boards[tokenId_].description = description_; + boards[tokenId_].location = location_; } /// @inheritdoc IBillboardRegistry - function removeFromWhitelist(address value_, address sender_) - external - isValidAddress(value_) - isAdmin(sender_) - isFromOperator - { - delete whitelist[value_]; + function setBoard(uint256 tokenId_, string memory contentUri_, string memory redirectUri_) external isFromOperator { + boards[tokenId_].contentUri_ = contentUri_; + boards[tokenId_].redirectUri_ = redirectUri_; } /// @inheritdoc IBillboardRegistry - function mint(address to_, address sender_) external isValidAddress(to_) isFromOperator returns (uint256 tokenId) { - if (isOpened == false && whitelist[sender_] != true) { - revert Unauthorized("creator"); - } - - _tokenIds.increment(); - uint256 newBoardId = _tokenIds.current(); - - _safeMint(to_, newBoardId); - - Board memory newBoard = Board({ - creator: to_, - tenant: to_, - lastHighestBidPrice: 0, - name: "", - description: "", - contentURI: "", - redirectURI: "", - location: "" - }); - boards[newBoardId] = newBoard; - - emit Mint(newBoardId, to_); + function newAuction(uint256 tokenId_, uint256 startAt_, uint256 endAt_) external returns (uint256 auctionId) { + auctionId = lastBoardAuctionId[tokenId_]++; - return newBoardId; + Auction({startAt: startAt_, endAt: endAt_, tokenId: tokenId_}); } /// @inheritdoc IBillboardRegistry - function getBoard(uint256 tokenId_) external view returns (Board memory board) { - return boards[tokenId_]; + function setAuction(uint256 tokenId_, uint256 auctionId_, uint256 startAt_, uint256 endAt_) external { + boardAuctions[tokenId_][auctionId_].startAt = startAt_; + boardAuctions[tokenId_][auctionId_].endAt = endAt_; } /// @inheritdoc IBillboardRegistry - function setBoardName( - uint256 tokenId_, - string memory name_, - address sender_ - ) external isBoardCreator(tokenId_, sender_) { - boards[tokenId_].name = name_; - } + function newBid(uint256 tokenId_, uint256 auctionId_, address bidder_, uint256 price_, uint256 tax_) external { + Bid bid = Bid({ + bidder: bidder_, + price: price_, + tax: tax_, + auctionId: auctionId_, + isWithdrawn: false, + isWon: false + }); - /// @inheritdoc IBillboardRegistry - function setBoardDescription( - uint256 tokenId_, - string memory description_, - address sender_ - ) external isBoardCreator(tokenId_, sender_) { - boards[tokenId_].description = description_; + boardAuctions[tokenId_][auctionId_].bids.push(bid); } /// @inheritdoc IBillboardRegistry - function setBoardLocation( - uint256 tokenId_, - string memory location_, - address sender_ - ) external isBoardCreator(tokenId_, sender_) { - boards[tokenId_].location = location_; + function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_, bool isWithdrawn_) external { + boardAuctions[tokenId_][auctionId_].bids[bidder_].isWon = isWon_; + boardAuctions[tokenId_][auctionId_].bids[bidder_].isWithdrawn = isWithdrawn_; } /// @inheritdoc IBillboardRegistry - function setBoardContentURI( - uint256 tokenId_, - string memory uri_, - address sender_ - ) external isBoardTenant(tokenId_, sender_) { - boards[tokenId_].contentURI = uri_; + function transferBidAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external { + uint256 amount = boardAuctions[tokenId_][auctionId_].bids[bidder_].price; + + (bool success, ) = to_.call{value: amount}(""); + if (!success) { + revert TransferFailed(); + } } /// @inheritdoc IBillboardRegistry - function setBoardRedirectURI( - uint256 tokenId_, - string memory redirectURI_, - address sender_ - ) external isBoardTenant(tokenId_, sender_) { - boards[tokenId_].redirectURI = redirectURI_; + function setTaxRate(uint256 taxRate_) external { + taxRate = taxRate_; } /// @inheritdoc IBillboardRegistry - function setBoardLastHighestBidPrice(uint256 tokenId_, uint256 price_) external isFromOperator { - boards[tokenId_].lastHighestBidPrice = price_; + function setTaxTreasury(address owner_, uint256 accumulated_, uint256 withdrawn_) external { + taxTreasury[owner_].accumulated = accumulated_; + taxTreasury[owner_].withdrawn = withdrawn_; } ////////////////////////////// @@ -212,11 +162,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /** * @notice See {IERC721-transferFrom}. */ - function transferFrom( - address from_, - address to_, - uint256 tokenId_ - ) public override(ERC721, IERC721) { + function transferFrom(address from_, address to_, uint256 tokenId_) public override(ERC721, IERC721) { safeTransferFrom(from_, to_, tokenId_, ""); } @@ -228,7 +174,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address to_, uint256 tokenId_, bytes memory data_ - ) public override(ERC721, IERC721) isValidAddress(from_) isValidAddress(to_) { + ) public override(ERC721, IERC721) { if (!_isApprovedOrOwner(msg.sender, tokenId_)) { revert Unauthorized("not owner nor approved"); } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 0703df1..a4d8259 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -8,8 +8,6 @@ interface IBillboard { /// Error ////////////////////////////// - error AdminNotFound(); - error InvalidAddress(); error Unauthorized(string type_); @@ -127,10 +125,10 @@ interface IBillboard { * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of a board. */ - function getAuction(uint256 tokenId_, uint256 auctionId_) - external - view - returns (IBillboardRegistry.Auction memory auction); + function getAuction( + uint256 tokenId_, + uint256 auctionId_ + ) external view returns (IBillboardRegistry.Auction memory auction); /** * @notice Clear a board auction. @@ -195,15 +193,7 @@ interface IBillboard { uint256 tokenId_, uint256 limit_, uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - IBillboardRegistry.Bid[] memory bids - ); + ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids); /** * @notice Get bids of a board auction by auction ID. @@ -223,15 +213,7 @@ interface IBillboard { uint256 auctionId_, uint256 limit_, uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - IBillboardRegistry.Bid[] memory bids - ); + ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids); ////////////////////////////// /// Tax & Withdraw @@ -266,9 +248,5 @@ interface IBillboard { * @param auctionId_ Auction ID of a board. * @param bidder_ Address of a auction bidder. */ - function withdrawBid( - uint256 tokenId_, - uint256 auctionId_, - address bidder_ - ) external; + function withdrawBid(uint256 tokenId_, uint256 auctionId_, address bidder_) external; } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 4e1b890..a4b7980 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -8,18 +8,14 @@ interface IBillboardRegistry is IERC721 { /// Error ////////////////////////////// - error AdminNotFound(); - - error BoardNotFound(); - - error InvalidBoardId(); - error InvalidAddress(); - error OperatorNotFound(); - error Unauthorized(string type_); + error ZeroAmount(); + + error TransferFailed(); + ////////////////////////////// /// Event ////////////////////////////// @@ -87,7 +83,8 @@ interface IBillboardRegistry is IERC721 { function mintBoard(address to_) external returns (uint256 tokenId); /** - * @notice Set the name, description and location of a board. + * @notice Set the name, description and location of a board + * from board creator. * * @param tokenId_ Token ID of a board. * @param name_ Board name. @@ -102,17 +99,14 @@ interface IBillboardRegistry is IERC721 { ) external; /** - * @notice Set the content URI and redirect URI of a board. + * @notice Set the content URI and redirect URI of a board + * from board tenant * * @param tokenId_ Token ID of a board. * @param contentUri_ Content URI of a board. * @param redirectURI_ Redirect URI when users clicking. */ - function setBoard( - uint256 tokenId_, - string memory contentUri_, - string memory redirectUri_ - ) external; + function setBoard(uint256 tokenId_, string memory contentUri_, string memory redirectUri_) external; ////////////////////////////// /// Auction @@ -125,11 +119,7 @@ interface IBillboardRegistry is IERC721 { * @param startAt_ Start time of an auction. * @param endAt_ End time of an auction. */ - function newAuction( - uint256 tokenId_, - uint256 startAt_, - uint256 endAt_ - ) external returns (uint256 auctionId_); + function newAuction(uint256 tokenId_, uint256 startAt_, uint256 endAt_) external returns (uint256 auctionId); /** * @notice Set the data of an auction @@ -139,12 +129,7 @@ interface IBillboardRegistry is IERC721 { * @param startAt_ Start time of an auction. * @param endAt_ End time of an auction. */ - function setAuction( - uint256 tokenId_, - uint256 auctionId_, - uint256 startAt_, - uint256 endAt_ - ) external; + function setAuction(uint256 tokenId_, uint256 auctionId_, uint256 startAt_, uint256 endAt_) external; /** * @notice Create new bid and add it to auction @@ -161,13 +146,7 @@ interface IBillboardRegistry is IERC721 { * @param price_ Price of a bid. * @param tax_ Tax of a bid. */ - function newBid( - uint256 tokenId_, - uint256 auctionId_, - address bidder_, - uint256 price_, - uint256 tax_ - ) external; + function newBid(uint256 tokenId_, uint256 auctionId_, address bidder_, uint256 price_, uint256 tax_) external; /** * @notice Set the data of a bid @@ -177,28 +156,17 @@ interface IBillboardRegistry is IERC721 { * @param bidder_ Bidder of an auction. * @param isWon_ Whether a bid is won. */ - function setBid( - uint256 tokenId_, - uint256 auctionId_, - address bidder_, - bool isWon, - bool isWithdrawn - ) external; + function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon, bool isWithdrawn) external; /** - * @notice Transfer amount of bid price to current board owner (last auction highest bidder) + * @notice Transfer amount of bid price to current board owner (last tenant) * * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of the highest bid. * @param to_ Address of a receiver. */ - function transferBidAmount( - uint256 tokenId_, - uint256 auctionId_, - address bidder_, - address to_ - ) external; + function transferBidAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external; /** * @notice Set the global tax rate. @@ -214,9 +182,5 @@ interface IBillboardRegistry is IERC721 { * @param accumulated_ Accumulated tax. * @param withdrawn_ Withdrawn tax. */ - function setTaxTreasury( - address owner_, - uint256 accumulated_, - uint256 withdrawn_ - ) external; + function setTaxTreasury(address owner_, uint256 accumulated_, uint256 withdrawn_) external; } diff --git a/src/Curation/Curation.sol b/src/Curation/Curation.sol index 5ffa7a4..391c42e 100644 --- a/src/Curation/Curation.sol +++ b/src/Curation/Curation.sol @@ -14,12 +14,7 @@ contract Curation is ICuration { } /// @inheritdoc ICuration - function curate( - address to_, - IERC20 token_, - uint256 amount_, - string calldata uri_ - ) public { + function curate(address to_, IERC20 token_, uint256 amount_, string calldata uri_) public { if (to_ == address(0)) revert ZeroAddress(); if (amount_ <= 0) revert ZeroAmount(); if (bytes(uri_).length == 0) revert InvalidURI(); diff --git a/src/Curation/ICuration.sol b/src/Curation/ICuration.sol index 1fa8181..df00828 100644 --- a/src/Curation/ICuration.sol +++ b/src/Curation/ICuration.sol @@ -65,12 +65,7 @@ interface ICuration { * @param amount_ Amount of tokens to curate. * @param uri_ Content URI. */ - function curate( - address to_, - IERC20 token_, - uint256 amount_, - string calldata uri_ - ) external; + function curate(address to_, IERC20 token_, uint256 amount_, string calldata uri_) external; /** * @notice Curate content by native token donation. diff --git a/src/Logbook/ILogbook.sol b/src/Logbook/ILogbook.sol index a7efc1f..294d845 100644 --- a/src/Logbook/ILogbook.sol +++ b/src/Logbook/ILogbook.sol @@ -181,11 +181,7 @@ interface ILogbook is IRoyalty, IERC721 { * @param commission_ Address (frontend operator) to earn commission * @param commissionBPS_ Basis points of the commission */ - function donateWithCommission( - uint256 tokenId_, - address commission_, - uint256 commissionBPS_ - ) external payable; + function donateWithCommission(uint256 tokenId_, address commission_, uint256 commissionBPS_) external payable; /** * @notice Get a logbook diff --git a/src/Logbook/Logbook.sol b/src/Logbook/Logbook.sol index e318e0e..1e3743e 100644 --- a/src/Logbook/Logbook.sol +++ b/src/Logbook/Logbook.sol @@ -128,11 +128,7 @@ contract Logbook is ERC721, Ownable, ILogbook, Royalty { } /// @inheritdoc ILogbook - function donateWithCommission( - uint256 tokenId_, - address commission_, - uint256 commissionBPS_ - ) external payable { + function donateWithCommission(uint256 tokenId_, address commission_, uint256 commissionBPS_) external payable { if (msg.value <= 0) revert ZeroAmount(); if (!_exists(tokenId_)) revert TokenNotExists(); if (commissionBPS_ > _ROYALTY_BPS_COMMISSION_MAX) revert InvalidBPS(0, _ROYALTY_BPS_COMMISSION_MAX); @@ -151,11 +147,9 @@ contract Logbook is ERC721, Ownable, ILogbook, Royalty { } /// @inheritdoc ILogbook - function getLogs(uint256 tokenId_) - external - view - returns (bytes32[] memory contentHashes, address[] memory authors) - { + function getLogs( + uint256 tokenId_ + ) external view returns (bytes32[] memory contentHashes, address[] memory authors) { Book memory book = _books[tokenId_]; uint32 logCount = book.logCount; @@ -398,11 +392,7 @@ contract Logbook is ERC721, Ownable, ILogbook, Royalty { } } - function _afterTokenTransfer( - address from_, - address to_, - uint256 tokenId_ - ) internal virtual override { + function _afterTokenTransfer(address from_, address to_, uint256 tokenId_) internal virtual override { super._afterTokenTransfer(from_, to_, tokenId_); // Call parent hook _books[tokenId_].transferCount++; diff --git a/src/Snapper/Snapper.sol b/src/Snapper/Snapper.sol index ef0de99..9230b73 100644 --- a/src/Snapper/Snapper.sol +++ b/src/Snapper/Snapper.sol @@ -77,11 +77,7 @@ contract Snapper is Ownable { * @param initBlock_ The Contract Creation block number of The Space contract. * @param snapshotCid_ The initial pixels picture IPFS CID of The Space. */ - function initRegion( - uint256 regionId, - uint256 initBlock_, - string calldata snapshotCid_ - ) external onlyOwner { + function initRegion(uint256 regionId, uint256 initBlock_, string calldata snapshotCid_) external onlyOwner { if (_latestSnapshots[regionId].block != 0) revert CannotBeReInitialized(regionId); _latestSnapshots[regionId].block = initBlock_; diff --git a/src/TheSpace/ACLManager.sol b/src/TheSpace/ACLManager.sol index 16eb3d5..fd018ba 100644 --- a/src/TheSpace/ACLManager.sol +++ b/src/TheSpace/ACLManager.sol @@ -9,11 +9,7 @@ import "./IACLManager.sol"; contract ACLManager is IACLManager, Context { mapping(Role => address) private _roles; - constructor( - address aclManager_, - address marketAdmin_, - address treasuryAdmin_ - ) { + constructor(address aclManager_, address marketAdmin_, address treasuryAdmin_) { if (aclManager_ == address(0)) revert ZeroAddress(); _transferRole(Role.aclManager, aclManager_); diff --git a/src/TheSpace/ITheSpace.sol b/src/TheSpace/ITheSpace.sol index f3bd559..e35f474 100644 --- a/src/TheSpace/ITheSpace.sol +++ b/src/TheSpace/ITheSpace.sol @@ -126,12 +126,7 @@ interface ITheSpace { * @param newPrice_ New price to be set. * @param color_ Color to be set. */ - function setPixel( - uint256 tokenId_, - uint256 bidPrice_, - uint256 newPrice_, - uint256 color_ - ) external; + function setPixel(uint256 tokenId_, uint256 bidPrice_, uint256 newPrice_, uint256 color_) external; /** * @notice Set color for a pixel. @@ -167,15 +162,7 @@ interface ITheSpace { address owner_, uint256 limit_, uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - ITheSpaceRegistry.Pixel[] memory pixels - ); + ) external view returns (uint256 total, uint256 limit, uint256 offset, ITheSpaceRegistry.Pixel[] memory pixels); ////////////////////////////// /// Trading diff --git a/src/TheSpace/ITheSpaceRegistry.sol b/src/TheSpace/ITheSpaceRegistry.sol index be9d01a..1149314 100644 --- a/src/TheSpace/ITheSpaceRegistry.sol +++ b/src/TheSpace/ITheSpaceRegistry.sol @@ -189,11 +189,7 @@ interface ITheSpaceRegistry is IERC721Enumerable { * @param color_ Color Id. * @param owner_ Token owner. */ - function setColor( - uint256 tokenId_, - uint256 color_, - address owner_ - ) external; + function setColor(uint256 tokenId_, uint256 color_, address owner_) external; ////////////////////////////// /// Event emission @@ -202,29 +198,17 @@ interface ITheSpaceRegistry is IERC721Enumerable { /** * @dev Emit {Tax} event */ - function emitTax( - uint256 tokenId_, - address taxpayer_, - uint256 amount_ - ) external; + function emitTax(uint256 tokenId_, address taxpayer_, uint256 amount_) external; /** * @dev Emit {Price} event */ - function emitPrice( - uint256 tokenId_, - uint256 price_, - address operator_ - ) external; + function emitPrice(uint256 tokenId_, uint256 price_, address operator_) external; /** * @dev Emit {UBI} event */ - function emitUBI( - uint256 tokenId_, - address recipient_, - uint256 amount_ - ) external; + function emitUBI(uint256 tokenId_, address recipient_, uint256 amount_) external; /** * @dev Emit {Treasury} event @@ -234,12 +218,7 @@ interface ITheSpaceRegistry is IERC721Enumerable { /** * @dev Emit {Deal} event */ - function emitDeal( - uint256 tokenId_, - address from_, - address to_, - uint256 amount_ - ) external; + function emitDeal(uint256 tokenId_, address from_, address to_, uint256 amount_) external; ////////////////////////////// /// ERC721 property related @@ -258,11 +237,7 @@ interface ITheSpaceRegistry is IERC721Enumerable { /** * @dev Perform ERC721 token transfer by market contract. */ - function safeTransferByMarket( - address from_, - address to_, - uint256 tokenId_ - ) external; + function safeTransferByMarket(address from_, address to_, uint256 tokenId_) external; /** * @dev If an ERC721 token has been minted. @@ -286,9 +261,5 @@ interface ITheSpaceRegistry is IERC721Enumerable { /** * @dev Perform ERC20 token transferFrom by market contract. */ - function transferCurrencyFrom( - address from_, - address to_, - uint256 amount_ - ) external; + function transferCurrencyFrom(address from_, address to_, uint256 amount_) external; } diff --git a/src/TheSpace/SpaceToken.sol b/src/TheSpace/SpaceToken.sol index 4223cbc..aeefbff 100644 --- a/src/TheSpace/SpaceToken.sol +++ b/src/TheSpace/SpaceToken.sol @@ -19,15 +19,15 @@ contract SpaceToken is ERC20 { uint256 lpTokens ) ERC20("The Space", "SPACE") { // Early Incentives - _mint(incentives, incentivesTokens * (10**uint256(decimals()))); + _mint(incentives, incentivesTokens * (10 ** uint256(decimals()))); // Community Treasury - _mint(treasury, treasuryTokens * (10**uint256(decimals()))); + _mint(treasury, treasuryTokens * (10 ** uint256(decimals()))); // Team - _mint(team, teamTokens * (10**uint256(decimals()))); + _mint(team, teamTokens * (10 ** uint256(decimals()))); // Liquidity Pool - _mint(lp, lpTokens * (10**uint256(decimals()))); + _mint(lp, lpTokens * (10 ** uint256(decimals()))); } } diff --git a/src/TheSpace/TheSpace.sol b/src/TheSpace/TheSpace.sol index 8fcdb83..9a6e3c1 100644 --- a/src/TheSpace/TheSpace.sol +++ b/src/TheSpace/TheSpace.sol @@ -37,7 +37,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { 1000000, // total supply 12, // taxRate 0, // treasuryShare - 1 * (10**uint256(ERC20(currencyAddress_).decimals())), // mintTax, 1 $SPACE + 1 * (10 ** uint256(ERC20(currencyAddress_).decimals())), // mintTax, 1 $SPACE currencyAddress_ ); } @@ -115,12 +115,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { } /// @inheritdoc ITheSpace - function setPixel( - uint256 tokenId_, - uint256 bidPrice_, - uint256 newPrice_, - uint256 color_ - ) external { + function setPixel(uint256 tokenId_, uint256 bidPrice_, uint256 newPrice_, uint256 color_) external { bid(tokenId_, bidPrice_); setPrice(tokenId_, newPrice_); _setColor(tokenId_, color_, msg.sender); @@ -133,11 +128,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { _setColor(tokenId_, color_, registry.ownerOf(tokenId_)); } - function _setColor( - uint256 tokenId_, - uint256 color_, - address owner_ - ) internal { + function _setColor(uint256 tokenId_, uint256 color_, address owner_) internal { if (registry.pixelColor(tokenId_) == color_) return; registry.setColor(tokenId_, color_, owner_); @@ -153,16 +144,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { address owner_, uint256 limit_, uint256 offset_ - ) - external - view - returns ( - uint256 total, - uint256 limit, - uint256 offset, - ITheSpaceRegistry.Pixel[] memory pixels - ) - { + ) external view returns (uint256 total, uint256 limit, uint256 offset, ITheSpaceRegistry.Pixel[] memory pixels) { uint256 _total = registry.balanceOf(owner_); if (limit_ == 0) { return (_total, limit_, offset_, new ITheSpaceRegistry.Pixel[](0)); @@ -217,11 +199,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { _setPrice(tokenId_, price_, registry.ownerOf(tokenId_)); } - function _setPrice( - uint256 tokenId_, - uint256 price_, - address operator_ - ) private { + function _setPrice(uint256 tokenId_, uint256 price_, address operator_) private { // max price to prevent overflow of `_getTax` uint256 maxPrice = registry.currency().totalSupply(); if (price_ > maxPrice) revert PriceTooHigh(maxPrice); @@ -363,11 +341,7 @@ contract TheSpace is ITheSpace, Multicall, ReentrancyGuard, ACLManager { /** * @notice Update tax record and emit Tax event. */ - function _recordTax( - uint256 tokenId_, - address taxpayer_, - uint256 amount_ - ) private { + function _recordTax(uint256 tokenId_, address taxpayer_, uint256 amount_) private { // calculate treasury change uint256 treasuryShare = registry.taxConfig(ITheSpaceRegistry.ConfigOptions.treasuryShare); uint256 treasuryAdded = (amount_ * treasuryShare) / 10000; diff --git a/src/TheSpace/TheSpaceRegistry.sol b/src/TheSpace/TheSpaceRegistry.sol index 8dd2b3d..94ceafc 100644 --- a/src/TheSpace/TheSpaceRegistry.sol +++ b/src/TheSpace/TheSpaceRegistry.sol @@ -116,11 +116,7 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { } /// @inheritdoc ITheSpaceRegistry - function setColor( - uint256 tokenId_, - uint256 color_, - address owner_ - ) external onlyOwner { + function setColor(uint256 tokenId_, uint256 color_, address owner_) external onlyOwner { pixelColor[tokenId_] = color_; emit Color(tokenId_, color_, owner_); } @@ -130,29 +126,17 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { ////////////////////////////// /// @inheritdoc ITheSpaceRegistry - function emitTax( - uint256 tokenId_, - address taxpayer_, - uint256 amount_ - ) external onlyOwner { + function emitTax(uint256 tokenId_, address taxpayer_, uint256 amount_) external onlyOwner { emit Tax(tokenId_, taxpayer_, amount_); } /// @inheritdoc ITheSpaceRegistry - function emitPrice( - uint256 tokenId_, - uint256 price_, - address operator_ - ) external onlyOwner { + function emitPrice(uint256 tokenId_, uint256 price_, address operator_) external onlyOwner { emit Price(tokenId_, price_, operator_); } /// @inheritdoc ITheSpaceRegistry - function emitUBI( - uint256 tokenId_, - address recipient_, - uint256 amount_ - ) external onlyOwner { + function emitUBI(uint256 tokenId_, address recipient_, uint256 amount_) external onlyOwner { emit UBI(tokenId_, recipient_, amount_); } @@ -162,12 +146,7 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { } /// @inheritdoc ITheSpaceRegistry - function emitDeal( - uint256 tokenId_, - address from_, - address to_, - uint256 amount_ - ) external onlyOwner { + function emitDeal(uint256 tokenId_, address from_, address to_, uint256 amount_) external onlyOwner { emit Deal(tokenId_, from_, to_, amount_); } @@ -187,11 +166,7 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { } /// @inheritdoc ITheSpaceRegistry - function safeTransferByMarket( - address from_, - address to_, - uint256 tokenId_ - ) external onlyOwner { + function safeTransferByMarket(address from_, address to_, uint256 tokenId_) external onlyOwner { _safeTransfer(from_, to_, tokenId_, ""); } @@ -209,11 +184,7 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { * @notice See {IERC721-transferFrom}. * @dev Override to collect tax and set price before transfer. */ - function transferFrom( - address from_, - address to_, - uint256 tokenId_ - ) public override(ERC721, IERC721) { + function transferFrom(address from_, address to_, uint256 tokenId_) public override(ERC721, IERC721) { safeTransferFrom(from_, to_, tokenId_, ""); } @@ -257,11 +228,7 @@ contract TheSpaceRegistry is ITheSpaceRegistry, ERC721Enumerable, Ownable { } /// @inheritdoc ITheSpaceRegistry - function transferCurrencyFrom( - address from_, - address to_, - uint256 amount_ - ) external onlyOwner { + function transferCurrencyFrom(address from_, address to_, uint256 amount_) external onlyOwner { currency.transferFrom(from_, to_, amount_); } } diff --git a/src/test/Curation/Curation.t.sol b/src/test/Curation/Curation.t.sol index a232dce..8449abd 100644 --- a/src/test/Curation/Curation.t.sol +++ b/src/test/Curation/Curation.t.sol @@ -41,7 +41,7 @@ contract CurationTest is Test { // deploy ERC-20 token usdt = new USDT(CURATOR, 1000); - assertEq(usdt.balanceOf(CURATOR), 1000 * (10**uint256(usdt.decimals()))); + assertEq(usdt.balanceOf(CURATOR), 1000 * (10 ** uint256(usdt.decimals()))); assertEq(usdt.balanceOf(CREATOR), 0); vm.prank(CURATOR); usdt.approve(address(curation), type(uint256).max); @@ -58,7 +58,7 @@ contract CurationTest is Test { * Curation: ERC-20 token */ function testERC20Curation() public { - uint256 amount = 10 * (10**uint256(usdt.decimals())); + uint256 amount = 10 * (10 ** uint256(usdt.decimals())); string memory uri = "ipfs://Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a"; uint256 curatorBalance = usdt.balanceOf(CURATOR); @@ -73,7 +73,7 @@ contract CurationTest is Test { } function testCannotCurateERC20IfNotApproval() public { - uint256 amount = 10 * (10**uint256(usdt.decimals())); + uint256 amount = 10 * (10 ** uint256(usdt.decimals())); string memory uri = "ipfs://Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a"; vm.startPrank(CURATOR); @@ -89,7 +89,7 @@ contract CurationTest is Test { } function testCannotCurateERC20ZeroAddress() public { - uint256 amount = 10 * (10**uint256(usdt.decimals())); + uint256 amount = 10 * (10 ** uint256(usdt.decimals())); string memory uri = "ipfs://Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a"; vm.expectRevert(abi.encodeWithSignature("ZeroAddress()")); @@ -106,7 +106,7 @@ contract CurationTest is Test { } function testCannotCurateERC20EmptyURI() public { - uint256 amount = 10 * (10**uint256(usdt.decimals())); + uint256 amount = 10 * (10 ** uint256(usdt.decimals())); string memory uri = ""; vm.expectRevert(abi.encodeWithSignature("InvalidURI()")); @@ -115,7 +115,7 @@ contract CurationTest is Test { } function testCannotCurateERC20SelfCuration() public { - uint256 amount = 10 * (10**uint256(usdt.decimals())); + uint256 amount = 10 * (10 ** uint256(usdt.decimals())); string memory uri = "ipfs://Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a"; vm.expectRevert(abi.encodeWithSignature("SelfCuration()")); diff --git a/src/test/Curation/USDT.sol b/src/test/Curation/USDT.sol index 2a8b383..61882bc 100644 --- a/src/test/Curation/USDT.sol +++ b/src/test/Curation/USDT.sol @@ -5,6 +5,6 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; contract USDT is ERC20 { constructor(address account_, uint256 amount_) ERC20("USDT", "USDT") { - _mint(account_, amount_ * (10**uint256(decimals()))); + _mint(account_, amount_ * (10 ** uint256(decimals()))); } } diff --git a/src/test/Logbook/Logbook.t.sol b/src/test/Logbook/Logbook.t.sol index 2f5269e..edfc081 100644 --- a/src/test/Logbook/Logbook.t.sol +++ b/src/test/Logbook/Logbook.t.sol @@ -578,11 +578,7 @@ contract LogbookTest is Test { assertEq(forkCount + 1, authors.length); } - function testForkWithCommission( - uint96 amount, - string calldata content, - uint256 bps - ) public { + function testForkWithCommission(uint96 amount, string calldata content, uint256 bps) public { bool isInvalidBPS = bps > _ROYALTY_BPS_COMMISSION_MAX; _claimToTraveloggersOwner(); @@ -610,11 +606,7 @@ contract LogbookTest is Test { /** * Split Royalty, Withdraw */ - function testSplitRoyalty( - uint8 logCount, - uint8 endAt, - uint96 forkPrice - ) public { + function testSplitRoyalty(uint8 logCount, uint8 endAt, uint96 forkPrice) public { vm.assume(logCount <= 64); _claimToTraveloggersOwner(); diff --git a/src/test/Logbook/LogbookNFTSVG.t.sol b/src/test/Logbook/LogbookNFTSVG.t.sol index 001208a..54a0f42 100644 --- a/src/test/Logbook/LogbookNFTSVG.t.sol +++ b/src/test/Logbook/LogbookNFTSVG.t.sol @@ -47,11 +47,7 @@ contract LogbookNFTSVGTest is Test { vm.label(DEPLOYER, "DEPLOYER"); } - function testTokenURI( - uint8 transfers, - uint8 logsPerTransfer, - uint16 tokenId - ) public { + function testTokenURI(uint8 transfers, uint8 logsPerTransfer, uint16 tokenId) public { vm.assume(transfers < 64 && transfers > 0); vm.assume(logsPerTransfer < 3 && logsPerTransfer > 0); vm.assume(tokenId <= CLAIM_TOKEN_END_ID && tokenId >= CLAIM_TOKEN_START_ID); diff --git a/src/test/TheSpace/BaseTheSpace.t.sol b/src/test/TheSpace/BaseTheSpace.t.sol index 9708dc5..48c2457 100644 --- a/src/test/TheSpace/BaseTheSpace.t.sol +++ b/src/test/TheSpace/BaseTheSpace.t.sol @@ -73,10 +73,10 @@ contract BaseTheSpaceTest is Test { LP, LP_TOKENS ); - assertEq(currency.balanceOf(TREASURY), TREASURY_TOKENS * (10**uint256(currency.decimals()))); - assertEq(currency.balanceOf(TEAM), TEAM_TOKENS * (10**uint256(currency.decimals()))); + assertEq(currency.balanceOf(TREASURY), TREASURY_TOKENS * (10 ** uint256(currency.decimals()))); + assertEq(currency.balanceOf(TEAM), TEAM_TOKENS * (10 ** uint256(currency.decimals()))); - PIXEL_PRICE = 1000 * (10**uint256(currency.decimals())); + PIXEL_PRICE = 1000 * (10 ** uint256(currency.decimals())); // deploy the space vm.expectEmit(true, false, false, false); @@ -138,11 +138,7 @@ contract BaseTheSpaceTest is Test { thespace.bid(PIXEL_ID, bidPrice); } - function _bidAs( - address bidder, - uint256 bidPrice, - uint256 newPrice - ) internal { + function _bidAs(address bidder, uint256 bidPrice, uint256 newPrice) internal { vm.prank(bidder); thespace.bid(PIXEL_ID, bidPrice); diff --git a/src/test/TheSpace/TheSpace.t.sol b/src/test/TheSpace/TheSpace.t.sol index acf32da..f62e7d4 100644 --- a/src/test/TheSpace/TheSpace.t.sol +++ b/src/test/TheSpace/TheSpace.t.sol @@ -155,7 +155,7 @@ contract TheSpaceTest is BaseTheSpaceTest { function testSetMintTax() public { // set mint tax - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); vm.expectEmit(true, true, false, false); emit Config(CONFIG_MINT_TAX, mintTax); _setMintTax(mintTax); @@ -198,7 +198,7 @@ contract TheSpaceTest is BaseTheSpaceTest { * @dev Pixel */ function testGetNonExistingPixel() public { - uint256 mintTax = 10 * (10**uint256(currency.decimals())); + uint256 mintTax = 10 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); ITheSpaceRegistry.Pixel memory pixel = thespace.getPixel(PIXEL_ID); @@ -569,7 +569,7 @@ contract TheSpaceTest is BaseTheSpaceTest { assertLt(currency.balanceOf(PIXEL_OWNER_1), tax); // set mint tax - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); // bid and token will be defaulted @@ -617,7 +617,7 @@ contract TheSpaceTest is BaseTheSpaceTest { _bidAs(PIXEL_OWNER_1, PIXEL_PRICE - 1); // price too low to bid a non-existing token - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); vm.expectRevert(abi.encodeWithSignature("PriceTooLow()")); @@ -626,7 +626,7 @@ contract TheSpaceTest is BaseTheSpaceTest { function testCannotBidExceedAllowance() public { // set mint tax - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); // revoke currency approval @@ -694,7 +694,7 @@ contract TheSpaceTest is BaseTheSpaceTest { assertEq(registry.balanceOf(PIXEL_OWNER), 0); // price was reset - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); assertEq(thespace.getPrice(PIXEL_ID), mintTax); @@ -850,7 +850,7 @@ contract TheSpaceTest is BaseTheSpaceTest { assertEq(thespace.getOwner(PIXEL_ID), address(0)); // price was reset to mint tax since it was burned - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); assertEq(thespace.getPrice(PIXEL_ID), mintTax); @@ -875,7 +875,7 @@ contract TheSpaceTest is BaseTheSpaceTest { assertEq(thespace.getTax(PIXEL_ID), 0); // price was reset to zero - uint256 mintTax = 50 * (10**uint256(currency.decimals())); + uint256 mintTax = 50 * (10 ** uint256(currency.decimals())); _setMintTax(mintTax); assertEq(thespace.getPrice(PIXEL_ID), 0); } From 490cbd1c56d73db8c8f3419d1fe6f8a6c4e4bffd Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 12 Nov 2023 16:58:03 +0800 Subject: [PATCH 16/55] feat(billboard): impls getters and basic setters --- src/Billboard/Billboard.sol | 113 +++++++++++++++++++++------ src/Billboard/BillboardRegistry.sol | 73 ++++++++++++----- src/Billboard/IBillboard.sol | 61 ++++++--------- src/Billboard/IBillboardRegistry.sol | 41 +++++++--- 4 files changed, 199 insertions(+), 89 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index cc0234a..9e5b4e9 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -15,6 +15,7 @@ contract Billboard is IBillboard { constructor() { admin = msg.sender; + whitelist[msg.sender] = true; } ////////////////////////////// @@ -37,14 +38,14 @@ contract Billboard is IBillboard { modifier isFromBoardCreator(uint256 tokenId_) { if (msg.sender != boards[tokenId_].creator) { - revert Unauthorized("board creator"); + revert Unauthorized("creator"); } _; } modifier isFromBoardTenant(uint256 tokenId_) { if (msg.sender != _ownerOf(tokenId_)) { - revert Unauthorized("board tenant"); + revert Unauthorized("tenant"); } _; } @@ -79,7 +80,15 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external isValidAddress(to_) { - registry.mint(to_, msg.sender); + if (!isOpened) { + revert MintClosed(); + } + + if (!whitelist[msg.sender]) { + revert Unauthorized("whitelist"); + } + + registry.mint(to_); } /// @inheritdoc IBillboard @@ -88,28 +97,28 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function setBoardName(uint256 tokenId_, string memory name_) external isFromBoardCreator { + function setBoardName(uint256 tokenId_, string calldata name_) external isFromBoardCreator { registry.setBoardName(tokenId_, name_); } /// @inheritdoc IBillboard - function setBoardDescription(uint256 tokenId_, string memory description_) external { - registry.setBoardDescription(tokenId_, description_, msg.sender); + function setBoardDescription(uint256 tokenId_, string calldata description_) external isFromBoardCreator { + registry.setBoardDescription(tokenId_, description_); } /// @inheritdoc IBillboard - function setBoardLocation(uint256 tokenId_, string memory location_) external { - registry.setBoardLocation(tokenId_, location_, msg.sender); + function setBoardLocation(uint256 tokenId_, string calldata location_) external isFromBoardCreator { + registry.setBoardLocation(tokenId_, location_); } /// @inheritdoc IBillboard - function setBoardContentURI(uint256 tokenId_, string memory uri_) external { - registry.setBoardContentURI(tokenId_, uri_, msg.sender); + function setBoardLocation(uint256 tokenId_, string calldata contentUri_) external isFromBoardCreator { + registry.setBoardContentUri(tokenId_, contentUri_); } /// @inheritdoc IBillboard - function setBoardRedirectURI(uint256 tokenId_, string memory redirectURI_) external { - registry.setBoardRedirectURI(tokenId_, redirectURI_, msg.sender); + function setBoardLocation(uint256 tokenId_, string calldata redirectUri_) external isFromBoardCreator { + registry.setBoardRedirectUri(tokenId_, redirectUri_); } ////////////////////////////// @@ -117,13 +126,18 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function setTaxRate(uint256 taxRate_) external isAdmin(msg.sender) { - registry.setTaxRate(taxRate_, msg.sender); + function getAuction( + uint256 tokenId_, + uint256 auctionId_ + ) external view returns (IBillboardRegistry.Auction memory auction) { + return registry.boardAuctions[tokenId_][auctionId_]; } /// @inheritdoc IBillboard - function getTaxRate() external view returns (uint256 taxRate) { - return registry.taxRate(); + function clearAuction(uint256 tokenId_) external { + registry.clearAuction(tokenId_); + + // TODO update board data } /// @inheritdoc IBillboard @@ -137,23 +151,76 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function getBidsByBoard( + function getBids( uint256 tokenId_, + uint256 auctionId_, uint256 limit_, uint256 offset_ ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids) { - return registry.getBidsByBoard(tokenId_, limit_, offset_); + IBillboardRegistry.Auction _auction = registry.boardAuctions[tokenId_][auctionId_]; + uint256 _total = _auction.bids.length; + + if (limit_ == 0) { + return (_total, limit_, offset_, new IBillboardRegistry.Bid[](0)); + } + + if (offset_ >= _total) { + return (_total, limit_, offset_, new IBillboardRegistry.Bid[](0)); + } + + uint256 left = _total - offset_; + uint256 size = left > limit_ ? limit_ : left; + + IBillboardRegistry.Bid[] memory _bids = new IBillboardRegistry.Bid[](size); + + for (uint256 i = 0; i < size; i++) { + _bids[i] = _auction.bids[offset_ + i]; + } + + return (_total, limit_, offset_, _bids); } + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// + /// @inheritdoc IBillboard - function clearAuction(uint256 tokenId_) external { - registry.clearAuction(tokenId_); + function getTaxRate() external view returns (uint256 taxRate) { + return registry.taxRate; + } - // TODO update board data + /// @inheritdoc IBillboard + function setTaxRate(uint256 taxRate_) external isFromAdmin { + registry.setTaxRate(taxRate_); } /// @inheritdoc IBillboard - function withdraw(uint256 tokenId_) external { - registry.withdraw(tokenId_, msg.sender); + function withdrawTax(uint256 tokenId_) external { + IBillboardRegistry.TaxTreasury taxTreasury = registry.taxTreasury[msg.sender]; + + uint256 amount = taxTreasury.accumulated - taxTreasury.withdrawn; + + if (amount <= 0) revert WithdrawFailed(); + + // transfer tax to the owner + registry.transferAmount(msg.sender, amount); + + // set taxTreasury.withdrawn to taxTreasury.accumulated + registry.setTaxTreasury(msg.sender, taxTreasury.accumulated, taxTreasury.accumulated); + } + + /// @inheritdoc IBillboard + function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { + IBillboardRegistry.Bid bid = boardAuctions[tokenId_][auctionId_].bids[msg.sender]; + uint256 amount = bid.price + bid.tax; + + if (bid.isWithdrawn) revert WithdrawFailed(); + if (amount == 0) revert WithdrawFailed(); + + // transfer bid price and tax back to the bidder + registry.transferAmount(msg.sender, amount); + + // set bid.isWithdrawn to true + registry.setBid(tokenId_, auctionId_, msg.sender, false, true); } } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 5022c6e..f545445 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -49,6 +49,10 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _; } + ////////////////////////////// + /// Board + ////////////////////////////// + /// @inheritdoc IBillboardRegistry function mint(address to_) external isFromOperator returns (uint256 tokenId) { _tokenIds.increment(); @@ -66,38 +70,63 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setBoard( - uint256 tokenId_, - string memory name_, - string memory description_, - string memory location_ - ) external isFromOperator { + function setBoardName(uint256 tokenId_, string calldata name_) external isFromOperator { boards[tokenId_].name = name_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardDescription(uint256 tokenId_, string calldata description_) external isFromOperator { boards[tokenId_].description = description_; + } + + /// @inheritdoc IBillboardRegistry + function setBoardLocation(uint256 tokenId_, string calldata location_) external isFromOperator { boards[tokenId_].location = location_; } /// @inheritdoc IBillboardRegistry - function setBoard(uint256 tokenId_, string memory contentUri_, string memory redirectUri_) external isFromOperator { - boards[tokenId_].contentUri_ = contentUri_; + function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external isFromOperator { + boards[tokenId_].redirectUri_ = redirectUri_; + } + + function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external isFromOperator { boards[tokenId_].redirectUri_ = redirectUri_; } + ////////////////////////////// + /// Auction + ////////////////////////////// + /// @inheritdoc IBillboardRegistry - function newAuction(uint256 tokenId_, uint256 startAt_, uint256 endAt_) external returns (uint256 auctionId) { + function newAuction( + uint256 tokenId_, + uint256 startAt_, + uint256 endAt_ + ) external isFromOperator returns (uint256 auctionId) { auctionId = lastBoardAuctionId[tokenId_]++; Auction({startAt: startAt_, endAt: endAt_, tokenId: tokenId_}); } /// @inheritdoc IBillboardRegistry - function setAuction(uint256 tokenId_, uint256 auctionId_, uint256 startAt_, uint256 endAt_) external { + function setAuction( + uint256 tokenId_, + uint256 auctionId_, + uint256 startAt_, + uint256 endAt_ + ) external isFromOperator { boardAuctions[tokenId_][auctionId_].startAt = startAt_; boardAuctions[tokenId_][auctionId_].endAt = endAt_; } /// @inheritdoc IBillboardRegistry - function newBid(uint256 tokenId_, uint256 auctionId_, address bidder_, uint256 price_, uint256 tax_) external { + function newBid( + uint256 tokenId_, + uint256 auctionId_, + address bidder_, + uint256 price_, + uint256 tax_ + ) external isFromOperator { Bid bid = Bid({ bidder: bidder_, price: price_, @@ -111,28 +140,36 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_, bool isWithdrawn_) external { + function setBid( + uint256 tokenId_, + uint256 auctionId_, + address bidder_, + bool isWon_, + bool isWithdrawn_ + ) external isFromOperator { boardAuctions[tokenId_][auctionId_].bids[bidder_].isWon = isWon_; boardAuctions[tokenId_][auctionId_].bids[bidder_].isWithdrawn = isWithdrawn_; } /// @inheritdoc IBillboardRegistry - function transferBidAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external { - uint256 amount = boardAuctions[tokenId_][auctionId_].bids[bidder_].price; - - (bool success, ) = to_.call{value: amount}(""); + function transferAmount(address to_, uint256 amount_) external isFromOperator { + (bool success, ) = to_.call{value: amount_}(""); if (!success) { revert TransferFailed(); } } + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// + /// @inheritdoc IBillboardRegistry - function setTaxRate(uint256 taxRate_) external { + function setTaxRate(uint256 taxRate_) external isFromOperator { taxRate = taxRate_; } /// @inheritdoc IBillboardRegistry - function setTaxTreasury(address owner_, uint256 accumulated_, uint256 withdrawn_) external { + function setTaxTreasury(address owner_, uint256 accumulated_, uint256 withdrawn_) external isFromOperator { taxTreasury[owner_].accumulated = accumulated_; taxTreasury[owner_].withdrawn = withdrawn_; } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index a4d8259..d950281 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -12,6 +12,10 @@ interface IBillboard { error Unauthorized(string type_); + error MintClosed(); + + error WithdrawFailed(); + ////////////////////////////// /// Upgradability ////////////////////////////// @@ -69,44 +73,45 @@ interface IBillboard { function getBoard(uint256 tokenId_) external view returns (IBillboardRegistry.Board memory board); /** - * @notice Set the name of a board. + * @notice Set the name of a board by board creator. * * @param tokenId_ Token ID of a board. * @param name_ Board name. */ - function setBoardName(uint256 tokenId_, string memory name_) external; + function setBoardName(uint256 tokenId_, string calldata name_) external; /** - * @notice Set the description of a board. + * @notice Set the name of a board by board creator. * * @param tokenId_ Token ID of a board. + * @param name_ Board name. * @param description_ Board description. */ - function setBoardDescription(uint256 tokenId_, string memory description_) external; + function setBoardDescription(uint256 tokenId_, string calldata description_) external; /** - * @notice Set the location of a board. + * @notice Set the location of a board by board creator. * * @param tokenId_ Token ID of a board. * @param location_ Digital address where a board located. */ - function setBoardLocation(uint256 tokenId_, string memory location_) external; + function setBoardLocation(uint256 tokenId_, string calldata location_) external; /** - * @notice Set the content URI of a board. + * @notice Set the content URI and redirect URI of a board by the tenant * * @param tokenId_ Token ID of a board. - * @param uri_ Content URI of a board. + * @param contentUri_ Content URI of a board. */ - function setBoardContentURI(uint256 tokenId_, string memory uri_) external; + function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external; /** - * @notice Set the redirect URI of a board when users clicking. + * @notice Set the redirect URI and redirect URI of a board by the tenant * * @param tokenId_ Token ID of a board. - * @param redirectURI_ Redirect URI of a board. + * @param redirectURI_ Redirect URI when users clicking. */ - function setBoardRedirectURI(uint256 tokenId_, string memory redirectURI_) external; + function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external; ////////////////////////////// /// Auction @@ -177,24 +182,6 @@ interface IBillboard { uint256 auctionId_ ) external view returns (IBillboardRegistry.Bid memory bid); - /** - * @notice Get bids of a board auction. - * - * @param tokenId_ Token ID of a board. - * @param limit_ Limit of returned bids. - * @param offset_ Offset of returned bids. - * - * @return total Total number of bids. - * @return limit Limit of returned bids. - * @return offset Offset of returned bids. - * @return bids Bids of a board. - */ - function getBidsByBoard( - uint256 tokenId_, - uint256 limit_, - uint256 offset_ - ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids); - /** * @notice Get bids of a board auction by auction ID. * @@ -208,7 +195,7 @@ interface IBillboard { * @return offset Offset of returned bids. * @return bids Bids of a board. */ - function getBidsByBoard( + function getBids( uint256 tokenId_, uint256 auctionId_, uint256 limit_, @@ -220,18 +207,18 @@ interface IBillboard { ////////////////////////////// /** - * @notice Set the global tax rate. + * @notice Get the global tax rate. * - * @param taxRate_ Tax rate. + * @return taxRate Tax rate. */ - function setTaxRate(uint256 taxRate_) external; + function getTaxRate() external view returns (uint256 taxRate); /** - * @notice Get the global tax rate. + * @notice Set the global tax rate. * - * @return taxRate Tax rate. + * @param taxRate_ Tax rate. */ - function getTaxRate() external view returns (uint256 taxRate); + function setTaxRate(uint256 taxRate_) external; /** * @notice Withdraw accumulated taxation of a board. diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index a4b7980..1856f5e 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -83,30 +83,45 @@ interface IBillboardRegistry is IERC721 { function mintBoard(address to_) external returns (uint256 tokenId); /** - * @notice Set the name, description and location of a board - * from board creator. + * @notice Set the name of a board by board creator. + * + * @param tokenId_ Token ID of a board. + * @param name_ Board name. + */ + function setBoardName(uint256 tokenId_, string calldata name_) external; + + /** + * @notice Set the name of a board by board creator. * * @param tokenId_ Token ID of a board. * @param name_ Board name. * @param description_ Board description. + */ + function setBoardDescription(uint256 tokenId_, string calldata description_) external; + + /** + * @notice Set the location of a board by board creator. + * + * @param tokenId_ Token ID of a board. * @param location_ Digital address where a board located. */ - function setBoard( - uint256 tokenId_, - string memory name_, - string memory description_, - string memory location_ - ) external; + function setBoardLocation(uint256 tokenId_, string calldata location_) external; /** - * @notice Set the content URI and redirect URI of a board - * from board tenant + * @notice Set the content URI and redirect URI of a board by the tenant * * @param tokenId_ Token ID of a board. * @param contentUri_ Content URI of a board. + */ + function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external; + + /** + * @notice Set the redirect URI and redirect URI of a board by the tenant + * + * @param tokenId_ Token ID of a board. * @param redirectURI_ Redirect URI when users clicking. */ - function setBoard(uint256 tokenId_, string memory contentUri_, string memory redirectUri_) external; + function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external; ////////////////////////////// /// Auction @@ -168,6 +183,10 @@ interface IBillboardRegistry is IERC721 { */ function transferBidAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external; + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// + /** * @notice Set the global tax rate. * From 98f620d6efe13f99a3a038eb03c11e2d1e2004f2 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 12 Nov 2023 19:45:51 +0800 Subject: [PATCH 17/55] feat(billboard): add lease to Auction --- src/Billboard/Billboard.sol | 29 ++++++++++++++-------------- src/Billboard/BillboardRegistry.sol | 10 +++++----- src/Billboard/IBillboardRegistry.sol | 10 ++++++---- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 9e5b4e9..9d03338 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -36,6 +36,13 @@ contract Billboard is IBillboard { _; } + modifier isFromWhitelist() { + if (whitelist[msg.sender] != true) { + revert Unauthorized("whitelist"); + } + _; + } + modifier isFromBoardCreator(uint256 tokenId_) { if (msg.sender != boards[tokenId_].creator) { revert Unauthorized("creator"); @@ -79,15 +86,11 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function mintBoard(address to_) external isValidAddress(to_) { + function mintBoard(address to_) external isValidAddress(to_) isFromWhitelist { if (!isOpened) { revert MintClosed(); } - if (!whitelist[msg.sender]) { - revert Unauthorized("whitelist"); - } - registry.mint(to_); } @@ -97,27 +100,27 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function setBoardName(uint256 tokenId_, string calldata name_) external isFromBoardCreator { + function setBoardName(uint256 tokenId_, string calldata name_) external isFromBoardCreator(tokenId_) { registry.setBoardName(tokenId_, name_); } /// @inheritdoc IBillboard - function setBoardDescription(uint256 tokenId_, string calldata description_) external isFromBoardCreator { + function setBoardDescription(uint256 tokenId_, string calldata description_) external isFromBoardCreator(tokenId_) { registry.setBoardDescription(tokenId_, description_); } /// @inheritdoc IBillboard - function setBoardLocation(uint256 tokenId_, string calldata location_) external isFromBoardCreator { + function setBoardLocation(uint256 tokenId_, string calldata location_) external isFromBoardCreator(tokenId_) { registry.setBoardLocation(tokenId_, location_); } /// @inheritdoc IBillboard - function setBoardLocation(uint256 tokenId_, string calldata contentUri_) external isFromBoardCreator { + function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external isFromBoardTenant(tokenId_) { registry.setBoardContentUri(tokenId_, contentUri_); } /// @inheritdoc IBillboard - function setBoardLocation(uint256 tokenId_, string calldata redirectUri_) external isFromBoardCreator { + function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external isFromBoardTenant(tokenId_) { registry.setBoardRedirectUri(tokenId_, redirectUri_); } @@ -136,14 +139,10 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { registry.clearAuction(tokenId_); - - // TODO update board data } /// @inheritdoc IBillboard - function placeBid(uint256 tokenId_, uint256 amount_) external { - registry.placeBid(tokenId_, amount_, msg.sender); - } + function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist {} /// @inheritdoc IBillboard function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid) { diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index f545445..6a24a70 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -109,14 +109,14 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setAuction( + function setAuctionLease( uint256 tokenId_, uint256 auctionId_, - uint256 startAt_, - uint256 endAt_ + uint256 leaseStartAt_, + uint256 leaseEndAt_ ) external isFromOperator { - boardAuctions[tokenId_][auctionId_].startAt = startAt_; - boardAuctions[tokenId_][auctionId_].endAt = endAt_; + boardAuctions[tokenId_][auctionId_].leaseStartAt = leaseStartAt_; + boardAuctions[tokenId_][auctionId_].leaseEndAt = leaseEndAt_; } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 1856f5e..ceec288 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -36,7 +36,7 @@ interface IBillboardRegistry is IERC721 { struct Board { address creator; - uint256 auctionId; // last cleared auction ID + uint256 auctionId; // last lease auction ID string name; string description; string location; @@ -48,6 +48,8 @@ interface IBillboardRegistry is IERC721 { uint256 tokenId; uint256 startAt; // timestamp uint256 endAt; // timestamp + uint256 leaseStartAt; // timestamp + uint256 leaseEndAt; // timestamp address highestBidder; address[] bidders; mapping(address => Bid) bids; @@ -141,10 +143,10 @@ interface IBillboardRegistry is IERC721 { * * @param tokenId_ Token ID of a board. * @param auctionId_ Token ID of a board. - * @param startAt_ Start time of an auction. - * @param endAt_ End time of an auction. + * @param leaseStartAt_ Start time of an board lease. + * @param leaseEndAt_ End time of an board lease. */ - function setAuction(uint256 tokenId_, uint256 auctionId_, uint256 startAt_, uint256 endAt_) external; + function setAuctionLease(uint256 tokenId_, uint256 auctionId_, uint256 leaseStartAt_, uint256 leaseEndAt_) external; /** * @notice Create new bid and add it to auction From ad3886ea480769c41b1e42befcf1efb3ab55f162 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 12 Nov 2023 21:58:43 +0800 Subject: [PATCH 18/55] feat(billboard): impl clearAuction --- src/Billboard/Billboard.sol | 46 ++++++++++++++++++++++++++-- src/Billboard/BillboardRegistry.sol | 19 +++++++++--- src/Billboard/IBillboard.sol | 24 +++++---------- src/Billboard/IBillboardRegistry.sol | 14 +++++++-- 4 files changed, 76 insertions(+), 27 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 9d03338..7378a38 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -51,7 +51,7 @@ contract Billboard is IBillboard { } modifier isFromBoardTenant(uint256 tokenId_) { - if (msg.sender != _ownerOf(tokenId_)) { + if (msg.sender != registry.ownerOf(tokenId_)) { revert Unauthorized("tenant"); } _; @@ -138,11 +138,51 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { - registry.clearAuction(tokenId_); + IBillboardRegistry.Board board = registry.boards[tokenId_]; + if (!board) revert BoardNotFound(); + + uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; + if (nextAuctionId == 0) revert AuctionNotFound(); + + IBillboardRegistry.Auction nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + + // reclaim ownership to board creator if no auction + if (!nextAuction) { + registry.safeTransferByOperator(msg.sender, board.creator, tokenId_); + return; + } + + if (block.timestamp < nextAuction.endAt) revert AuctionNotEnded(); + + IBillboardRegistry.Bid highestBid = nextAuction.bids[nextAuction.highestBidder]; + if (highestBid.price > 0) { + // transfer bid price to board owner (previous tenant or creator) + registry.transferAmount(registry.ownerOf(tokenId_), highestBid.price); + + // transfer bid tax to board creator's tax treasury + (uint256 taxAccumulated, uint256 taxWithdrawn) = registry.taxTreasury[recipient]; + registry.setTaxTreasury(board.creator, taxAccumulated + highestBid.tax, taxWithdrawn); + } + + // transfer ownership + registry.safeTransferByOperator(registry.ownerOf(tokenId_), nextAuction.highestBidder, tokenId_); + + // mark highest bid as won + highestBid.isWon = true; + + // set auction lease + uint256 leaseStartAt = block.timestamp; + uint256 leaseEndAt = block.timestamp + 14 days; + registry.setAuctionLease(tokenId_, nextAuctionId, leaseStartAt, leaseEndAt); + + // update Board.auctionId + registry.setBoardAuctionId(tokenId_, nextAuctionId); } /// @inheritdoc IBillboard - function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist {} + function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist { + // new auction + } /// @inheritdoc IBillboard function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid) { diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 6a24a70..801240f 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -22,8 +22,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // tokenId => auctionId => Auction mapping(uint256 => mapping(uint256 => Auction)) public boardAuctions; - // tokenId => lastAuctionId - mapping(uint256 => uint256) public lastBoardAuctionId; + // tokenId => nextAuctionId (start from 1) + mapping(uint256 => uint256) public nextBoardAuctionId; // board creator => TaxTreasury mapping(address => TaxTreasury) public taxTreasury; @@ -69,6 +69,16 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { return newTokenId; } + /// @inheritdoc ITheSpaceRegistry + function safeTransferByOperator(address from_, address to_, uint256 tokenId_) external isFromOperator { + _safeTransfer(from_, to_, tokenId_, ""); + } + + /// @inheritdoc IBillboardRegistry + function setBoardAuctionId(uint256 tokenId_, uint256 calldata auctionId_) external isFromOperator { + boards[tokenId_].auctionId = auctionId_; + } + /// @inheritdoc IBillboardRegistry function setBoardName(uint256 tokenId_, string calldata name_) external isFromOperator { boards[tokenId_].name = name_; @@ -102,8 +112,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, uint256 startAt_, uint256 endAt_ - ) external isFromOperator returns (uint256 auctionId) { - auctionId = lastBoardAuctionId[tokenId_]++; + ) external isFromOperator returns (uint256 newAuctionId) { + newAuctionId = nextBoardAuctionId[tokenId_]++; Auction({startAt: startAt_, endAt: endAt_, tokenId: tokenId_}); } @@ -216,6 +226,5 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { revert Unauthorized("not owner nor approved"); } _safeTransfer(from_, to_, tokenId_, data_); - boards[tokenId_].tenant = to_; } } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index d950281..44c86d8 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -14,6 +14,12 @@ interface IBillboard { error MintClosed(); + error BoardNotFound(); + + error AuctionNotFound(); + + error AuctionNotEnded(); + error WithdrawFailed(); ////////////////////////////// @@ -117,13 +123,6 @@ interface IBillboard { /// Auction ////////////////////////////// - /** - * @notice Get last cleared auction of a board. - * - * @param tokenId_ Token ID of a board. - */ - function getAuction(uint256 tokenId_) external view returns (IBillboardRegistry.Auction memory auction); - /** * @notice Get auction of a board by auction ID. * @@ -136,21 +135,14 @@ interface IBillboard { ) external view returns (IBillboardRegistry.Auction memory auction); /** - * @notice Clear a board auction. - * - * 1. update Board.auctionId - * 2. update Auction.startAt, endAt - * 3. update Bid.isWon - * 4. transfer bid price to last Auction.higghestBidder - * 5. transfer bid tax to TaxTreasury - * ... + * @notice Clear the next auction of a board. * * @param tokenId_ Token ID of a board. */ function clearAuction(uint256 tokenId_) external; /** - * @notice Place bid for a board. + * @notice Place bid for the next auction of a board. * * @param tokenId_ Token ID of a board. * @param amount_ Amount of a bid. diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index ceec288..a4e0f44 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -84,6 +84,14 @@ interface IBillboardRegistry is IERC721 { */ function mintBoard(address to_) external returns (uint256 tokenId); + /** + * @notice Set the auctionId of a board. + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of an auction. + */ + function setBoardAuctionId(uint256 tokenId_, uint256 calldata auctionId_) external; + /** * @notice Set the name of a board by board creator. * @@ -158,7 +166,7 @@ interface IBillboardRegistry is IERC721 { * - if any `auction.highestBidder = bidder` * * @param tokenId_ Token ID of a board. - * @param auctionId_ Auction ID of an auction. + * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. * @param price_ Price of a bid. * @param tax_ Tax of a bid. @@ -169,7 +177,7 @@ interface IBillboardRegistry is IERC721 { * @notice Set the data of a bid * * @param tokenId_ Token ID of a board. - * @param auctionId_ Auction ID of an auction. + * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. * @param isWon_ Whether a bid is won. */ @@ -179,7 +187,7 @@ interface IBillboardRegistry is IERC721 { * @notice Transfer amount of bid price to current board owner (last tenant) * * @param tokenId_ Token ID of a board. - * @param auctionId_ Auction ID of an auction. + * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of the highest bid. * @param to_ Address of a receiver. */ From 21b5b2e17e3de892acae90faf7506d1d4be547c9 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 12 Nov 2023 22:25:47 +0800 Subject: [PATCH 19/55] feat(billboard): impl placeBid --- src/Billboard/Billboard.sol | 37 ++++++++++++++++++++++++++--- src/Billboard/BillboardRegistry.sol | 2 +- src/Billboard/IBillboard.sol | 4 ++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 7378a38..fdacc84 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -181,7 +181,34 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist { - // new auction + IBillboardRegistry.Board board = registry.boards[tokenId_]; + if (!board) revert BoardNotFound(); + + uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; + IBillboardRegistry.Auction nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + + // create new auction and new bid if no next auction + if (!nextAuction) { + _newAuctionAndBid(tokenId_, amount_); + return; + } + + // clear auction first if next auction is ended, then create new auction and new bid + if (block.timestamp >= nextAuction.endAt) { + clearAuction(tokenId_); + _newAuctionAndBid(tokenId_, amount_); + return; + } else { + // push new bid to next auction + registry.newBid(tokenId_, nextAuctionId, msg.sender, amount_, calculateTax(amount_)); + } + } + + function _newAuctionAndBid(uint256 tokenId_, uint256 amount_) private { + uint256 startAt = block.timestamp; + uint256 endAt = block.timestamp + 14 days; + uint256 auctionId = registry.newAuction(tokenId_, startAt, endAt); + registry.newBid(tokenId_, auctionId, msg.sender, amount_, calculateTax(amount_)); } /// @inheritdoc IBillboard @@ -233,8 +260,12 @@ contract Billboard is IBillboard { registry.setTaxRate(taxRate_); } + function calculateTax(uint256 amount_) public view returns (uint256 tax) { + return (amount_ * registry.taxRate) / 100; + } + /// @inheritdoc IBillboard - function withdrawTax(uint256 tokenId_) external { + function withdrawTax() external { IBillboardRegistry.TaxTreasury taxTreasury = registry.taxTreasury[msg.sender]; uint256 amount = taxTreasury.accumulated - taxTreasury.withdrawn; @@ -254,7 +285,7 @@ contract Billboard is IBillboard { uint256 amount = bid.price + bid.tax; if (bid.isWithdrawn) revert WithdrawFailed(); - if (amount == 0) revert WithdrawFailed(); + if (amount <= 0) revert WithdrawFailed(); // transfer bid price and tax back to the bidder registry.transferAmount(msg.sender, amount); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 801240f..3ec0e49 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -115,7 +115,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ) external isFromOperator returns (uint256 newAuctionId) { newAuctionId = nextBoardAuctionId[tokenId_]++; - Auction({startAt: startAt_, endAt: endAt_, tokenId: tokenId_}); + Auction({tokenId: tokenId_, startAt: startAt_, endAt: endAt_}); } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 44c86d8..aa404b2 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -218,7 +218,7 @@ interface IBillboard { * @param tokenId_ Token ID of a board. * @param owner_ Address of a treasury owner. */ - function withdrawTax(uint256 tokenId_, address owner_) external; + function withdrawTax() external; /** * @notice Withdraw bid that were not won by auction id; @@ -227,5 +227,5 @@ interface IBillboard { * @param auctionId_ Auction ID of a board. * @param bidder_ Address of a auction bidder. */ - function withdrawBid(uint256 tokenId_, uint256 auctionId_, address bidder_) external; + function withdrawBid(uint256 tokenId_, uint256 auctionId_) external; } From a09893456d2e003d5d687647cca2d9338f017e73 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 14 Nov 2023 11:59:39 +0800 Subject: [PATCH 20/55] feat(billboard): move `bidders` and `bids` out of `Auction` struct --- src/Billboard/Billboard.sol | 38 ++++++++++++------------- src/Billboard/BillboardRegistry.sol | 42 +++++++++++++++++++++------- src/Billboard/IBillboard.sol | 10 ++----- src/Billboard/IBillboardRegistry.sol | 14 ++++------ 4 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index fdacc84..569300c 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -44,7 +44,7 @@ contract Billboard is IBillboard { } modifier isFromBoardCreator(uint256 tokenId_) { - if (msg.sender != boards[tokenId_].creator) { + if (msg.sender != registry.boards[tokenId_].creator) { revert Unauthorized("creator"); } _; @@ -62,22 +62,22 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function upgradeRegistry(address contract_) external isValidAddress(contract_) isAdmin(msg.sender) { + function upgradeRegistry(address contract_) external isValidAddress(contract_) isFromAdmin { registry = BillboardRegistry(contract_); } /// @inheritdoc IBillboardRegistry - function setIsOpened(bool value_, address sender_) external isAdmin(sender_) { + function setIsOpened(bool value_) external isFromAdmin { isOpened = value_; } /// @inheritdoc IBillboardRegistry - function addToWhitelist(address value_, address sender_) external isAdmin(sender_) { + function addToWhitelist(address value_) external isFromAdmin { whitelist[value_] = true; } /// @inheritdoc IBillboardRegistry - function removeFromWhitelist(address value_, address sender_) external isAdmin(sender_) { + function removeFromWhitelist(address value_) external isFromAdmin { whitelist[value_] = false; } @@ -115,13 +115,13 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external isFromBoardTenant(tokenId_) { - registry.setBoardContentUri(tokenId_, contentUri_); + function setBoardContentURI(uint256 tokenId_, string calldata contentURI_) external isFromBoardTenant(tokenId_) { + registry.setBoardContentURI(tokenId_, contentURI_); } /// @inheritdoc IBillboard - function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external isFromBoardTenant(tokenId_) { - registry.setBoardRedirectUri(tokenId_, redirectUri_); + function setBoardRedirectURI(uint256 tokenId_, string calldata redirectURI_) external isFromBoardTenant(tokenId_) { + registry.setBoardRedirectURI(tokenId_, redirectURI_); } ////////////////////////////// @@ -138,13 +138,13 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { - IBillboardRegistry.Board board = registry.boards[tokenId_]; + IBillboardRegistry.Board memory board = registry.boards[tokenId_]; if (!board) revert BoardNotFound(); uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; if (nextAuctionId == 0) revert AuctionNotFound(); - IBillboardRegistry.Auction nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + IBillboardRegistry.Auction memory nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; // reclaim ownership to board creator if no auction if (!nextAuction) { @@ -154,13 +154,13 @@ contract Billboard is IBillboard { if (block.timestamp < nextAuction.endAt) revert AuctionNotEnded(); - IBillboardRegistry.Bid highestBid = nextAuction.bids[nextAuction.highestBidder]; + IBillboardRegistry.Bid memory highestBid = nextAuction.bids[nextAuction.highestBidder]; if (highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) registry.transferAmount(registry.ownerOf(tokenId_), highestBid.price); // transfer bid tax to board creator's tax treasury - (uint256 taxAccumulated, uint256 taxWithdrawn) = registry.taxTreasury[recipient]; + (uint256 taxAccumulated, uint256 taxWithdrawn) = registry.taxTreasury[board.creator]; registry.setTaxTreasury(board.creator, taxAccumulated + highestBid.tax, taxWithdrawn); } @@ -181,11 +181,11 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist { - IBillboardRegistry.Board board = registry.boards[tokenId_]; + IBillboardRegistry.Board memory board = registry.boards[tokenId_]; if (!board) revert BoardNotFound(); uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; - IBillboardRegistry.Auction nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + IBillboardRegistry.Auction memory nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; // create new auction and new bid if no next auction if (!nextAuction) { @@ -195,7 +195,7 @@ contract Billboard is IBillboard { // clear auction first if next auction is ended, then create new auction and new bid if (block.timestamp >= nextAuction.endAt) { - clearAuction(tokenId_); + this.clearAuction(tokenId_); _newAuctionAndBid(tokenId_, amount_); return; } else { @@ -223,7 +223,7 @@ contract Billboard is IBillboard { uint256 limit_, uint256 offset_ ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids) { - IBillboardRegistry.Auction _auction = registry.boardAuctions[tokenId_][auctionId_]; + IBillboardRegistry.Auction memory _auction = registry.boardAuctions[tokenId_][auctionId_]; uint256 _total = _auction.bids.length; if (limit_ == 0) { @@ -266,7 +266,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function withdrawTax() external { - IBillboardRegistry.TaxTreasury taxTreasury = registry.taxTreasury[msg.sender]; + IBillboardRegistry.TaxTreasury memory taxTreasury = registry.taxTreasury[msg.sender]; uint256 amount = taxTreasury.accumulated - taxTreasury.withdrawn; @@ -281,7 +281,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { - IBillboardRegistry.Bid bid = boardAuctions[tokenId_][auctionId_].bids[msg.sender]; + IBillboardRegistry.Bid memory bid = registry.boardAuctions[tokenId_][auctionId_].bids[msg.sender]; uint256 amount = bid.price + bid.tax; if (bid.isWithdrawn) revert WithdrawFailed(); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 3ec0e49..c4ab1b5 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -25,6 +25,12 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // tokenId => nextAuctionId (start from 1) mapping(uint256 => uint256) public nextBoardAuctionId; + // auctionId => bidders + mapping(uint256 => address[]) public auctionBidders; + + // auctioId => bidder => Bid + mapping(uint256 => mapping(address => Bid)) auctionBids; + // board creator => TaxTreasury mapping(address => TaxTreasury) public taxTreasury; @@ -60,7 +66,15 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _safeMint(to_, newTokenId); - Board memory newBoard = Board({creator: to_}); + Board memory newBoard = Board({ + creator: to_, + auctionId: 0, + name: "", + description: "", + location: "", + contentURI: "", + redirectURI: "" + }); boards[newTokenId] = newBoard; // TODO @@ -69,13 +83,13 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { return newTokenId; } - /// @inheritdoc ITheSpaceRegistry + /// @inheritdoc IBillboardRegistry function safeTransferByOperator(address from_, address to_, uint256 tokenId_) external isFromOperator { _safeTransfer(from_, to_, tokenId_, ""); } /// @inheritdoc IBillboardRegistry - function setBoardAuctionId(uint256 tokenId_, uint256 calldata auctionId_) external isFromOperator { + function setBoardAuctionId(uint256 tokenId_, uint256 auctionId_) external isFromOperator { boards[tokenId_].auctionId = auctionId_; } @@ -95,12 +109,12 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external isFromOperator { - boards[tokenId_].redirectUri_ = redirectUri_; + function setBoardContentURI(uint256 tokenId_, string calldata contentURI_) external isFromOperator { + boards[tokenId_].contentURI = contentURI_; } - function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external isFromOperator { - boards[tokenId_].redirectUri_ = redirectUri_; + function setBoardRedirectURI(uint256 tokenId_, string calldata redirectURI_) external isFromOperator { + boards[tokenId_].redirectURI = redirectURI_; } ////////////////////////////// @@ -115,7 +129,14 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ) external isFromOperator returns (uint256 newAuctionId) { newAuctionId = nextBoardAuctionId[tokenId_]++; - Auction({tokenId: tokenId_, startAt: startAt_, endAt: endAt_}); + Auction({ + tokenId: tokenId_, + startAt: startAt_, + endAt: endAt_, + leaseStartAt: 0, + leaseEndAt: 0, + highestBidder: address(0) + }); } /// @inheritdoc IBillboardRegistry @@ -137,16 +158,17 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 price_, uint256 tax_ ) external isFromOperator { - Bid bid = Bid({ + Bid memory bid = Bid({ bidder: bidder_, price: price_, tax: tax_, auctionId: auctionId_, + placedAt: block.timestamp, isWithdrawn: false, isWon: false }); - boardAuctions[tokenId_][auctionId_].bids.push(bid); + auctionBidders[auctionId_].push(bid); } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index aa404b2..5faa329 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -90,7 +90,6 @@ interface IBillboard { * @notice Set the name of a board by board creator. * * @param tokenId_ Token ID of a board. - * @param name_ Board name. * @param description_ Board description. */ function setBoardDescription(uint256 tokenId_, string calldata description_) external; @@ -107,9 +106,9 @@ interface IBillboard { * @notice Set the content URI and redirect URI of a board by the tenant * * @param tokenId_ Token ID of a board. - * @param contentUri_ Content URI of a board. + * @param contentURI_ Content URI of a board. */ - function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external; + function setBoardContentURI(uint256 tokenId_, string calldata contentURI_) external; /** * @notice Set the redirect URI and redirect URI of a board by the tenant @@ -117,7 +116,7 @@ interface IBillboard { * @param tokenId_ Token ID of a board. * @param redirectURI_ Redirect URI when users clicking. */ - function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external; + function setBoardRedirectURI(uint256 tokenId_, string calldata redirectURI_) external; ////////////////////////////// /// Auction @@ -215,8 +214,6 @@ interface IBillboard { /** * @notice Withdraw accumulated taxation of a board. * - * @param tokenId_ Token ID of a board. - * @param owner_ Address of a treasury owner. */ function withdrawTax() external; @@ -225,7 +222,6 @@ interface IBillboard { * * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of a board. - * @param bidder_ Address of a auction bidder. */ function withdrawBid(uint256 tokenId_, uint256 auctionId_) external; } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index a4e0f44..1cb13ef 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -51,8 +51,6 @@ interface IBillboardRegistry is IERC721 { uint256 leaseStartAt; // timestamp uint256 leaseEndAt; // timestamp address highestBidder; - address[] bidders; - mapping(address => Bid) bids; } struct Bid { @@ -90,7 +88,7 @@ interface IBillboardRegistry is IERC721 { * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of an auction. */ - function setBoardAuctionId(uint256 tokenId_, uint256 calldata auctionId_) external; + function setBoardAuctionId(uint256 tokenId_, uint256 auctionId_) external; /** * @notice Set the name of a board by board creator. @@ -104,7 +102,6 @@ interface IBillboardRegistry is IERC721 { * @notice Set the name of a board by board creator. * * @param tokenId_ Token ID of a board. - * @param name_ Board name. * @param description_ Board description. */ function setBoardDescription(uint256 tokenId_, string calldata description_) external; @@ -121,9 +118,9 @@ interface IBillboardRegistry is IERC721 { * @notice Set the content URI and redirect URI of a board by the tenant * * @param tokenId_ Token ID of a board. - * @param contentUri_ Content URI of a board. + * @param contentURI_ Content URI of a board. */ - function setBoardContentUri(uint256 tokenId_, string calldata contentUri_) external; + function setBoardContentURI(uint256 tokenId_, string calldata contentURI_) external; /** * @notice Set the redirect URI and redirect URI of a board by the tenant @@ -131,7 +128,7 @@ interface IBillboardRegistry is IERC721 { * @param tokenId_ Token ID of a board. * @param redirectURI_ Redirect URI when users clicking. */ - function setBoardRedirectUri(uint256 tokenId_, string calldata redirectUri_) external; + function setBoardRedirectURI(uint256 tokenId_, string calldata redirectURI_) external; ////////////////////////////// /// Auction @@ -180,8 +177,9 @@ interface IBillboardRegistry is IERC721 { * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. * @param isWon_ Whether a bid is won. + * @param isWithdrawn_ Whether a bid is won. */ - function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon, bool isWithdrawn) external; + function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_, bool isWithdrawn_) external; /** * @notice Transfer amount of bid price to current board owner (last tenant) From 842ebe8b542bd5872c5208e427f5213e422e3647 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:28:04 +0800 Subject: [PATCH 21/55] fix(billboard): fix formatter --- .vscode/settings.json | 2 +- src/Billboard/BillboardRegistry.sol | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 122a9b7..05a475b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,6 @@ "editor.formatOnSave": true, "solidity.formatter": "prettier", "[solidity]": { - "editor.defaultFormatter": "JuanBlanco.solidity" + "editor.defaultFormatter": "NomicFoundation.hardhat-solidity" } } \ No newline at end of file diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index c4ab1b5..081ef36 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -168,7 +168,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { isWon: false }); - auctionBidders[auctionId_].push(bid); + auctionBids[auctionId_][bidder_] = bid; + auctionBidders[auctionId_].push(bidder_); } /// @inheritdoc IBillboardRegistry @@ -179,8 +180,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { bool isWon_, bool isWithdrawn_ ) external isFromOperator { - boardAuctions[tokenId_][auctionId_].bids[bidder_].isWon = isWon_; - boardAuctions[tokenId_][auctionId_].bids[bidder_].isWithdrawn = isWithdrawn_; + auctionBids[auctionId_][bidder_].isWon = isWon_; + auctionBids[auctionId_][bidder_].isWithdrawn = isWithdrawn_; } /// @inheritdoc IBillboardRegistry From 15e69a77ee2b56dd3b7bc333bdcbb069263346fb Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 14 Nov 2023 20:44:31 +0800 Subject: [PATCH 22/55] fix(billboard): fix getters & setters --- src/Billboard/Billboard.sol | 96 ++++++++++++++-------------- src/Billboard/BillboardRegistry.sol | 46 ++++++++++--- src/Billboard/IBillboardRegistry.sol | 59 ++++++++++++++++- 3 files changed, 143 insertions(+), 58 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 569300c..8d6a6ff 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -44,7 +44,8 @@ contract Billboard is IBillboard { } modifier isFromBoardCreator(uint256 tokenId_) { - if (msg.sender != registry.boards[tokenId_].creator) { + (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + if (_boardCreator != msg.sender) { revert Unauthorized("creator"); } _; @@ -96,7 +97,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function getBoard(uint256 tokenId_) external view returns (IBillboardRegistry.Board memory board) { - return registry.boards[tokenId_]; + return registry.getBoard(tokenId_); } /// @inheritdoc IBillboard @@ -133,82 +134,82 @@ contract Billboard is IBillboard { uint256 tokenId_, uint256 auctionId_ ) external view returns (IBillboardRegistry.Auction memory auction) { - return registry.boardAuctions[tokenId_][auctionId_]; + return registry.getAuction(tokenId_, auctionId_); } /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { - IBillboardRegistry.Board memory board = registry.boards[tokenId_]; - if (!board) revert BoardNotFound(); + (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + if (_boardCreator == address(0)) revert BoardNotFound(); - uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; - if (nextAuctionId == 0) revert AuctionNotFound(); + uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); + if (_nextAuctionId == 0) revert AuctionNotFound(); - IBillboardRegistry.Auction memory nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); // reclaim ownership to board creator if no auction - if (!nextAuction) { - registry.safeTransferByOperator(msg.sender, board.creator, tokenId_); + if (_nextAuction.tokenId == 0) { + registry.safeTransferByOperator(msg.sender, _boardCreator, tokenId_); return; } - if (block.timestamp < nextAuction.endAt) revert AuctionNotEnded(); + if (block.timestamp < _nextAuction.endAt) revert AuctionNotEnded(); - IBillboardRegistry.Bid memory highestBid = nextAuction.bids[nextAuction.highestBidder]; - if (highestBid.price > 0) { + IBillboardRegistry.Bid memory _highestBid = registry.getBid(_nextAuctionId, _nextAuction.highestBidder); + if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) - registry.transferAmount(registry.ownerOf(tokenId_), highestBid.price); + registry.transferAmount(registry.ownerOf(tokenId_), _highestBid.price); // transfer bid tax to board creator's tax treasury - (uint256 taxAccumulated, uint256 taxWithdrawn) = registry.taxTreasury[board.creator]; - registry.setTaxTreasury(board.creator, taxAccumulated + highestBid.tax, taxWithdrawn); + (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(_boardCreator); + registry.setTaxTreasury(_boardCreator, _taxAccumulated + _highestBid.tax, _taxWithdrawn); } // transfer ownership - registry.safeTransferByOperator(registry.ownerOf(tokenId_), nextAuction.highestBidder, tokenId_); + registry.safeTransferByOperator(registry.ownerOf(tokenId_), _nextAuction.highestBidder, tokenId_); // mark highest bid as won - highestBid.isWon = true; + registry.setBidWon(tokenId_, _nextAuctionId, _nextAuction.highestBidder, true); // set auction lease uint256 leaseStartAt = block.timestamp; uint256 leaseEndAt = block.timestamp + 14 days; - registry.setAuctionLease(tokenId_, nextAuctionId, leaseStartAt, leaseEndAt); + registry.setAuctionLease(tokenId_, _nextAuctionId, leaseStartAt, leaseEndAt); // update Board.auctionId - registry.setBoardAuctionId(tokenId_, nextAuctionId); + registry.setBoardAuctionId(tokenId_, _nextAuctionId); } /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist { - IBillboardRegistry.Board memory board = registry.boards[tokenId_]; - if (!board) revert BoardNotFound(); + (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + if (_boardCreator == address(0)) revert BoardNotFound(); - uint256 nextAuctionId = registry.nextBoardAuctionId[tokenId_]; - IBillboardRegistry.Auction memory nextAuction = registry.boardAuctions[tokenId_][nextAuctionId]; + uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); + IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); // create new auction and new bid if no next auction - if (!nextAuction) { + if (_nextAuction.tokenId == 0) { _newAuctionAndBid(tokenId_, amount_); return; } // clear auction first if next auction is ended, then create new auction and new bid - if (block.timestamp >= nextAuction.endAt) { + if (block.timestamp >= _nextAuction.endAt) { this.clearAuction(tokenId_); _newAuctionAndBid(tokenId_, amount_); return; } else { // push new bid to next auction - registry.newBid(tokenId_, nextAuctionId, msg.sender, amount_, calculateTax(amount_)); + registry.newBid(tokenId_, _nextAuctionId, msg.sender, amount_, calculateTax(amount_)); } } function _newAuctionAndBid(uint256 tokenId_, uint256 amount_) private { - uint256 startAt = block.timestamp; - uint256 endAt = block.timestamp + 14 days; - uint256 auctionId = registry.newAuction(tokenId_, startAt, endAt); - registry.newBid(tokenId_, auctionId, msg.sender, amount_, calculateTax(amount_)); + uint256 _startAt = block.timestamp; + uint256 _endAt = block.timestamp + 14 days; + uint256 _auctionId = registry.newAuction(tokenId_, _startAt, _endAt); + registry.newBid(tokenId_, _auctionId, msg.sender, amount_, calculateTax(amount_)); } /// @inheritdoc IBillboard @@ -223,8 +224,8 @@ contract Billboard is IBillboard { uint256 limit_, uint256 offset_ ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids) { - IBillboardRegistry.Auction memory _auction = registry.boardAuctions[tokenId_][auctionId_]; - uint256 _total = _auction.bids.length; + IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId_, auctionId_); + uint256 _total = registry.getBidCount(auctionId_); if (limit_ == 0) { return (_total, limit_, offset_, new IBillboardRegistry.Bid[](0)); @@ -234,13 +235,14 @@ contract Billboard is IBillboard { return (_total, limit_, offset_, new IBillboardRegistry.Bid[](0)); } - uint256 left = _total - offset_; - uint256 size = left > limit_ ? limit_ : left; + uint256 _left = _total - offset_; + uint256 _size = _left > limit_ ? limit_ : _left; - IBillboardRegistry.Bid[] memory _bids = new IBillboardRegistry.Bid[](size); + IBillboardRegistry.Bid[] memory _bids = new IBillboardRegistry.Bid[](_size); - for (uint256 i = 0; i < size; i++) { - _bids[i] = _auction.bids[offset_ + i]; + for (uint256 i = 0; i < _size; i++) { + address _bidder = registry.auctionBidders(auctionId_, offset_ + i); + _bids[i] = registry.getBid(auctionId_, _bidder); } return (_total, limit_, offset_, _bids); @@ -252,7 +254,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function getTaxRate() external view returns (uint256 taxRate) { - return registry.taxRate; + return registry.taxRate(); } /// @inheritdoc IBillboard @@ -261,14 +263,14 @@ contract Billboard is IBillboard { } function calculateTax(uint256 amount_) public view returns (uint256 tax) { - return (amount_ * registry.taxRate) / 100; + return (amount_ * registry.taxRate()) / 100; } /// @inheritdoc IBillboard function withdrawTax() external { - IBillboardRegistry.TaxTreasury memory taxTreasury = registry.taxTreasury[msg.sender]; + (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(msg.sender); - uint256 amount = taxTreasury.accumulated - taxTreasury.withdrawn; + uint256 amount = _taxAccumulated - _taxWithdrawn; if (amount <= 0) revert WithdrawFailed(); @@ -276,21 +278,21 @@ contract Billboard is IBillboard { registry.transferAmount(msg.sender, amount); // set taxTreasury.withdrawn to taxTreasury.accumulated - registry.setTaxTreasury(msg.sender, taxTreasury.accumulated, taxTreasury.accumulated); + registry.setTaxTreasury(msg.sender, _taxAccumulated, _taxAccumulated); } /// @inheritdoc IBillboard function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { - IBillboardRegistry.Bid memory bid = registry.boardAuctions[tokenId_][auctionId_].bids[msg.sender]; - uint256 amount = bid.price + bid.tax; + IBillboardRegistry.Bid memory _bid = registry.getBid(auctionId_, msg.sender); + uint256 amount = _bid.price + _bid.tax; - if (bid.isWithdrawn) revert WithdrawFailed(); + if (_bid.isWithdrawn) revert WithdrawFailed(); if (amount <= 0) revert WithdrawFailed(); // transfer bid price and tax back to the bidder registry.transferAmount(msg.sender, amount); // set bid.isWithdrawn to true - registry.setBid(tokenId_, auctionId_, msg.sender, false, true); + registry.setBidWithdrawn(tokenId_, auctionId_, msg.sender, true); } } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 081ef36..00c483c 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -55,6 +55,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _; } + /// @inheritdoc IBillboardRegistry + function setOperator(address operator_) external isFromOperator { + operator = operator_; + } + ////////////////////////////// /// Board ////////////////////////////// @@ -66,7 +71,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _safeMint(to_, newTokenId); - Board memory newBoard = Board({ + Board memory _newBoard = Board({ creator: to_, auctionId: 0, name: "", @@ -75,7 +80,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { contentURI: "", redirectURI: "" }); - boards[newTokenId] = newBoard; + boards[newTokenId] = _newBoard; // TODO // emit Mint(newBoardId, to_); @@ -88,6 +93,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _safeTransfer(from_, to_, tokenId_, ""); } + /// @inheritdoc IBillboardRegistry + function getBoard(uint256 tokenId_) external view returns (Board memory board) { + board = boards[tokenId_]; + } + /// @inheritdoc IBillboardRegistry function setBoardAuctionId(uint256 tokenId_, uint256 auctionId_) external isFromOperator { boards[tokenId_].auctionId = auctionId_; @@ -121,6 +131,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// Auction ////////////////////////////// + /// @inheritdoc IBillboardRegistry + function getAuction(uint256 tokenId_, uint256 auctionId_) external view returns (Auction memory auction) { + auction = boardAuctions[tokenId_][auctionId_]; + } + /// @inheritdoc IBillboardRegistry function newAuction( uint256 tokenId_, @@ -150,6 +165,16 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { boardAuctions[tokenId_][auctionId_].leaseEndAt = leaseEndAt_; } + /// @inheritdoc IBillboardRegistry + function getBidCount(uint256 auctionId_) external returns (uint256 count) { + count = auctionBidders[auctionId_].length; + } + + /// @inheritdoc IBillboardRegistry + function getBid(uint256 auctionId_, address bidder_) external view returns (Bid memory bid) { + bid = auctionBids[auctionId_][bidder_]; + } + /// @inheritdoc IBillboardRegistry function newBid( uint256 tokenId_, @@ -158,7 +183,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 price_, uint256 tax_ ) external isFromOperator { - Bid memory bid = Bid({ + Bid memory _bid = Bid({ bidder: bidder_, price: price_, tax: tax_, @@ -168,26 +193,29 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { isWon: false }); - auctionBids[auctionId_][bidder_] = bid; + auctionBids[auctionId_][bidder_] = _bid; auctionBidders[auctionId_].push(bidder_); } /// @inheritdoc IBillboardRegistry - function setBid( + function setBidWon(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_) external isFromOperator { + auctionBids[auctionId_][bidder_].isWon = isWon_; + } + + /// @inheritdoc IBillboardRegistry + function setBidWithdrawn( uint256 tokenId_, uint256 auctionId_, address bidder_, - bool isWon_, bool isWithdrawn_ ) external isFromOperator { - auctionBids[auctionId_][bidder_].isWon = isWon_; auctionBids[auctionId_][bidder_].isWithdrawn = isWithdrawn_; } /// @inheritdoc IBillboardRegistry function transferAmount(address to_, uint256 amount_) external isFromOperator { - (bool success, ) = to_.call{value: amount_}(""); - if (!success) { + (bool _success, ) = to_.call{value: amount_}(""); + if (!_success) { revert TransferFailed(); } } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 1cb13ef..0b3cc7b 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -69,6 +69,13 @@ interface IBillboardRegistry is IERC721 { uint256 withdrawn; } + /** + * @notice Set the new operator. + * + * @param operator_ Address of the new operator. + */ + function setOperator(address operator_) external; + ////////////////////////////// /// Board ////////////////////////////// @@ -82,6 +89,22 @@ interface IBillboardRegistry is IERC721 { */ function mintBoard(address to_) external returns (uint256 tokenId); + /** + * @notice Transfer a board (NFT) by the operator. + * + * @param from_ Address of the board sender. + * @param to_ Address of the board receiver. + * @param tokenId_ Token ID of the board. + */ + function safeTransferByOperator(address from_, address to_, uint256 tokenId_) external; + + /** + * @notice Get a board + * + * @param tokenId_ Token ID of a board. + */ + function getBoard(uint256 tokenId_) external returns (Board memory board); + /** * @notice Set the auctionId of a board. * @@ -134,6 +157,14 @@ interface IBillboardRegistry is IERC721 { /// Auction ////////////////////////////// + /** + * @notice Get an auction + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Token ID of a board. + */ + function getAuction(uint256 tokenId_, uint256 auctionId_) external returns (Auction memory auction); + /** * @notice Create new auction * @@ -153,6 +184,21 @@ interface IBillboardRegistry is IERC721 { */ function setAuctionLease(uint256 tokenId_, uint256 auctionId_, uint256 leaseStartAt_, uint256 leaseEndAt_) external; + /** + * @notice Get bid count of an auction + * + * @param auctionId_ Auction ID of an auction. + */ + function getBidCount(uint256 auctionId_) external returns (uint256 count); + + /** + * @notice Get a bid of an auction + * + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of an auction. + */ + function getBid(uint256 auctionId_, address bidder_) external returns (Bid memory bid); + /** * @notice Create new bid and add it to auction * @@ -171,15 +217,24 @@ interface IBillboardRegistry is IERC721 { function newBid(uint256 tokenId_, uint256 auctionId_, address bidder_, uint256 price_, uint256 tax_) external; /** - * @notice Set the data of a bid + * @notice Set isWon of a bid * * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. * @param isWon_ Whether a bid is won. + */ + function setBidWon(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_) external; + + /** + * @notice Set isWithdrawn of a bid + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of an auction. * @param isWithdrawn_ Whether a bid is won. */ - function setBid(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_, bool isWithdrawn_) external; + function setBidWithdrawn(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWithdrawn_) external; /** * @notice Transfer amount of bid price to current board owner (last tenant) From 43f6f5b6133bf506a7920f75e501af31fc195df2 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 14 Nov 2023 22:52:14 +0800 Subject: [PATCH 23/55] fix(billboard): fix interface --- src/Billboard/Billboard.sol | 2 +- src/Billboard/BillboardRegistry.sol | 8 ++++---- src/Billboard/IBillboard.sol | 7 +++++++ src/Billboard/IBillboardRegistry.sol | 14 +++++--------- src/test/Billboard/BillboardTestBase.t.sol | 14 +------------- 5 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 8d6a6ff..d27ac41 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -92,7 +92,7 @@ contract Billboard is IBillboard { revert MintClosed(); } - registry.mint(to_); + registry.mintBoard(to_); } /// @inheritdoc IBillboard diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 00c483c..cfb296b 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -36,9 +36,9 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { constructor( address operator_, + uint256 taxRate_, string memory name_, - string memory symbol_, - uint256 taxRate_ + string memory symbol_ ) ERC721(name_, symbol_) { operator = operator_; taxRate = taxRate_; @@ -65,7 +65,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ////////////////////////////// /// @inheritdoc IBillboardRegistry - function mint(address to_) external isFromOperator returns (uint256 tokenId) { + function mintBoard(address to_) external isFromOperator returns (uint256 tokenId) { _tokenIds.increment(); uint256 newTokenId = _tokenIds.current(); @@ -166,7 +166,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function getBidCount(uint256 auctionId_) external returns (uint256 count) { + function getBidCount(uint256 auctionId_) external view returns (uint256 count) { count = auctionBidders[auctionId_].length; } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 5faa329..760b9d8 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -211,6 +211,13 @@ interface IBillboard { */ function setTaxRate(uint256 taxRate_) external; + /** + * @notice Calculate tax of a bid. + * + * @param amount_ Amount of a bid. + */ + function calculateTax(uint256 amount_) external returns (uint256 tax); + /** * @notice Withdraw accumulated taxation of a board. * diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 0b3cc7b..c055d5d 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -8,12 +8,8 @@ interface IBillboardRegistry is IERC721 { /// Error ////////////////////////////// - error InvalidAddress(); - error Unauthorized(string type_); - error ZeroAmount(); - error TransferFailed(); ////////////////////////////// @@ -103,7 +99,7 @@ interface IBillboardRegistry is IERC721 { * * @param tokenId_ Token ID of a board. */ - function getBoard(uint256 tokenId_) external returns (Board memory board); + function getBoard(uint256 tokenId_) external view returns (Board memory board); /** * @notice Set the auctionId of a board. @@ -163,7 +159,7 @@ interface IBillboardRegistry is IERC721 { * @param tokenId_ Token ID of a board. * @param auctionId_ Token ID of a board. */ - function getAuction(uint256 tokenId_, uint256 auctionId_) external returns (Auction memory auction); + function getAuction(uint256 tokenId_, uint256 auctionId_) external view returns (Auction memory auction); /** * @notice Create new auction @@ -189,7 +185,7 @@ interface IBillboardRegistry is IERC721 { * * @param auctionId_ Auction ID of an auction. */ - function getBidCount(uint256 auctionId_) external returns (uint256 count); + function getBidCount(uint256 auctionId_) external view returns (uint256 count); /** * @notice Get a bid of an auction @@ -197,7 +193,7 @@ interface IBillboardRegistry is IERC721 { * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. */ - function getBid(uint256 auctionId_, address bidder_) external returns (Bid memory bid); + function getBid(uint256 auctionId_, address bidder_) external view returns (Bid memory bid); /** * @notice Create new bid and add it to auction @@ -244,7 +240,7 @@ interface IBillboardRegistry is IERC721 { * @param bidder_ Bidder of the highest bid. * @param to_ Address of a receiver. */ - function transferBidAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external; + function transferAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external; ////////////////////////////// /// Tax & Withdraw diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 8c90848..e41dc20 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -6,14 +6,12 @@ import "forge-std/Test.sol"; import "forge-std/Vm.sol"; import {Billboard} from "../../Billboard/Billboard.sol"; -import {BillboardAuction} from "../../Billboard/BillboardAuction.sol"; import {BillboardRegistry} from "../../Billboard/BillboardRegistry.sol"; import {IBillboard} from "../../Billboard/IBillboard.sol"; import {IBillboardRegistry} from "../../Billboard/IBillboardRegistry.sol"; contract BillboardTestBase is Test { Billboard internal operator; - BillboardAuction internal auction; BillboardRegistry internal registry; uint256 constant TAX_RATE = 1; @@ -36,20 +34,10 @@ contract BillboardTestBase is Test { assertEq(ADMIN, operator.admin()); address operatorAddress = address(operator); - // deploy auction - auction = new BillboardAuction(ADMIN, operatorAddress, TAX_RATE); - assertEq(ADMIN, auction.admin()); - assertEq(operatorAddress, auction.operator()); - // deploy registry - registry = new BillboardRegistry(ADMIN, operatorAddress, "BLBD", "BLBD"); - assertEq(ADMIN, registry.admin()); + registry = new BillboardRegistry(operatorAddress, TAX_RATE, "BLBD", "BLBD"); assertEq(operatorAddress, registry.operator()); - // upgrade auction - operator.upgradeAuction(address(auction)); - assertEq(address(auction), address(operator.auction())); - // upgrade registry operator.upgradeRegistry(address(registry)); assertEq(address(registry), address(operator.registry())); From e7c3304fc96df76be2632cb1c099ce6c91359e5c Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 15 Nov 2023 13:37:14 +0800 Subject: [PATCH 24/55] fix(billboard): fix interfaces --- src/Billboard/Billboard.sol | 29 +++++++++++++-------- src/Billboard/BillboardRegistry.sol | 39 +++++++++------------------- src/Billboard/IBillboard.sol | 16 +++--------- src/Billboard/IBillboardRegistry.sol | 14 +++++----- 4 files changed, 40 insertions(+), 58 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index d27ac41..bd39cac 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -67,17 +67,17 @@ contract Billboard is IBillboard { registry = BillboardRegistry(contract_); } - /// @inheritdoc IBillboardRegistry + /// @inheritdoc IBillboard function setIsOpened(bool value_) external isFromAdmin { isOpened = value_; } - /// @inheritdoc IBillboardRegistry + /// @inheritdoc IBillboard function addToWhitelist(address value_) external isFromAdmin { whitelist[value_] = true; } - /// @inheritdoc IBillboardRegistry + /// @inheritdoc IBillboard function removeFromWhitelist(address value_) external isFromAdmin { whitelist[value_] = false; } @@ -155,7 +155,11 @@ contract Billboard is IBillboard { if (block.timestamp < _nextAuction.endAt) revert AuctionNotEnded(); - IBillboardRegistry.Bid memory _highestBid = registry.getBid(_nextAuctionId, _nextAuction.highestBidder); + IBillboardRegistry.Bid memory _highestBid = registry.getBid( + tokenId_, + _nextAuctionId, + _nextAuction.highestBidder + ); if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) registry.transferAmount(registry.ownerOf(tokenId_), _highestBid.price); @@ -213,8 +217,12 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid) { - return registry.getBid(tokenId_, bidder_); + function getBid( + uint256 tokenId_, + uint256 auctionId_, + address bidder_ + ) external view returns (IBillboardRegistry.Bid memory bid) { + return registry.getBid(tokenId_, auctionId_, bidder_); } /// @inheritdoc IBillboard @@ -224,8 +232,7 @@ contract Billboard is IBillboard { uint256 limit_, uint256 offset_ ) external view returns (uint256 total, uint256 limit, uint256 offset, IBillboardRegistry.Bid[] memory bids) { - IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId_, auctionId_); - uint256 _total = registry.getBidCount(auctionId_); + uint256 _total = registry.getBidCount(tokenId_, auctionId_); if (limit_ == 0) { return (_total, limit_, offset_, new IBillboardRegistry.Bid[](0)); @@ -241,8 +248,8 @@ contract Billboard is IBillboard { IBillboardRegistry.Bid[] memory _bids = new IBillboardRegistry.Bid[](_size); for (uint256 i = 0; i < _size; i++) { - address _bidder = registry.auctionBidders(auctionId_, offset_ + i); - _bids[i] = registry.getBid(auctionId_, _bidder); + address _bidder = registry.auctionBidders(tokenId_, auctionId_, offset_ + i); + _bids[i] = registry.getBid(tokenId_, auctionId_, _bidder); } return (_total, limit_, offset_, _bids); @@ -283,7 +290,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { - IBillboardRegistry.Bid memory _bid = registry.getBid(auctionId_, msg.sender); + IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, auctionId_, msg.sender); uint256 amount = _bid.price + _bid.tax; if (_bid.isWithdrawn) revert WithdrawFailed(); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index cfb296b..f8fd98c 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -25,11 +25,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // tokenId => nextAuctionId (start from 1) mapping(uint256 => uint256) public nextBoardAuctionId; - // auctionId => bidders - mapping(uint256 => address[]) public auctionBidders; + // tokenId => auctionId => bidders + mapping(uint256 => mapping(uint256 => address[])) public auctionBidders; - // auctioId => bidder => Bid - mapping(uint256 => mapping(address => Bid)) auctionBids; + // tokenId => auctionId => bidder => Bid + mapping(uint256 => mapping(uint256 => mapping(address => Bid))) public auctionBids; // board creator => TaxTreasury mapping(address => TaxTreasury) public taxTreasury; @@ -166,13 +166,13 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { } /// @inheritdoc IBillboardRegistry - function getBidCount(uint256 auctionId_) external view returns (uint256 count) { - count = auctionBidders[auctionId_].length; + function getBidCount(uint256 tokenId_, uint256 auctionId_) external view returns (uint256 count) { + count = auctionBidders[tokenId_][auctionId_].length; } /// @inheritdoc IBillboardRegistry - function getBid(uint256 auctionId_, address bidder_) external view returns (Bid memory bid) { - bid = auctionBids[auctionId_][bidder_]; + function getBid(uint256 tokenId_, uint256 auctionId_, address bidder_) external view returns (Bid memory bid) { + bid = auctionBids[tokenId_][auctionId_][bidder_]; } /// @inheritdoc IBillboardRegistry @@ -193,13 +193,13 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { isWon: false }); - auctionBids[auctionId_][bidder_] = _bid; - auctionBidders[auctionId_].push(bidder_); + auctionBids[tokenId_][auctionId_][bidder_] = _bid; + auctionBidders[tokenId_][auctionId_].push(bidder_); } /// @inheritdoc IBillboardRegistry function setBidWon(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_) external isFromOperator { - auctionBids[auctionId_][bidder_].isWon = isWon_; + auctionBids[tokenId_][auctionId_][bidder_].isWon = isWon_; } /// @inheritdoc IBillboardRegistry @@ -209,7 +209,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { address bidder_, bool isWithdrawn_ ) external isFromOperator { - auctionBids[auctionId_][bidder_].isWithdrawn = isWithdrawn_; + auctionBids[tokenId_][auctionId_][bidder_].isWithdrawn = isWithdrawn_; } /// @inheritdoc IBillboardRegistry @@ -263,19 +263,4 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { function transferFrom(address from_, address to_, uint256 tokenId_) public override(ERC721, IERC721) { safeTransferFrom(from_, to_, tokenId_, ""); } - - /** - * @notice See {IERC721-safeTransferFrom}. - */ - function safeTransferFrom( - address from_, - address to_, - uint256 tokenId_, - bytes memory data_ - ) public override(ERC721, IERC721) { - if (!_isApprovedOrOwner(msg.sender, tokenId_)) { - revert Unauthorized("not owner nor approved"); - } - _safeTransfer(from_, to_, tokenId_, data_); - } } diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 760b9d8..4ec3bc4 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -148,29 +148,19 @@ interface IBillboard { */ function placeBid(uint256 tokenId_, uint256 amount_) external; - /** - * @notice Get bid of a board auction. - * - * @param tokenId_ Token ID of a board. - * @param bidder_ Address of a bidder. - * - * @return bid Bid of a board. - */ - function getBid(uint256 tokenId_, address bidder_) external view returns (IBillboardRegistry.Bid memory bid); - /** * @notice Get bid of a board auction by auction ID. * * @param tokenId_ Token ID of a board. - * @param bidder_ Address of a bidder. * @param auctionId_ Auction ID of a board. + * @param bidder_ Address of a bidder. * * @return bid Bid of a board. */ function getBid( uint256 tokenId_, - address bidder_, - uint256 auctionId_ + uint256 auctionId_, + address bidder_ ) external view returns (IBillboardRegistry.Bid memory bid); /** diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index c055d5d..4fc7c69 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -183,17 +183,19 @@ interface IBillboardRegistry is IERC721 { /** * @notice Get bid count of an auction * + * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of an auction. */ - function getBidCount(uint256 auctionId_) external view returns (uint256 count); + function getBidCount(uint256 tokenId_, uint256 auctionId_) external view returns (uint256 count); /** * @notice Get a bid of an auction * + * @param tokenId_ Token ID of a board. * @param auctionId_ Auction ID of an auction. * @param bidder_ Bidder of an auction. */ - function getBid(uint256 auctionId_, address bidder_) external view returns (Bid memory bid); + function getBid(uint256 tokenId_, uint256 auctionId_, address bidder_) external view returns (Bid memory bid); /** * @notice Create new bid and add it to auction @@ -233,14 +235,12 @@ interface IBillboardRegistry is IERC721 { function setBidWithdrawn(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWithdrawn_) external; /** - * @notice Transfer amount of bid price to current board owner (last tenant) + * @notice Transfer amount to a receiver. * - * @param tokenId_ Token ID of a board. - * @param auctionId_ Auction ID of an auction. - * @param bidder_ Bidder of the highest bid. * @param to_ Address of a receiver. + * @param amount_ Amount. */ - function transferAmount(uint256 tokenId_, uint256 auctionId_, address bidder_, address to_) external; + function transferAmount(address to_, uint256 amount_) external; ////////////////////////////// /// Tax & Withdraw From d28270241ea53ed1babb99ec8c6747a96df76ed4 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:54:52 +0800 Subject: [PATCH 25/55] feat(billboard): revise deployment & tests --- src/Billboard/Billboard.sol | 36 +- src/Billboard/IBillboard.sol | 10 +- src/test/Billboard/BillboardTest.t.sol | 423 ++++++++++----------- src/test/Billboard/BillboardTestBase.t.sol | 26 +- 4 files changed, 235 insertions(+), 260 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index bd39cac..0e4435c 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -13,22 +13,24 @@ contract Billboard is IBillboard { address public admin; mapping(address => bool) public whitelist; - constructor() { + constructor(address registry_, uint256 taxRate_, string memory name_, string memory symbol_) { admin = msg.sender; whitelist[msg.sender] = true; + + // deploy operator only + if (registry_ != address(0)) { + registry = BillboardRegistry(registry_); + } + // deploy operator and registry + else { + registry = new BillboardRegistry(address(this), taxRate_, name_, symbol_); + } } ////////////////////////////// /// Modifiers ////////////////////////////// - modifier isValidAddress(address value_) { - if (value_ == address(0)) { - revert InvalidAddress(); - } - _; - } - modifier isFromAdmin() { if (msg.sender != admin) { revert Unauthorized("admin"); @@ -63,10 +65,14 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function upgradeRegistry(address contract_) external isValidAddress(contract_) isFromAdmin { - registry = BillboardRegistry(contract_); + function setRegistryOperator(address operator_) external isFromAdmin { + registry.setOperator(operator_); } + ////////////////////////////// + /// Access control + ////////////////////////////// + /// @inheritdoc IBillboard function setIsOpened(bool value_) external isFromAdmin { isOpened = value_; @@ -87,9 +93,9 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function mintBoard(address to_) external isValidAddress(to_) isFromWhitelist { - if (!isOpened) { - revert MintClosed(); + function mintBoard(address to_) external { + if (!isOpened && whitelist[msg.sender] != true) { + revert Unauthorized("whitelist"); } registry.mintBoard(to_); @@ -192,6 +198,10 @@ contract Billboard is IBillboard { uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); + // TODO: check if current address already has bidded + // TODO: transfer ETH to registry + // TODO: set highestBidder + // create new auction and new bid if no next auction if (_nextAuction.tokenId == 0) { _newAuctionAndBid(tokenId_, amount_); diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 4ec3bc4..428c7b9 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -8,12 +8,8 @@ interface IBillboard { /// Error ////////////////////////////// - error InvalidAddress(); - error Unauthorized(string type_); - error MintClosed(); - error BoardNotFound(); error AuctionNotFound(); @@ -27,11 +23,11 @@ interface IBillboard { ////////////////////////////// /** - * @notice Switch the registry logic contract to another one. + * @notice Set the address of operator to current registry contract. * - * @param contract_ Address of new registry logic contract. + * @param operator_ Address of operator_. */ - function upgradeRegistry(address contract_) external; + function setRegistryOperator(address operator_) external; ////////////////////////////// /// Access control diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 26cf9fd..bfc4b46 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -8,38 +8,38 @@ contract BillboardTest is BillboardTestBase { /// Upgradability ////////////////////////////// - function testUpgradeAuctionByAttacker() public { - vm.startPrank(ATTACKER); + function testUpgradeRegistry() public { + vm.startPrank(ADMIN); - vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - operator.upgradeAuction(ZERO_ADDRESS); + // deploy new operator + Billboard newOperator = new Billboard(address(registry), TAX_RATE, "BLBD", "BLBD"); + assertEq(newOperator.admin(), ADMIN); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); - operator.upgradeAuction(FAKE_CONTRACT); + // upgrade registry's operator + assertEq(registry.operator(), address(operator)); + operator.setRegistryOperator(address(newOperator)); + assertEq(registry.operator(), address(newOperator)); } function testUpgradeRegistryByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - operator.upgradeRegistry(ZERO_ADDRESS); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); - operator.upgradeRegistry(FAKE_CONTRACT); + operator.setRegistryOperator(FAKE_CONTRACT); } + ////////////////////////////// + /// Access control + ////////////////////////////// + function testSetIsOpened() public { vm.startPrank(ADMIN); operator.setIsOpened(true); - assertEq(true, auction.isOpened()); - assertEq(true, registry.isOpened()); - - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - auction.setIsOpened(true, ADMIN); + assertEq(operator.isOpened(), true); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - registry.setIsOpened(true, ADMIN); + operator.setIsOpened(false); + assertEq(operator.isOpened(), false); } function testSetIsOpenedByAttacker() public { @@ -52,20 +52,9 @@ contract BillboardTest is BillboardTestBase { function testAddToWhitelist() public { vm.startPrank(ADMIN); - vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - operator.addToWhitelist(ZERO_ADDRESS); - operator.addToWhitelist(USER_A); - assertEq(registry.whitelist(USER_A), true); - assertEq(registry.whitelist(USER_B), false); - assertEq(auction.whitelist(USER_A), true); - assertEq(auction.whitelist(USER_B), false); - - // not allow bypassing operator - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - registry.addToWhitelist(USER_A, ADMIN); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - auction.addToWhitelist(USER_A, ADMIN); + assertEq(operator.whitelist(USER_A), true); + assertEq(operator.whitelist(USER_B), false); } function testAddToWhitelistByAttacker() public { @@ -79,20 +68,10 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); operator.addToWhitelist(USER_A); - assertEq(registry.whitelist(USER_A), true); - - vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - operator.removeFromWhitelist(ZERO_ADDRESS); + assertEq(operator.whitelist(USER_A), true); operator.removeFromWhitelist(USER_A); - assertEq(registry.whitelist(USER_A), false); - assertEq(auction.whitelist(USER_A), false); - - // not allow bypassing operator - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - registry.removeFromWhitelist(USER_A, ADMIN); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); - auction.removeFromWhitelist(USER_A, ADMIN); + assertEq(operator.whitelist(USER_A), false); } function testRemoveToWhitelistByAttacker() public { @@ -115,255 +94,253 @@ contract BillboardTest is BillboardTestBase { // get board & check data IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.creator); - assertEq(ADMIN, board.tenant); - assertEq(0, board.lastHighestBidPrice); - assertEq("", board.name); - assertEq("", board.description); - assertEq("", board.location); - assertEq("", board.contentURI); - assertEq("", board.redirectURI); + assertEq(board.creator, ADMIN); + assertEq(board.auctionId, 0); + assertEq(board.name, ""); + assertEq(board.description, ""); + assertEq(board.location, ""); + assertEq(board.contentURI, ""); + assertEq(board.redirectURI, ""); // mint again for checking id generator operator.mintBoard(ADMIN); assertEq(2, registry.balanceOf(ADMIN)); board = operator.getBoard(2); - assertEq(ADMIN, board.creator); - assertEq(ADMIN, board.tenant); + assertEq(board.creator, ADMIN); } - function testMintBoardByAttacker() public { - vm.startPrank(ATTACKER); + // function testMintBoardByAttacker() public { + // vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - operator.mintBoard(ATTACKER); - } + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + // operator.mintBoard(ATTACKER); + // } - function testSetBoardProperties() public { - _mintBoard(); + // function testSetBoardProperties() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ADMIN); + // vm.stopPrank(); + // vm.startPrank(ADMIN); - operator.setBoardName(1, "name"); - operator.setBoardDescription(1, "description"); - operator.setBoardLocation(1, "location"); - operator.setBoardContentURI(1, "uri"); - operator.setBoardRedirectURI(1, "redirect URI"); + // operator.setBoardName(1, "name"); + // operator.setBoardDescription(1, "description"); + // operator.setBoardLocation(1, "location"); + // operator.setBoardContentURI(1, "uri"); + // operator.setBoardRedirectURI(1, "redirect URI"); - IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq("name", board.name); - assertEq("description", board.description); - assertEq("location", board.location); - assertEq("uri", board.contentURI); - assertEq("redirect URI", board.redirectURI); - } + // IBillboardRegistry.Board memory board = operator.getBoard(1); + // assertEq("name", board.name); + // assertEq("description", board.description); + // assertEq("location", board.location); + // assertEq("uri", board.contentURI); + // assertEq("redirect URI", board.redirectURI); + // } - function testSetBoardProprtiesByAttacker() public { - _mintBoard(); + // function testSetBoardProprtiesByAttacker() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ATTACKER); + // vm.stopPrank(); + // vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardName(1, "name"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardName(1, "name"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardDescription(1, "description"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardDescription(1, "description"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardLocation(1, "location"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardLocation(1, "location"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - operator.setBoardContentURI(1, "uri"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); + // operator.setBoardContentURI(1, "uri"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - operator.setBoardRedirectURI(1, "redirect URI"); - } + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); + // operator.setBoardRedirectURI(1, "redirect URI"); + // } - function testGetTokenURI() public { - _mintBoard(); + // function testGetTokenURI() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ADMIN); + // vm.stopPrank(); + // vm.startPrank(ADMIN); - operator.setBoardContentURI(1, "new uri"); - assertEq("new uri", registry.tokenURI(1)); - } + // operator.setBoardContentURI(1, "new uri"); + // assertEq("new uri", registry.tokenURI(1)); + // } - function testTransfer() public { - _mintBoard(); + // function testTransfer() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ADMIN); - assertEq(ADMIN, registry.ownerOf(1)); + // vm.stopPrank(); + // vm.startPrank(ADMIN); + // assertEq(ADMIN, registry.ownerOf(1)); - // transfer board from admin to zero address - vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - registry.transferFrom(ADMIN, ZERO_ADDRESS, 1); + // // transfer board from admin to zero address + // vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); + // registry.transferFrom(ADMIN, ZERO_ADDRESS, 1); - // transfer board from admin to user_a - registry.transferFrom(ADMIN, USER_A, 1); - IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.creator); - assertEq(USER_A, board.tenant); - assertEq(USER_A, registry.ownerOf(1)); + // // transfer board from admin to user_a + // registry.transferFrom(ADMIN, USER_A, 1); + // IBillboardRegistry.Board memory board = operator.getBoard(1); + // assertEq(ADMIN, board.creator); + // assertEq(USER_A, board.tenant); + // assertEq(USER_A, registry.ownerOf(1)); - vm.stopPrank(); - vm.startPrank(USER_A); + // vm.stopPrank(); + // vm.startPrank(USER_A); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardName(1, "name by a"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardName(1, "name by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardDescription(1, "description by a"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardDescription(1, "description by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardLocation(1, "location by a"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardLocation(1, "location by a"); - operator.setBoardContentURI(1, "uri by a"); - operator.setBoardRedirectURI(1, "redirect URI by a"); + // operator.setBoardContentURI(1, "uri by a"); + // operator.setBoardRedirectURI(1, "redirect URI by a"); - board = operator.getBoard(1); - assertEq("", board.name); - assertEq("", board.description); - assertEq("", board.location); - assertEq("uri by a", board.contentURI); - assertEq("redirect URI by a", board.redirectURI); + // board = operator.getBoard(1); + // assertEq("", board.name); + // assertEq("", board.description); + // assertEq("", board.location); + // assertEq("uri by a", board.contentURI); + // assertEq("redirect URI by a", board.redirectURI); - // transfer board from user_a to user_b - registry.safeTransferFrom(USER_A, USER_B, 1); - board = operator.getBoard(1); - assertEq(ADMIN, board.creator); - assertEq(USER_B, board.tenant); - assertEq(USER_B, registry.ownerOf(1)); + // // transfer board from user_a to user_b + // registry.safeTransferFrom(USER_A, USER_B, 1); + // board = operator.getBoard(1); + // assertEq(ADMIN, board.creator); + // assertEq(USER_B, board.tenant); + // assertEq(USER_B, registry.ownerOf(1)); - vm.stopPrank(); - vm.startPrank(USER_B); + // vm.stopPrank(); + // vm.startPrank(USER_B); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardName(1, "name by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardName(1, "name by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardDescription(1, "description by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardDescription(1, "description by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardLocation(1, "location by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardLocation(1, "location by b"); - operator.setBoardContentURI(1, "uri by b"); - operator.setBoardRedirectURI(1, "redirect URI by b"); + // operator.setBoardContentURI(1, "uri by b"); + // operator.setBoardRedirectURI(1, "redirect URI by b"); - board = operator.getBoard(1); - assertEq("", board.name); - assertEq("", board.description); - assertEq("", board.location); - assertEq("uri by b", board.contentURI); - assertEq("redirect URI by b", board.redirectURI); + // board = operator.getBoard(1); + // assertEq("", board.name); + // assertEq("", board.description); + // assertEq("", board.location); + // assertEq("uri by b", board.contentURI); + // assertEq("redirect URI by b", board.redirectURI); - // transfer board from user_b to user_c by operator - vm.stopPrank(); - vm.startPrank(address(operator)); + // // transfer board from user_b to user_c by operator + // vm.stopPrank(); + // vm.startPrank(address(operator)); - registry.transferFrom(USER_B, USER_C, 1); - board = operator.getBoard(1); - assertEq(ADMIN, board.creator); - assertEq(USER_C, board.tenant); - assertEq(USER_C, registry.ownerOf(1)); + // registry.transferFrom(USER_B, USER_C, 1); + // board = operator.getBoard(1); + // assertEq(ADMIN, board.creator); + // assertEq(USER_C, board.tenant); + // assertEq(USER_C, registry.ownerOf(1)); - vm.stopPrank(); - vm.startPrank(USER_C); + // vm.stopPrank(); + // vm.startPrank(USER_C); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardName(1, "name by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardName(1, "name by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardDescription(1, "description by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardDescription(1, "description by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - operator.setBoardLocation(1, "location by b"); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // operator.setBoardLocation(1, "location by b"); - operator.setBoardContentURI(1, "uri by c"); - operator.setBoardRedirectURI(1, "redirect URI by c"); + // operator.setBoardContentURI(1, "uri by c"); + // operator.setBoardRedirectURI(1, "redirect URI by c"); - board = operator.getBoard(1); - assertEq("", board.name); - assertEq("", board.description); - assertEq("", board.location); - assertEq("uri by c", board.contentURI); - assertEq("redirect URI by c", board.redirectURI); - } + // board = operator.getBoard(1); + // assertEq("", board.name); + // assertEq("", board.description); + // assertEq("", board.location); + // assertEq("uri by c", board.contentURI); + // assertEq("redirect URI by c", board.redirectURI); + // } - function testTransferByAttacker() public { - _mintBoard(); + // function testTransferByAttacker() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ATTACKER); + // vm.stopPrank(); + // vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); - registry.transferFrom(ADMIN, ATTACKER, 1); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); + // registry.transferFrom(ADMIN, ATTACKER, 1); - vm.stopPrank(); - vm.startPrank(ADMIN); - registry.transferFrom(ADMIN, USER_A, 1); + // vm.stopPrank(); + // vm.startPrank(ADMIN); + // registry.transferFrom(ADMIN, USER_A, 1); - vm.stopPrank(); - vm.startPrank(ATTACKER); + // vm.stopPrank(); + // vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); - registry.safeTransferFrom(USER_A, ATTACKER, 1); - } + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); + // registry.safeTransferFrom(USER_A, ATTACKER, 1); + // } - function testApprove() public { - _mintBoard(); + // function testApprove() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(ADMIN); + // vm.stopPrank(); + // vm.startPrank(ADMIN); - registry.approve(USER_A, 1); - assertEq(USER_A, registry.getApproved(1)); + // registry.approve(USER_A, 1); + // assertEq(USER_A, registry.getApproved(1)); - vm.stopPrank(); - vm.startPrank(USER_A); - registry.transferFrom(ADMIN, USER_A, 1); + // vm.stopPrank(); + // vm.startPrank(USER_A); + // registry.transferFrom(ADMIN, USER_A, 1); - IBillboardRegistry.Board memory board = operator.getBoard(1); - assertEq(ADMIN, board.creator); - assertEq(USER_A, board.tenant); - } + // IBillboardRegistry.Board memory board = operator.getBoard(1); + // assertEq(ADMIN, board.creator); + // assertEq(USER_A, board.tenant); + // } - function testApproveByAttacker() public { - _mintBoard(); + // function testApproveByAttacker() public { + // _mintBoard(); - vm.stopPrank(); - vm.startPrank(USER_A); + // vm.stopPrank(); + // vm.startPrank(USER_A); - vm.expectRevert("ERC721: approve caller is not token owner or approved for all"); - registry.approve(USER_A, 1); - } + // vm.expectRevert("ERC721: approve caller is not token owner or approved for all"); + // registry.approve(USER_A, 1); + // } - ////////////////////////////// - /// Auction - ////////////////////////////// + // ////////////////////////////// + // /// Auction + // ////////////////////////////// - function testSetTaxRate() public { - vm.startPrank(ADMIN); + // function testSetTaxRate() public { + // vm.startPrank(ADMIN); - operator.setTaxRate(2); - assertEq(2, operator.getTaxRate()); - } + // operator.setTaxRate(2); + // assertEq(2, operator.getTaxRate()); + // } - function testSetTaxRateByAttacker() public { - vm.startPrank(ATTACKER); + // function testSetTaxRateByAttacker() public { + // vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); - operator.setTaxRate(2); - } + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + // operator.setTaxRate(2); + // } - function testBid() public {} + // function testBid() public {} - function testClearAuction() public {} + // function testClearAuction() public {} - function testBidByAttacker() public {} + // function testBidByAttacker() public {} - function testClearAuctionByAttacker() public {} + // function testClearAuctionByAttacker() public {} } diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index e41dc20..df56f21 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -29,26 +29,18 @@ contract BillboardTestBase is Test { function setUp() public { vm.startPrank(ADMIN); - // deploy operator - operator = new Billboard(); - assertEq(ADMIN, operator.admin()); - address operatorAddress = address(operator); - - // deploy registry - registry = new BillboardRegistry(operatorAddress, TAX_RATE, "BLBD", "BLBD"); - assertEq(operatorAddress, registry.operator()); - - // upgrade registry - operator.upgradeRegistry(address(registry)); - assertEq(address(registry), address(operator.registry())); - } + // deploy operator & registry + operator = new Billboard(address(0), TAX_RATE, "BLBD", "BLBD"); + registry = operator.registry(); + assertEq(operator.admin(), ADMIN); + assertEq(registry.operator(), address(operator)); - function _mintBoard() public { vm.stopPrank(); - vm.startPrank(ADMIN); + } - // mint + function _mintBoard() public { + vm.prank(ADMIN); operator.mintBoard(ADMIN); - assertEq(1, registry.balanceOf(ADMIN)); + assertEq(registry.balanceOf(ADMIN), 1); } } From 32f96d590bea975827750b01f3eedd7885a26358 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 15 Nov 2023 16:59:38 +0800 Subject: [PATCH 26/55] feat(billboard): add tests for mintBoard --- src/Billboard/Billboard.sol | 6 +++--- src/test/Billboard/BillboardTest.t.sol | 23 ++++++++++++++++------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 0e4435c..c93933d 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -94,11 +94,11 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external { - if (!isOpened && whitelist[msg.sender] != true) { + if (isOpened || whitelist[msg.sender] == true) { + registry.mintBoard(to_); + } else { revert Unauthorized("whitelist"); } - - registry.mintBoard(to_); } /// @inheritdoc IBillboard diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index bfc4b46..11abc53 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -90,7 +90,7 @@ contract BillboardTest is BillboardTestBase { // mint operator.mintBoard(ADMIN); - assertEq(1, registry.balanceOf(ADMIN)); + assertEq(registry.balanceOf(ADMIN), 1); // get board & check data IBillboardRegistry.Board memory board = operator.getBoard(1); @@ -104,17 +104,26 @@ contract BillboardTest is BillboardTestBase { // mint again for checking id generator operator.mintBoard(ADMIN); - assertEq(2, registry.balanceOf(ADMIN)); + assertEq(registry.balanceOf(ADMIN), 2); board = operator.getBoard(2); assertEq(board.creator, ADMIN); } - // function testMintBoardByAttacker() public { - // vm.startPrank(ATTACKER); + function testMintBoardIfOpened() public { + vm.startPrank(ADMIN); + operator.setIsOpened(true); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.mintBoard(ATTACKER); - // } + vm.startPrank(USER_A); + operator.mintBoard(USER_A); + assertEq(registry.balanceOf(USER_A), 1); + } + + function testMintBoardByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + operator.mintBoard(ATTACKER); + } // function testSetBoardProperties() public { // _mintBoard(); From d7c1b89c7514bd80d5ed0f5d76649d617f6103bf Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 15 Nov 2023 17:25:28 +0800 Subject: [PATCH 27/55] feat(billboard): add tests for board properties --- src/Billboard/Billboard.sol | 4 +- src/Billboard/BillboardRegistry.sol | 8 +- src/Billboard/IBillboard.sol | 2 +- src/test/Billboard/BillboardTest.t.sol | 94 +++++++++++----------- src/test/Billboard/BillboardTestBase.t.sol | 6 +- 5 files changed, 56 insertions(+), 58 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index c93933d..173d657 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -93,9 +93,9 @@ contract Billboard is IBillboard { ////////////////////////////// /// @inheritdoc IBillboard - function mintBoard(address to_) external { + function mintBoard(address to_) external returns (uint256 tokenId) { if (isOpened || whitelist[msg.sender] == true) { - registry.mintBoard(to_); + tokenId = registry.mintBoard(to_); } else { revert Unauthorized("whitelist"); } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index f8fd98c..1f0a76b 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -67,9 +67,9 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function mintBoard(address to_) external isFromOperator returns (uint256 tokenId) { _tokenIds.increment(); - uint256 newTokenId = _tokenIds.current(); + tokenId = _tokenIds.current(); - _safeMint(to_, newTokenId); + _safeMint(to_, tokenId); Board memory _newBoard = Board({ creator: to_, @@ -80,12 +80,10 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { contentURI: "", redirectURI: "" }); - boards[newTokenId] = _newBoard; + boards[tokenId] = _newBoard; // TODO // emit Mint(newBoardId, to_); - - return newTokenId; } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 428c7b9..56db621 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -63,7 +63,7 @@ interface IBillboard { * * @param to_ Address of the new board receiver. */ - function mintBoard(address to_) external; + function mintBoard(address to_) external returns (uint256 tokenId); /** * @notice Get a board data. diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 11abc53..4a5dc25 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -92,6 +92,9 @@ contract BillboardTest is BillboardTestBase { operator.mintBoard(ADMIN); assertEq(registry.balanceOf(ADMIN), 1); + // ownership + assertEq(registry.ownerOf(1), ADMIN); + // get board & check data IBillboardRegistry.Board memory board = operator.getBoard(1); assertEq(board.creator, ADMIN); @@ -125,57 +128,54 @@ contract BillboardTest is BillboardTestBase { operator.mintBoard(ATTACKER); } - // function testSetBoardProperties() public { - // _mintBoard(); + function testSetBoardProperties() public { + uint256 _tokenId = _mintBoard(ADMIN); - // vm.stopPrank(); - // vm.startPrank(ADMIN); + vm.startPrank(ADMIN); - // operator.setBoardName(1, "name"); - // operator.setBoardDescription(1, "description"); - // operator.setBoardLocation(1, "location"); - // operator.setBoardContentURI(1, "uri"); - // operator.setBoardRedirectURI(1, "redirect URI"); + operator.setBoardName(_tokenId, "name"); + operator.setBoardDescription(_tokenId, "description"); + operator.setBoardLocation(_tokenId, "location"); + operator.setBoardContentURI(_tokenId, "uri"); + operator.setBoardRedirectURI(_tokenId, "redirect URI"); - // IBillboardRegistry.Board memory board = operator.getBoard(1); - // assertEq("name", board.name); - // assertEq("description", board.description); - // assertEq("location", board.location); - // assertEq("uri", board.contentURI); - // assertEq("redirect URI", board.redirectURI); - // } + IBillboardRegistry.Board memory board = operator.getBoard(1); + assertEq(board.name, "name"); + assertEq(board.description, "description"); + assertEq(board.location, "location"); + assertEq(board.contentURI, "uri"); + assertEq(board.redirectURI, "redirect URI"); + } - // function testSetBoardProprtiesByAttacker() public { - // _mintBoard(); + function testSetBoardProprtiesByAttacker() public { + uint256 _tokenId = _mintBoard(ADMIN); - // vm.stopPrank(); - // vm.startPrank(ATTACKER); + vm.startPrank(ATTACKER); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - // operator.setBoardName(1, "name"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardName(_tokenId, "name"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - // operator.setBoardDescription(1, "description"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardDescription(_tokenId, "description"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); - // operator.setBoardLocation(1, "location"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardLocation(_tokenId, "location"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - // operator.setBoardContentURI(1, "uri"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "tenant")); + operator.setBoardContentURI(_tokenId, "uri"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board tenant")); - // operator.setBoardRedirectURI(1, "redirect URI"); - // } + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "tenant")); + operator.setBoardRedirectURI(_tokenId, "redirect URI"); + } - // function testGetTokenURI() public { - // _mintBoard(); + function testGetTokenURI() public { + uint256 _tokenId = _mintBoard(ADMIN); - // vm.stopPrank(); - // vm.startPrank(ADMIN); + vm.startPrank(ADMIN); - // operator.setBoardContentURI(1, "new uri"); - // assertEq("new uri", registry.tokenURI(1)); - // } + operator.setBoardContentURI(_tokenId, "new uri"); + assertEq(registry.tokenURI(_tokenId), "new uri"); + } // function testTransfer() public { // _mintBoard(); @@ -198,13 +198,13 @@ contract BillboardTest is BillboardTestBase { // vm.stopPrank(); // vm.startPrank(USER_A); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardName(1, "name by a"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardDescription(1, "description by a"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardLocation(1, "location by a"); // operator.setBoardContentURI(1, "uri by a"); @@ -227,13 +227,13 @@ contract BillboardTest is BillboardTestBase { // vm.stopPrank(); // vm.startPrank(USER_B); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardName(1, "name by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardDescription(1, "description by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardLocation(1, "location by b"); // operator.setBoardContentURI(1, "uri by b"); @@ -259,13 +259,13 @@ contract BillboardTest is BillboardTestBase { // vm.stopPrank(); // vm.startPrank(USER_C); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardName(1, "name by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardDescription(1, "description by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "board creator")); + // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); // operator.setBoardLocation(1, "location by b"); // operator.setBoardContentURI(1, "uri by c"); diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index df56f21..db493f7 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -1,7 +1,7 @@ //SPDX-License-Identifier: Apache-2.0 pragma solidity ^0.8.20; -import "forge-std/console2.sol"; +import "forge-std/console.sol"; import "forge-std/Test.sol"; import "forge-std/Vm.sol"; @@ -38,9 +38,9 @@ contract BillboardTestBase is Test { vm.stopPrank(); } - function _mintBoard() public { + function _mintBoard(address to_) public returns (uint256 tokenId) { vm.prank(ADMIN); - operator.mintBoard(ADMIN); + tokenId = operator.mintBoard(to_); assertEq(registry.balanceOf(ADMIN), 1); } } From da0d73fd72428cde47327ace25ba47cd0ce9da92 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 15 Nov 2023 19:56:11 +0800 Subject: [PATCH 28/55] feat(billboard): add tests for ownership --- src/Billboard/BillboardRegistry.sol | 11 - src/test/Billboard/BillboardTest.t.sol | 252 +++++++++------------ src/test/Billboard/BillboardTestBase.t.sol | 4 +- 3 files changed, 113 insertions(+), 154 deletions(-) diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 1f0a76b..2b7a51a 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -244,17 +244,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { return boards[tokenId_].contentURI; } - /** - * @notice See {IERC721-isApprovedForAll}. - */ - function isApprovedForAll(address owner_, address operator_) public view override(ERC721, IERC721) returns (bool) { - if (operator_ == operator) { - return true; - } - - return super.isApprovedForAll(owner_, operator_); - } - /** * @notice See {IERC721-transferFrom}. */ diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 4a5dc25..392b652 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -42,7 +42,7 @@ contract BillboardTest is BillboardTestBase { assertEq(operator.isOpened(), false); } - function testSetIsOpenedByAttacker() public { + function testCannotSetIsOpenedByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); @@ -57,7 +57,7 @@ contract BillboardTest is BillboardTestBase { assertEq(operator.whitelist(USER_B), false); } - function testAddToWhitelistByAttacker() public { + function testCannotAddToWhitelistByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); @@ -74,7 +74,7 @@ contract BillboardTest is BillboardTestBase { assertEq(operator.whitelist(USER_A), false); } - function testRemoveToWhitelistByAttacker() public { + function testCannotRemoveToWhitelistByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); @@ -121,7 +121,7 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.balanceOf(USER_A), 1); } - function testMintBoardByAttacker() public { + function testCannotMintBoardByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); @@ -129,7 +129,7 @@ contract BillboardTest is BillboardTestBase { } function testSetBoardProperties() public { - uint256 _tokenId = _mintBoard(ADMIN); + uint256 _tokenId = _mintBoard(); vm.startPrank(ADMIN); @@ -147,8 +147,8 @@ contract BillboardTest is BillboardTestBase { assertEq(board.redirectURI, "redirect URI"); } - function testSetBoardProprtiesByAttacker() public { - uint256 _tokenId = _mintBoard(ADMIN); + function testCannotSetBoardProprtiesByAttacker() public { + uint256 _tokenId = _mintBoard(); vm.startPrank(ATTACKER); @@ -169,7 +169,7 @@ contract BillboardTest is BillboardTestBase { } function testGetTokenURI() public { - uint256 _tokenId = _mintBoard(ADMIN); + uint256 _tokenId = _mintBoard(); vm.startPrank(ADMIN); @@ -177,174 +177,126 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.tokenURI(_tokenId), "new uri"); } - // function testTransfer() public { - // _mintBoard(); - - // vm.stopPrank(); - // vm.startPrank(ADMIN); - // assertEq(ADMIN, registry.ownerOf(1)); - - // // transfer board from admin to zero address - // vm.expectRevert(abi.encodeWithSignature("InvalidAddress()")); - // registry.transferFrom(ADMIN, ZERO_ADDRESS, 1); - - // // transfer board from admin to user_a - // registry.transferFrom(ADMIN, USER_A, 1); - // IBillboardRegistry.Board memory board = operator.getBoard(1); - // assertEq(ADMIN, board.creator); - // assertEq(USER_A, board.tenant); - // assertEq(USER_A, registry.ownerOf(1)); - - // vm.stopPrank(); - // vm.startPrank(USER_A); - - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardName(1, "name by a"); - - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardDescription(1, "description by a"); - - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardLocation(1, "location by a"); - - // operator.setBoardContentURI(1, "uri by a"); - // operator.setBoardRedirectURI(1, "redirect URI by a"); + function testTransfer() public { + // mint + uint256 _tokenId = _mintBoard(); - // board = operator.getBoard(1); - // assertEq("", board.name); - // assertEq("", board.description); - // assertEq("", board.location); - // assertEq("uri by a", board.contentURI); - // assertEq("redirect URI by a", board.redirectURI); + // transfer + vm.startPrank(ADMIN); + registry.transferFrom(ADMIN, USER_A, _tokenId); - // // transfer board from user_a to user_b - // registry.safeTransferFrom(USER_A, USER_B, 1); - // board = operator.getBoard(1); - // assertEq(ADMIN, board.creator); - // assertEq(USER_B, board.tenant); - // assertEq(USER_B, registry.ownerOf(1)); + IBillboardRegistry.Board memory board = operator.getBoard(_tokenId); + assertEq(board.creator, ADMIN); + assertEq(registry.balanceOf(ADMIN), 0); + assertEq(registry.ownerOf(_tokenId), USER_A); - // vm.stopPrank(); - // vm.startPrank(USER_B); + // set board properties + vm.stopPrank(); + vm.startPrank(USER_A); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardName(1, "name by b"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardName(_tokenId, "name by a"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardDescription(1, "description by b"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardDescription(_tokenId, "description by a"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardLocation(1, "location by b"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardLocation(_tokenId, "location by a"); - // operator.setBoardContentURI(1, "uri by b"); - // operator.setBoardRedirectURI(1, "redirect URI by b"); + operator.setBoardContentURI(_tokenId, "uri by a"); + operator.setBoardRedirectURI(_tokenId, "redirect URI by a"); - // board = operator.getBoard(1); - // assertEq("", board.name); - // assertEq("", board.description); - // assertEq("", board.location); - // assertEq("uri by b", board.contentURI); - // assertEq("redirect URI by b", board.redirectURI); + board = operator.getBoard(_tokenId); + assertEq(board.name, ""); + assertEq(board.description, ""); + assertEq(board.location, ""); + assertEq(board.contentURI, "uri by a"); + assertEq(board.redirectURI, "redirect URI by a"); - // // transfer board from user_b to user_c by operator - // vm.stopPrank(); - // vm.startPrank(address(operator)); + // transfer board from user_a to user_b + registry.safeTransferFrom(USER_A, USER_B, 1); + board = operator.getBoard(_tokenId); + assertEq(board.creator, ADMIN); + assertEq(registry.ownerOf(1), USER_B); - // registry.transferFrom(USER_B, USER_C, 1); - // board = operator.getBoard(1); - // assertEq(ADMIN, board.creator); - // assertEq(USER_C, board.tenant); - // assertEq(USER_C, registry.ownerOf(1)); + vm.stopPrank(); + vm.startPrank(USER_B); - // vm.stopPrank(); - // vm.startPrank(USER_C); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardName(_tokenId, "name by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardName(1, "name by b"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardDescription(_tokenId, "description by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardDescription(1, "description by b"); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + operator.setBoardLocation(_tokenId, "location by b"); - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); - // operator.setBoardLocation(1, "location by b"); + operator.setBoardContentURI(_tokenId, "uri by b"); + operator.setBoardRedirectURI(_tokenId, "redirect URI by b"); - // operator.setBoardContentURI(1, "uri by c"); - // operator.setBoardRedirectURI(1, "redirect URI by c"); + board = operator.getBoard(_tokenId); + assertEq(board.name, ""); + assertEq(board.description, ""); + assertEq(board.location, ""); + assertEq(board.contentURI, "uri by b"); + assertEq(board.redirectURI, "redirect URI by b"); + } - // board = operator.getBoard(1); - // assertEq("", board.name); - // assertEq("", board.description); - // assertEq("", board.location); - // assertEq("uri by c", board.contentURI); - // assertEq("redirect URI by c", board.redirectURI); - // } + function testCannotTransferToZeroAddress() public { + uint256 _tokenId = _mintBoard(); - // function testTransferByAttacker() public { - // _mintBoard(); + vm.startPrank(ADMIN); - // vm.stopPrank(); - // vm.startPrank(ATTACKER); + vm.expectRevert("ERC721: transfer to the zero address"); + registry.transferFrom(ADMIN, ZERO_ADDRESS, _tokenId); + } - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); - // registry.transferFrom(ADMIN, ATTACKER, 1); + function testCannotTransferByOperator() public { + uint256 _tokenId = _mintBoard(); - // vm.stopPrank(); - // vm.startPrank(ADMIN); - // registry.transferFrom(ADMIN, USER_A, 1); + vm.startPrank(address(operator)); - // vm.stopPrank(); - // vm.startPrank(ATTACKER); + vm.expectRevert("ERC721: caller is not token owner or approved"); + registry.transferFrom(USER_B, USER_C, _tokenId); + } - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "not owner nor approved")); - // registry.safeTransferFrom(USER_A, ATTACKER, 1); - // } + function testCannotTransferByAttacker() public { + uint256 _tokenId = _mintBoard(); - // function testApprove() public { - // _mintBoard(); + vm.startPrank(ATTACKER); - // vm.stopPrank(); - // vm.startPrank(ADMIN); + vm.expectRevert("ERC721: caller is not token owner or approved"); + registry.transferFrom(ADMIN, ATTACKER, _tokenId); + } - // registry.approve(USER_A, 1); - // assertEq(USER_A, registry.getApproved(1)); + function testApprove() public { + uint256 _tokenId = _mintBoard(); - // vm.stopPrank(); - // vm.startPrank(USER_A); - // registry.transferFrom(ADMIN, USER_A, 1); + vm.startPrank(ADMIN); + registry.approve(USER_A, _tokenId); + assertEq(USER_A, registry.getApproved(_tokenId)); - // IBillboardRegistry.Board memory board = operator.getBoard(1); - // assertEq(ADMIN, board.creator); - // assertEq(USER_A, board.tenant); - // } + vm.stopPrank(); + vm.startPrank(USER_A); + registry.transferFrom(ADMIN, USER_A, _tokenId); - // function testApproveByAttacker() public { - // _mintBoard(); + IBillboardRegistry.Board memory board = operator.getBoard(_tokenId); + assertEq(ADMIN, board.creator); + } - // vm.stopPrank(); - // vm.startPrank(USER_A); + function testApproveByAttacker() public { + uint256 _tokenId = _mintBoard(); - // vm.expectRevert("ERC721: approve caller is not token owner or approved for all"); - // registry.approve(USER_A, 1); - // } + vm.stopPrank(); + vm.startPrank(ATTACKER); + vm.expectRevert("ERC721: approve caller is not token owner or approved for all"); + registry.approve(USER_A, _tokenId); + } // ////////////////////////////// // /// Auction // ////////////////////////////// - // function testSetTaxRate() public { - // vm.startPrank(ADMIN); - - // operator.setTaxRate(2); - // assertEq(2, operator.getTaxRate()); - // } - - // function testSetTaxRateByAttacker() public { - // vm.startPrank(ATTACKER); - - // vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); - // operator.setTaxRate(2); - // } - // function testBid() public {} // function testClearAuction() public {} @@ -352,4 +304,22 @@ contract BillboardTest is BillboardTestBase { // function testBidByAttacker() public {} // function testClearAuctionByAttacker() public {} + + ////////////////////////////// + /// Tax & Withdraw + ////////////////////////////// + + function testSetTaxRate() public { + vm.startPrank(ADMIN); + + operator.setTaxRate(2); + assertEq(operator.getTaxRate(), 2); + } + + function testSetTaxRateByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + operator.setTaxRate(2); + } } diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index db493f7..89e97e2 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -38,9 +38,9 @@ contract BillboardTestBase is Test { vm.stopPrank(); } - function _mintBoard(address to_) public returns (uint256 tokenId) { + function _mintBoard() public returns (uint256 tokenId) { vm.prank(ADMIN); - tokenId = operator.mintBoard(to_); + tokenId = operator.mintBoard(ADMIN); assertEq(registry.balanceOf(ADMIN), 1); } } From 2c1660e670256dc71c5cbb9d4c63e76790c42a92 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 16 Nov 2023 12:43:57 +0800 Subject: [PATCH 29/55] fix(billboard): add missing transfer and highestBidder logic of `placeBid` func --- src/Billboard/Billboard.sol | 10 +++++----- src/Billboard/BillboardRegistry.sol | 21 ++++++++++++++++++++- src/Billboard/IBillboard.sol | 4 +++- src/test/Billboard/BillboardTest.t.sol | 10 +++++----- 4 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 173d657..7c951dd 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -191,17 +191,13 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function placeBid(uint256 tokenId_, uint256 amount_) external isFromWhitelist { + function placeBid(uint256 tokenId_, uint256 amount_) external payable isFromWhitelist { (address _boardCreator, , , , , , ) = registry.boards(tokenId_); if (_boardCreator == address(0)) revert BoardNotFound(); uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); - // TODO: check if current address already has bidded - // TODO: transfer ETH to registry - // TODO: set highestBidder - // create new auction and new bid if no next auction if (_nextAuction.tokenId == 0) { _newAuctionAndBid(tokenId_, amount_); @@ -215,6 +211,10 @@ contract Billboard is IBillboard { return; } else { // push new bid to next auction + if (registry.getBid(tokenId_, _nextAuctionId, msg.sender).bidder != address(0)) { + revert BidAlreadyPlaced(); + } + registry.newBid(tokenId_, _nextAuctionId, msg.sender, amount_, calculateTax(amount_)); } } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 2b7a51a..8f7c2bc 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -22,7 +22,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // tokenId => auctionId => Auction mapping(uint256 => mapping(uint256 => Auction)) public boardAuctions; - // tokenId => nextAuctionId (start from 1) + // tokenId => nextAuctionId (start from 1 if exists) mapping(uint256 => uint256) public nextBoardAuctionId; // tokenId => auctionId => bidders @@ -191,8 +191,27 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { isWon: false }); + // add to auction bids auctionBids[tokenId_][auctionId_][bidder_] = _bid; + + // add to auction bidders auctionBidders[tokenId_][auctionId_].push(bidder_); + + // set auction highest bidder if no highest bidder or price is higher. + // + // Note: for same price, the first bidder will always be + // the highest bidder since the block.timestamp is always greater. + address highestBidder = boardAuctions[tokenId_][auctionId_].highestBidder; + Bid memory highestBid = auctionBids[tokenId_][auctionId_][highestBidder]; + if (highestBid.bidder == address(0) || price_ > highestBid.price) { + boardAuctions[tokenId_][auctionId_].highestBidder = bidder_; + } + + // lock ETH + (bool _success, ) = address(this).call{value: price_ + tax_}(""); + if (!_success) { + revert TransferFailed(); + } } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 56db621..a0e6847 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -16,6 +16,8 @@ interface IBillboard { error AuctionNotEnded(); + error BidAlreadyPlaced(); + error WithdrawFailed(); ////////////////////////////// @@ -142,7 +144,7 @@ interface IBillboard { * @param tokenId_ Token ID of a board. * @param amount_ Amount of a bid. */ - function placeBid(uint256 tokenId_, uint256 amount_) external; + function placeBid(uint256 tokenId_, uint256 amount_) external payable; /** * @notice Get bid of a board auction by auction ID. diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 392b652..694e340 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -274,14 +274,14 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); registry.approve(USER_A, _tokenId); - assertEq(USER_A, registry.getApproved(_tokenId)); + assertEq(registry.getApproved(_tokenId), USER_A); vm.stopPrank(); vm.startPrank(USER_A); registry.transferFrom(ADMIN, USER_A, _tokenId); IBillboardRegistry.Board memory board = operator.getBoard(_tokenId); - assertEq(ADMIN, board.creator); + assertEq(board.creator, ADMIN); } function testApproveByAttacker() public { @@ -293,9 +293,9 @@ contract BillboardTest is BillboardTestBase { registry.approve(USER_A, _tokenId); } - // ////////////////////////////// - // /// Auction - // ////////////////////////////// + ////////////////////////////// + /// Auction + ////////////////////////////// // function testBid() public {} From cf251164632044e7131256159aed7e7fbd114323 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 16 Nov 2023 14:34:16 +0800 Subject: [PATCH 30/55] fix(billboard): remove unused Board.auctionId --- src/Billboard/Billboard.sol | 26 ++++++++++++++------------ src/Billboard/BillboardRegistry.sol | 6 ------ src/Billboard/IBillboardRegistry.sol | 9 --------- src/test/Billboard/BillboardTest.t.sol | 8 ++++++++ 4 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 7c951dd..9f2229d 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -46,7 +46,7 @@ contract Billboard is IBillboard { } modifier isFromBoardCreator(uint256 tokenId_) { - (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + (address _boardCreator, , , , , ) = registry.boards(tokenId_); if (_boardCreator != msg.sender) { revert Unauthorized("creator"); } @@ -145,22 +145,26 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) external { - (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + // revert if board not found + (address _boardCreator, , , , , ) = registry.boards(tokenId_); if (_boardCreator == address(0)) revert BoardNotFound(); + // revert if it's a new board uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); if (_nextAuctionId == 0) revert AuctionNotFound(); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); + // revert if auction is still running + if (block.timestamp < _nextAuction.endAt) revert AuctionNotEnded(); + // reclaim ownership to board creator if no auction - if (_nextAuction.tokenId == 0) { - registry.safeTransferByOperator(msg.sender, _boardCreator, tokenId_); + address _prevOwner = registry.ownerOf(tokenId_); + if (_nextAuction.tokenId == 0 && _prevOwner != _boardCreator) { + registry.safeTransferByOperator(_prevOwner, _boardCreator, tokenId_); return; } - if (block.timestamp < _nextAuction.endAt) revert AuctionNotEnded(); - IBillboardRegistry.Bid memory _highestBid = registry.getBid( tokenId_, _nextAuctionId, @@ -168,7 +172,7 @@ contract Billboard is IBillboard { ); if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) - registry.transferAmount(registry.ownerOf(tokenId_), _highestBid.price); + registry.transferAmount(_prevOwner, _highestBid.price); // transfer bid tax to board creator's tax treasury (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(_boardCreator); @@ -176,7 +180,7 @@ contract Billboard is IBillboard { } // transfer ownership - registry.safeTransferByOperator(registry.ownerOf(tokenId_), _nextAuction.highestBidder, tokenId_); + registry.safeTransferByOperator(_prevOwner, _nextAuction.highestBidder, tokenId_); // mark highest bid as won registry.setBidWon(tokenId_, _nextAuctionId, _nextAuction.highestBidder, true); @@ -185,14 +189,11 @@ contract Billboard is IBillboard { uint256 leaseStartAt = block.timestamp; uint256 leaseEndAt = block.timestamp + 14 days; registry.setAuctionLease(tokenId_, _nextAuctionId, leaseStartAt, leaseEndAt); - - // update Board.auctionId - registry.setBoardAuctionId(tokenId_, _nextAuctionId); } /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external payable isFromWhitelist { - (address _boardCreator, , , , , , ) = registry.boards(tokenId_); + (address _boardCreator, , , , , ) = registry.boards(tokenId_); if (_boardCreator == address(0)) revert BoardNotFound(); uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); @@ -304,6 +305,7 @@ contract Billboard is IBillboard { uint256 amount = _bid.price + _bid.tax; if (_bid.isWithdrawn) revert WithdrawFailed(); + if (_bid.isWon) revert WithdrawFailed(); if (amount <= 0) revert WithdrawFailed(); // transfer bid price and tax back to the bidder diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 8f7c2bc..48ad12b 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -73,7 +73,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { Board memory _newBoard = Board({ creator: to_, - auctionId: 0, name: "", description: "", location: "", @@ -96,11 +95,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { board = boards[tokenId_]; } - /// @inheritdoc IBillboardRegistry - function setBoardAuctionId(uint256 tokenId_, uint256 auctionId_) external isFromOperator { - boards[tokenId_].auctionId = auctionId_; - } - /// @inheritdoc IBillboardRegistry function setBoardName(uint256 tokenId_, string calldata name_) external isFromOperator { boards[tokenId_].name = name_; diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 4fc7c69..f30bad2 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -32,7 +32,6 @@ interface IBillboardRegistry is IERC721 { struct Board { address creator; - uint256 auctionId; // last lease auction ID string name; string description; string location; @@ -101,14 +100,6 @@ interface IBillboardRegistry is IERC721 { */ function getBoard(uint256 tokenId_) external view returns (Board memory board); - /** - * @notice Set the auctionId of a board. - * - * @param tokenId_ Token ID of a board. - * @param auctionId_ Auction ID of an auction. - */ - function setBoardAuctionId(uint256 tokenId_, uint256 auctionId_) external; - /** * @notice Set the name of a board by board creator. * diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 694e340..b0d9e72 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -260,6 +260,14 @@ contract BillboardTest is BillboardTestBase { registry.transferFrom(USER_B, USER_C, _tokenId); } + function testTransferByOperator() public { + uint256 _tokenId = _mintBoard(); + + vm.startPrank(address(operator)); + registry.safeTransferByOperator(ADMIN, USER_A, _tokenId); + assertEq(registry.ownerOf(_tokenId), USER_A); + } + function testCannotTransferByAttacker() public { uint256 _tokenId = _mintBoard(); From 43f0e46e7cc7b7e0dc5953673d9efe689ef1f995 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:06:22 +0800 Subject: [PATCH 31/55] feat(billboard): add tests for placeBid --- src/Billboard/Billboard.sol | 28 ++++++++--- src/Billboard/BillboardRegistry.sol | 20 +++----- src/Billboard/IBillboard.sol | 2 + src/Billboard/IBillboardRegistry.sol | 2 - src/test/Billboard/BillboardTest.t.sol | 58 ++++++++++++++++++++-- src/test/Billboard/BillboardTestBase.t.sol | 2 +- 6 files changed, 86 insertions(+), 26 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 9f2229d..17084cd 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -13,7 +13,7 @@ contract Billboard is IBillboard { address public admin; mapping(address => bool) public whitelist; - constructor(address registry_, uint256 taxRate_, string memory name_, string memory symbol_) { + constructor(address payable registry_, uint256 taxRate_, string memory name_, string memory symbol_) { admin = msg.sender; whitelist[msg.sender] = true; @@ -144,7 +144,7 @@ contract Billboard is IBillboard { } /// @inheritdoc IBillboard - function clearAuction(uint256 tokenId_) external { + function clearAuction(uint256 tokenId_) public { // revert if board not found (address _boardCreator, , , , , ) = registry.boards(tokenId_); if (_boardCreator == address(0)) revert BoardNotFound(); @@ -160,7 +160,7 @@ contract Billboard is IBillboard { // reclaim ownership to board creator if no auction address _prevOwner = registry.ownerOf(tokenId_); - if (_nextAuction.tokenId == 0 && _prevOwner != _boardCreator) { + if (_nextAuction.startAt == 0 && _prevOwner != _boardCreator) { registry.safeTransferByOperator(_prevOwner, _boardCreator, tokenId_); return; } @@ -200,14 +200,14 @@ contract Billboard is IBillboard { IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); // create new auction and new bid if no next auction - if (_nextAuction.tokenId == 0) { + if (_nextAuction.startAt == 0) { _newAuctionAndBid(tokenId_, amount_); return; } // clear auction first if next auction is ended, then create new auction and new bid if (block.timestamp >= _nextAuction.endAt) { - this.clearAuction(tokenId_); + clearAuction(tokenId_); _newAuctionAndBid(tokenId_, amount_); return; } else { @@ -216,7 +216,10 @@ contract Billboard is IBillboard { revert BidAlreadyPlaced(); } - registry.newBid(tokenId_, _nextAuctionId, msg.sender, amount_, calculateTax(amount_)); + uint256 _tax = calculateTax(amount_); + registry.newBid(tokenId_, _nextAuctionId, msg.sender, amount_, _tax); + + _lockBidPriceAndTax(amount_ + _tax); } } @@ -224,7 +227,18 @@ contract Billboard is IBillboard { uint256 _startAt = block.timestamp; uint256 _endAt = block.timestamp + 14 days; uint256 _auctionId = registry.newAuction(tokenId_, _startAt, _endAt); - registry.newBid(tokenId_, _auctionId, msg.sender, amount_, calculateTax(amount_)); + uint256 _tax = calculateTax(amount_); + + registry.newBid(tokenId_, _auctionId, msg.sender, amount_, _tax); + + _lockBidPriceAndTax(amount_ + _tax); + } + + function _lockBidPriceAndTax(uint256 amount_) private { + (bool _success, ) = address(registry).call{value: amount_}(""); + if (!_success) { + revert TransferFailed(); + } } /// @inheritdoc IBillboard diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 48ad12b..425c31e 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -55,6 +55,9 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _; } + // Function to receive Ether. + receive() external payable {} + /// @inheritdoc IBillboardRegistry function setOperator(address operator_) external isFromOperator { operator = operator_; @@ -71,7 +74,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { _safeMint(to_, tokenId); - Board memory _newBoard = Board({ + boards[tokenId] = Board({ creator: to_, name: "", description: "", @@ -79,7 +82,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { contentURI: "", redirectURI: "" }); - boards[tokenId] = _newBoard; // TODO // emit Mint(newBoardId, to_); @@ -134,10 +136,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 startAt_, uint256 endAt_ ) external isFromOperator returns (uint256 newAuctionId) { - newAuctionId = nextBoardAuctionId[tokenId_]++; + nextBoardAuctionId[tokenId_]++; + + newAuctionId = nextBoardAuctionId[tokenId_]; - Auction({ - tokenId: tokenId_, + boardAuctions[tokenId_][newAuctionId] = Auction({ startAt: startAt_, endAt: endAt_, leaseStartAt: 0, @@ -179,7 +182,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { bidder: bidder_, price: price_, tax: tax_, - auctionId: auctionId_, placedAt: block.timestamp, isWithdrawn: false, isWon: false @@ -200,12 +202,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { if (highestBid.bidder == address(0) || price_ > highestBid.price) { boardAuctions[tokenId_][auctionId_].highestBidder = bidder_; } - - // lock ETH - (bool _success, ) = address(this).call{value: price_ + tax_}(""); - if (!_success) { - revert TransferFailed(); - } } /// @inheritdoc IBillboardRegistry diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index a0e6847..0117590 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -20,6 +20,8 @@ interface IBillboard { error WithdrawFailed(); + error TransferFailed(); + ////////////////////////////// /// Upgradability ////////////////////////////// diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index f30bad2..b64bb37 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -40,7 +40,6 @@ interface IBillboardRegistry is IERC721 { } struct Auction { - uint256 tokenId; uint256 startAt; // timestamp uint256 endAt; // timestamp uint256 leaseStartAt; // timestamp @@ -52,7 +51,6 @@ interface IBillboardRegistry is IERC721 { address bidder; uint256 price; uint256 tax; - uint256 auctionId; uint256 placedAt; // timestamp bool isWon; bool isWithdrawn; diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index b0d9e72..0f4bc3b 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -12,7 +12,7 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); // deploy new operator - Billboard newOperator = new Billboard(address(registry), TAX_RATE, "BLBD", "BLBD"); + Billboard newOperator = new Billboard(payable(registry), TAX_RATE, "BLBD", "BLBD"); assertEq(newOperator.admin(), ADMIN); // upgrade registry's operator @@ -98,7 +98,6 @@ contract BillboardTest is BillboardTestBase { // get board & check data IBillboardRegistry.Board memory board = operator.getBoard(1); assertEq(board.creator, ADMIN); - assertEq(board.auctionId, 0); assertEq(board.name, ""); assertEq(board.description, ""); assertEq(board.location, ""); @@ -121,6 +120,19 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.balanceOf(USER_A), 1); } + function testMintBoardByWhitelist() public { + vm.prank(USER_A); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + operator.mintBoard(USER_A); + + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); + + vm.prank(USER_A); + operator.mintBoard(USER_A); + assertEq(registry.balanceOf(USER_A), 1); + } + function testCannotMintBoardByAttacker() public { vm.startPrank(ATTACKER); @@ -217,7 +229,7 @@ contract BillboardTest is BillboardTestBase { registry.safeTransferFrom(USER_A, USER_B, 1); board = operator.getBoard(_tokenId); assertEq(board.creator, ADMIN); - assertEq(registry.ownerOf(1), USER_B); + assertEq(registry.ownerOf(_tokenId), USER_B); vm.stopPrank(); vm.startPrank(USER_B); @@ -305,7 +317,45 @@ contract BillboardTest is BillboardTestBase { /// Auction ////////////////////////////// - // function testBid() public {} + function testPlaceBid() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + vm.startPrank(ADMIN); + vm.deal(ADMIN, _total); + uint256 _prevBalance = ADMIN.balance; + + assertEq(registry.nextBoardAuctionId(_tokenId), 0); + operator.placeBid{value: _total}(_tokenId, _amount); + + // check balances + uint256 _afterBalance = ADMIN.balance; + assertEq(_afterBalance, _prevBalance - _total); + assertEq(address(operator).balance, 0); + assertEq(address(registry).balance, _total); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + + assertEq(_nextAuctionId, 1); + assertEq(_auction.startAt, block.timestamp); + assertEq(_auction.endAt, block.timestamp + 14 days); + assertEq(_auction.leaseStartAt, 0); + assertEq(_auction.leaseEndAt, 0); + assertEq(_auction.highestBidder, ADMIN); + + // check bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); + assertEq(_bid.bidder, ADMIN); + assertEq(_bid.price, _amount); + assertEq(_bid.tax, _tax); + assertEq(_bid.placedAt, block.timestamp); + assertEq(_bid.isWon, false); + assertEq(_bid.isWithdrawn, false); + } // function testClearAuction() public {} diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 89e97e2..964370f 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -30,7 +30,7 @@ contract BillboardTestBase is Test { vm.startPrank(ADMIN); // deploy operator & registry - operator = new Billboard(address(0), TAX_RATE, "BLBD", "BLBD"); + operator = new Billboard(payable(address(0)), TAX_RATE, "BLBD", "BLBD"); registry = operator.registry(); assertEq(operator.admin(), ADMIN); assertEq(registry.operator(), address(operator)); From 7c224262b3915bc5350a2b9af5f8828cc3cd6eb2 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 16 Nov 2023 20:46:21 +0800 Subject: [PATCH 32/55] feat(billboard): add more tests for placeBid --- src/Billboard/Billboard.sol | 2 +- src/Billboard/BillboardRegistry.sol | 11 +-- src/Billboard/IBillboardRegistry.sol | 1 - src/test/Billboard/BillboardTest.t.sol | 127 ++++++++++++++++++++++++- 4 files changed, 128 insertions(+), 13 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 17084cd..6432b25 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -212,7 +212,7 @@ contract Billboard is IBillboard { return; } else { // push new bid to next auction - if (registry.getBid(tokenId_, _nextAuctionId, msg.sender).bidder != address(0)) { + if (registry.getBid(tokenId_, _nextAuctionId, msg.sender).placedAt != 0) { revert BidAlreadyPlaced(); } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 425c31e..6ba16d1 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -178,14 +178,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 price_, uint256 tax_ ) external isFromOperator { - Bid memory _bid = Bid({ - bidder: bidder_, - price: price_, - tax: tax_, - placedAt: block.timestamp, - isWithdrawn: false, - isWon: false - }); + Bid memory _bid = Bid({price: price_, tax: tax_, placedAt: block.timestamp, isWithdrawn: false, isWon: false}); // add to auction bids auctionBids[tokenId_][auctionId_][bidder_] = _bid; @@ -199,7 +192,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // the highest bidder since the block.timestamp is always greater. address highestBidder = boardAuctions[tokenId_][auctionId_].highestBidder; Bid memory highestBid = auctionBids[tokenId_][auctionId_][highestBidder]; - if (highestBid.bidder == address(0) || price_ > highestBid.price) { + if (highestBidder == address(0) || price_ > highestBid.price) { boardAuctions[tokenId_][auctionId_].highestBidder = bidder_; } } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index b64bb37..7069c30 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -48,7 +48,6 @@ interface IBillboardRegistry is IERC721 { } struct Bid { - address bidder; uint256 price; uint256 tax; uint256 placedAt; // timestamp diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 0f4bc3b..585972b 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -339,7 +339,6 @@ contract BillboardTest is BillboardTestBase { // check auction uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_nextAuctionId, 1); assertEq(_auction.startAt, block.timestamp); assertEq(_auction.endAt, block.timestamp + 14 days); @@ -349,7 +348,6 @@ contract BillboardTest is BillboardTestBase { // check bid IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); - assertEq(_bid.bidder, ADMIN); assertEq(_bid.price, _amount); assertEq(_bid.tax, _tax); assertEq(_bid.placedAt, block.timestamp); @@ -357,6 +355,131 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.isWithdrawn, false); } + function testPlaceBidWithSamePrice() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // bid with ADMIN + vm.startPrank(ADMIN); + vm.deal(ADMIN, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, ADMIN); + + // add USER_A to whitelist + operator.addToWhitelist(USER_A); + + // bid with USER_A + vm.startPrank(USER_A); + vm.deal(USER_A, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, ADMIN); + + // check if USER_A's bid exists + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bid.placedAt, block.timestamp); + + // check registry balance + assertEq(address(registry).balance, _total * 2); + } + + function testPlaceBidWithHigherPrice() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // bid with ADMIN + vm.startPrank(ADMIN); + vm.deal(ADMIN, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, ADMIN); + + // add USER_A to whitelist + operator.addToWhitelist(USER_A); + + // bid with USER_A + vm.startPrank(USER_A); + vm.deal(USER_A, _total * 2); + operator.placeBid{value: _total * 2}(_tokenId, _amount * 2); + _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, USER_A); + } + + function testPlaceBidZeroPrice() public { + uint256 _tokenId = _mintBoard(); + + vm.startPrank(ADMIN); + vm.deal(ADMIN, 1 ether); + uint256 _prevBalance = ADMIN.balance; + + operator.placeBid{value: 0}(_tokenId, 0); + + // check balances + uint256 _afterBalance = ADMIN.balance; + assertEq(_afterBalance, _prevBalance); + assertEq(address(operator).balance, 0); + assertEq(address(registry).balance, 0); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, ADMIN); + + // check bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); + assertEq(_bid.placedAt, block.timestamp); + } + + function testPlaceBidByWhitelist() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); + + vm.deal(USER_A, _total); + vm.prank(USER_A); + operator.placeBid{value: _total}(_tokenId, _amount); + assertEq(USER_A.balance, 0); + } + + function testCannotPlaceBidTwice() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + vm.startPrank(ADMIN); + vm.deal(ADMIN, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + assertEq(ADMIN.balance, 0); + + vm.deal(ADMIN, _total); + vm.expectRevert(abi.encodeWithSignature("BidAlreadyPlaced()")); + operator.placeBid{value: _total}(_tokenId, _amount); + } + + function testCannotPlaceBidByAttacker() public { + uint256 _tokenId = _mintBoard(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + vm.startPrank(ATTACKER); + vm.deal(ATTACKER, _total); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + operator.placeBid{value: _total}(_tokenId, _amount); + } + // function testClearAuction() public {} // function testBidByAttacker() public {} From 4fda8b62a8c9742d446958e84a0c9b8115122677 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:24:03 +0800 Subject: [PATCH 33/55] feat(billboard): add tests for clearAuction --- src/Billboard/Billboard.sol | 50 ++++-- src/Billboard/BillboardRegistry.sol | 1 + src/test/Billboard/BillboardTest.t.sol | 188 +++++++++++++++------ src/test/Billboard/BillboardTestBase.t.sol | 17 ++ 4 files changed, 185 insertions(+), 71 deletions(-) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 6432b25..787c27d 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -165,30 +165,37 @@ contract Billboard is IBillboard { return; } + _clearAuction(tokenId_, _boardCreator, _nextAuctionId); + } + + function _clearAuction(uint256 tokenId_, address boardCreator_, uint256 nextAuctionId_) private { + IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, nextAuctionId_); IBillboardRegistry.Bid memory _highestBid = registry.getBid( tokenId_, - _nextAuctionId, + nextAuctionId_, _nextAuction.highestBidder ); + + address _prevOwner = registry.ownerOf(tokenId_); if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) registry.transferAmount(_prevOwner, _highestBid.price); // transfer bid tax to board creator's tax treasury - (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(_boardCreator); - registry.setTaxTreasury(_boardCreator, _taxAccumulated + _highestBid.tax, _taxWithdrawn); + (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(boardCreator_); + registry.setTaxTreasury(boardCreator_, _taxAccumulated + _highestBid.tax, _taxWithdrawn); } // transfer ownership registry.safeTransferByOperator(_prevOwner, _nextAuction.highestBidder, tokenId_); // mark highest bid as won - registry.setBidWon(tokenId_, _nextAuctionId, _nextAuction.highestBidder, true); + registry.setBidWon(tokenId_, nextAuctionId_, _nextAuction.highestBidder, true); // set auction lease uint256 leaseStartAt = block.timestamp; - uint256 leaseEndAt = block.timestamp + 14 days; - registry.setAuctionLease(tokenId_, _nextAuctionId, leaseStartAt, leaseEndAt); + uint256 leaseEndAt = leaseStartAt + registry.leaseTerm(); + registry.setAuctionLease(tokenId_, nextAuctionId_, leaseStartAt, leaseEndAt); } /// @inheritdoc IBillboard @@ -199,19 +206,26 @@ contract Billboard is IBillboard { uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); - // create new auction and new bid if no next auction + // if it's a new board without next auction, + // create new auction and new bid first, + // then clear auction and transfer ownership to the bidder immediately. if (_nextAuction.startAt == 0) { - _newAuctionAndBid(tokenId_, amount_); + uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, block.timestamp); + _clearAuction(tokenId_, _boardCreator, _auctionId); return; } - // clear auction first if next auction is ended, then create new auction and new bid + // if next auction is ended, + // clear auction first, + // then create new auction and new bid if (block.timestamp >= _nextAuction.endAt) { - clearAuction(tokenId_); - _newAuctionAndBid(tokenId_, amount_); + _clearAuction(tokenId_, _boardCreator, _nextAuctionId); + _newAuctionAndBid(tokenId_, amount_, block.timestamp + registry.leaseTerm()); return; - } else { - // push new bid to next auction + } + // if next auction is not ended, + // push new bid to next auction + else { if (registry.getBid(tokenId_, _nextAuctionId, msg.sender).placedAt != 0) { revert BidAlreadyPlaced(); } @@ -223,13 +237,13 @@ contract Billboard is IBillboard { } } - function _newAuctionAndBid(uint256 tokenId_, uint256 amount_) private { + function _newAuctionAndBid(uint256 tokenId_, uint256 amount_, uint256 endAt_) private returns (uint256 auctionId) { uint256 _startAt = block.timestamp; - uint256 _endAt = block.timestamp + 14 days; - uint256 _auctionId = registry.newAuction(tokenId_, _startAt, _endAt); uint256 _tax = calculateTax(amount_); - registry.newBid(tokenId_, _auctionId, msg.sender, amount_, _tax); + auctionId = registry.newAuction(tokenId_, _startAt, endAt_); + + registry.newBid(tokenId_, auctionId, msg.sender, amount_, _tax); _lockBidPriceAndTax(amount_ + _tax); } @@ -295,7 +309,7 @@ contract Billboard is IBillboard { } function calculateTax(uint256 amount_) public view returns (uint256 tax) { - return (amount_ * registry.taxRate()) / 100; + return amount_ * (registry.taxRate() / 100) * registry.leaseTerm(); } /// @inheritdoc IBillboard diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 6ba16d1..8c7ebbe 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -15,6 +15,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { Counters.Counter private _tokenIds; uint256 public taxRate; + uint256 public leaseTerm = 14 days; // tokenId => Board mapping(uint256 => Board) public boards; diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 585972b..0b081a8 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -304,7 +304,7 @@ contract BillboardTest is BillboardTestBase { assertEq(board.creator, ADMIN); } - function testApproveByAttacker() public { + function testCannotApproveByAttacker() public { uint256 _tokenId = _mintBoard(); vm.stopPrank(); @@ -317,99 +317,107 @@ contract BillboardTest is BillboardTestBase { /// Auction ////////////////////////////// - function testPlaceBid() public { + function testPlaceBidOnNewBoard() public { + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); + uint256 _tokenId = _mintBoard(); uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; + vm.deal(USER_A, _total); - vm.startPrank(ADMIN); - vm.deal(ADMIN, _total); - uint256 _prevBalance = ADMIN.balance; + uint256 _prevNextActionId = registry.nextBoardAuctionId(_tokenId); + uint256 _prevCreatorBalance = ADMIN.balance; + uint256 _prevBidderBalance = USER_A.balance; + uint256 _prevOperatorBalance = address(operator).balance; + uint256 _prevRegistryBalance = address(registry).balance; - assertEq(registry.nextBoardAuctionId(_tokenId), 0); + vm.prank(USER_A); operator.placeBid{value: _total}(_tokenId, _amount); // check balances - uint256 _afterBalance = ADMIN.balance; - assertEq(_afterBalance, _prevBalance - _total); - assertEq(address(operator).balance, 0); - assertEq(address(registry).balance, _total); + assertEq(ADMIN.balance, _prevCreatorBalance + _amount); + assertEq(USER_A.balance, _prevBidderBalance - _total); + assertEq(address(operator).balance, _prevOperatorBalance); + assertEq(address(registry).balance, _prevRegistryBalance + _tax); // check auction uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_nextAuctionId, 1); + assertEq(_prevNextActionId, 0); + assertEq(_nextAuctionId, _prevNextActionId + 1); assertEq(_auction.startAt, block.timestamp); - assertEq(_auction.endAt, block.timestamp + 14 days); - assertEq(_auction.leaseStartAt, 0); - assertEq(_auction.leaseEndAt, 0); - assertEq(_auction.highestBidder, ADMIN); + assertEq(_auction.endAt, block.timestamp); + assertEq(_auction.leaseStartAt, block.timestamp); + assertEq(_auction.leaseEndAt, block.timestamp + registry.leaseTerm()); + assertEq(_auction.highestBidder, USER_A); // check bid - IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); assertEq(_bid.price, _amount); assertEq(_bid.tax, _tax); assertEq(_bid.placedAt, block.timestamp); - assertEq(_bid.isWon, false); + assertEq(_bid.isWon, true); assertEq(_bid.isWithdrawn, false); } function testPlaceBidWithSamePrice() public { - uint256 _tokenId = _mintBoard(); + (uint256 _tokenId, uint256 _prevNextAuctionId) = _mintBoardAndPlaceBid(); uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; - // bid with ADMIN - vm.startPrank(ADMIN); - vm.deal(ADMIN, _total); + // new auction and new bid with USER_A + vm.deal(USER_A, _total); + vm.prank(USER_A); operator.placeBid{value: _total}(_tokenId, _amount); uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + assertEq(_nextAuctionId, _prevNextAuctionId + 1); IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_auction.highestBidder, ADMIN); - - // add USER_A to whitelist - operator.addToWhitelist(USER_A); + assertEq(_auction.highestBidder, USER_A); - // bid with USER_A - vm.startPrank(USER_A); - vm.deal(USER_A, _total); + // new bid with USER_B + vm.deal(USER_B, _total); + vm.prank(USER_B); operator.placeBid{value: _total}(_tokenId, _amount); + _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + assertEq(_nextAuctionId, _prevNextAuctionId + 1); // still the same auction _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_auction.highestBidder, ADMIN); + assertEq(_auction.highestBidder, USER_A); // USER_A is still the same highest bidder - // check if USER_A's bid exists - IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); - assertEq(_bid.placedAt, block.timestamp); + // check if bids exist + IBillboardRegistry.Bid memory _bidA = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bidA.placedAt, block.timestamp); + assertEq(_bidA.isWon, false); + IBillboardRegistry.Bid memory _bidB = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bidB.placedAt, block.timestamp); + assertEq(_bidB.isWon, false); // check registry balance assertEq(address(registry).balance, _total * 2); } function testPlaceBidWithHigherPrice() public { - uint256 _tokenId = _mintBoard(); + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; - // bid with ADMIN - vm.startPrank(ADMIN); - vm.deal(ADMIN, _total); + // bid with USER_A + vm.deal(USER_A, _total); + vm.prank(USER_A); operator.placeBid{value: _total}(_tokenId, _amount); uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_auction.highestBidder, ADMIN); - - // add USER_A to whitelist - operator.addToWhitelist(USER_A); + assertEq(_auction.highestBidder, USER_A); - // bid with USER_A - vm.startPrank(USER_A); - vm.deal(USER_A, _total * 2); + // bid with USER_B + vm.startPrank(USER_B); + vm.deal(USER_B, _total * 2); operator.placeBid{value: _total * 2}(_tokenId, _amount * 2); _auction = registry.getAuction(_tokenId, _nextAuctionId); - assertEq(_auction.highestBidder, USER_A); + assertEq(_auction.highestBidder, USER_B); } function testPlaceBidZeroPrice() public { @@ -435,6 +443,7 @@ contract BillboardTest is BillboardTestBase { // check bid IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); assertEq(_bid.placedAt, block.timestamp); + assertEq(_bid.isWon, true); } function testPlaceBidByWhitelist() public { @@ -452,18 +461,59 @@ contract BillboardTest is BillboardTestBase { assertEq(USER_A.balance, 0); } + function testPlaceBidIfAuctionEnded() public { + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _amount = 1 ether; + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // place a bid with USER_A + vm.startPrank(USER_A); + vm.deal(USER_A, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, USER_A); + assertEq(_auction.endAt, block.timestamp + registry.leaseTerm()); + + // make auction ended + vm.warp(_auction.endAt + 1 seconds); + + // place a bid with USER_B + vm.startPrank(USER_B); + vm.deal(USER_B, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + + // check auction + uint256 _newNextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _newAuction = registry.getAuction(_tokenId, _newNextAuctionId); + assertEq(_newNextAuctionId, _nextAuctionId + 1); + assertEq(_newAuction.highestBidder, USER_B); + assertEq(_newAuction.endAt, block.timestamp + registry.leaseTerm()); + + // USER_A won the previous auction + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bid.isWon, true); + + // USER_B's bid is still in a running auction + IBillboardRegistry.Bid memory _newBid = registry.getBid(_tokenId, _newNextAuctionId, USER_B); + assertEq(_newBid.isWon, false); + } + function testCannotPlaceBidTwice() public { - uint256 _tokenId = _mintBoard(); + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; - vm.startPrank(ADMIN); - vm.deal(ADMIN, _total); + vm.startPrank(USER_A); + vm.deal(USER_A, _total); operator.placeBid{value: _total}(_tokenId, _amount); - assertEq(ADMIN.balance, 0); + assertEq(USER_A.balance, 0); - vm.deal(ADMIN, _total); + vm.deal(USER_A, _total); vm.expectRevert(abi.encodeWithSignature("BidAlreadyPlaced()")); operator.placeBid{value: _total}(_tokenId, _amount); } @@ -480,11 +530,35 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _total}(_tokenId, _amount); } - // function testClearAuction() public {} + function testCannotClearAuctionOnNewBoard() public { + uint256 _mintedAt = block.timestamp; + uint256 _clearedAt = _mintedAt + 1; + uint256 _tokenId = _mintBoard(); + + vm.startPrank(ADMIN); + + // clear auction + vm.warp(_clearedAt); + vm.expectRevert(abi.encodeWithSignature("AuctionNotFound()")); + operator.clearAuction(_tokenId); + } + + function testCannotClearAuctionIfAuctionNotEnded() public { + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + + // place a bid + vm.startPrank(USER_A); + vm.deal(USER_A, 0); + operator.placeBid{value: 0}(_tokenId, 0); - // function testBidByAttacker() public {} + // try to clear auction + vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + operator.clearAuction(_tokenId); - // function testClearAuctionByAttacker() public {} + vm.warp(block.timestamp + registry.leaseTerm() - 1 seconds); + vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + operator.clearAuction(_tokenId); + } ////////////////////////////// /// Tax & Withdraw @@ -497,10 +571,18 @@ contract BillboardTest is BillboardTestBase { assertEq(operator.getTaxRate(), 2); } - function testSetTaxRateByAttacker() public { + function testCannotSetTaxRateByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); operator.setTaxRate(2); } + + function testWithdrawTax() public {} + + function testCannotWithdrawTaxByAttacker() public {} + + function testWithdrawBid() public {} + + function testCannotWithdrawBidByAttacker() public {} } diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 964370f..7e2dfe1 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -43,4 +43,21 @@ contract BillboardTestBase is Test { tokenId = operator.mintBoard(ADMIN); assertEq(registry.balanceOf(ADMIN), 1); } + + function _mintBoardAndPlaceBid() public returns (uint256 tokenId, uint256 _nextAuctionId) { + tokenId = _mintBoard(); + + // (new board) ADMIN places first bid and takes the ownership + vm.startPrank(ADMIN); + operator.placeBid{value: 0}(tokenId, 0); + _nextAuctionId = registry.nextBoardAuctionId(tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId, _nextAuctionId); + assertEq(_nextAuctionId, 1); + assertEq(_auction.highestBidder, ADMIN); + + // add USER_A and USER_B to whitelist + operator.addToWhitelist(USER_A); + operator.addToWhitelist(USER_B); + vm.stopPrank(); + } } From 882b9ba2b8facf460226c3f1e41e809386ac0cf7 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 17 Nov 2023 17:27:49 +0800 Subject: [PATCH 34/55] feat(billboard): add fuzz tests --- .gas-snapshot | 175 ++- .husky/pre-commit | 4 +- package-lock.json | 1480 ++++++++++++++++++++++-- package.json | 2 +- src/test/Billboard/BillboardTest.t.sol | 64 +- 5 files changed, 1555 insertions(+), 170 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index cdac718..65da3ae 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -1,23 +1,152 @@ -BillboardTest:testAddToWhitelist() (gas: 102721) -BillboardTest:testAddToWhitelistByAttacker() (gas: 11980) -BillboardTest:testApprove() (gas: 196706) -BillboardTest:testApproveByAttacker() (gas: 167482) -BillboardTest:testBid() (gas: 188) -BillboardTest:testBidByAttacker() (gas: 166) -BillboardTest:testClearAuction() (gas: 188) -BillboardTest:testClearAuctionByAttacker() (gas: 167) -BillboardTest:testGetTokenURI() (gas: 190476) -BillboardTest:testMintBoard() (gas: 284718) -BillboardTest:testMintBoardByAttacker() (gas: 21681) -BillboardTest:testRemoveToWhitelist() (gas: 72724) -BillboardTest:testRemoveToWhitelistByAttacker() (gas: 11981) -BillboardTest:testSetBoardProperties() (gas: 302887) -BillboardTest:testSetBoardProprtiesByAttacker() (gas: 186054) -BillboardTest:testSetIsOpened() (gas: 47920) -BillboardTest:testSetIsOpenedByAttacker() (gas: 11940) -BillboardTest:testSetTaxRate() (gas: 27363) -BillboardTest:testSetTaxRateByAttacker() (gas: 11992) -BillboardTest:testTransfer() (gas: 411852) -BillboardTest:testTransferByAttacker() (gas: 192057) -BillboardTest:testUpgradeAuctionByAttacker() (gas: 13636) -BillboardTest:testUpgradeRegistryByAttacker() (gas: 13635) \ No newline at end of file +ACLManagerTest:testCannotGrantACLManagerRole() (gas: 12206) +ACLManagerTest:testCannotGrantRoleByNonACLManager() (gas: 17353) +ACLManagerTest:testCannotGrantRoleToZeroAddress() (gas: 12195) +ACLManagerTest:testCannotRenounceRoleByACLManager() (gas: 12056) +ACLManagerTest:testCannotRenounceRoleByAttacker() (gas: 12346) +ACLManagerTest:testCannotTransferRoleByAttacker() (gas: 12473) +ACLManagerTest:testCannotTransferRoleToZeroAddress() (gas: 12193) +ACLManagerTest:testGrantRole() (gas: 23547) +ACLManagerTest:testRenounceRole() (gas: 27841) +ACLManagerTest:testRoles() (gas: 15393) +ACLManagerTest:testTransferRole() (gas: 21528) +BillboardTest:testAddToWhitelist() (gas: 37314) +BillboardTest:testApproveAndTransfer() (gas: 157829) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11772) +BillboardTest:testCannotApproveByAttacker() (gas: 131382) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 679059) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139133) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13960) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145191) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 709756, ~: 712100) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129339) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162160) +BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) +BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) +BillboardTest:testCannotTransferByOperator() (gas: 133860) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129414) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11971) +BillboardTest:testCannotWithdrawBidByAttacker() (gas: 188) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 252) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 752876) +BillboardTest:testGetTokenURI() (gas: 154193) +BillboardTest:testMintBoard() (gas: 220013) +BillboardTest:testMintBoardByWhitelist() (gas: 157589) +BillboardTest:testMintBoardIfOpened() (gas: 130603) +BillboardTest:testPlaceBidByWhitelist() (gas: 493304) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1005279) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 500763, ~: 503713) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 802701, ~: 802701) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 803985, ~: 807888) +BillboardTest:testPlaceBidZeroPrice() (gas: 418787) +BillboardTest:testRemoveToWhitelist() (gas: 24992) +BillboardTest:testSafeTransferByOperator() (gas: 140039) +BillboardTest:testSetBoardProperties() (gas: 284970) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 328878) +BillboardTest:testSetIsOpened() (gas: 15932) +BillboardTest:testSetTaxRate() (gas: 24803) +BillboardTest:testUpgradeRegistry() (gas: 2390816) +BillboardTest:testWithdrawBid() (gas: 274) +BillboardTest:testWithdrawTax() (gas: 232) +CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) +CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) +CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) +CurationTest:testCannotCurateERC20SelfCuration() (gas: 16031) +CurationTest:testCannotCurateERC20ZeroAddress() (gas: 15899) +CurationTest:testCannotCurateNativeTokenCurateZeroAmount() (gas: 9958) +CurationTest:testCannotCurateNativeTokenEmptyURI() (gas: 16468) +CurationTest:testCannotCurateNativeTokenSelfCuration() (gas: 16713) +CurationTest:testCannotCurateNativeTokenToContractRejector() (gas: 28554) +CurationTest:testCannotCurateNativeTokenZeroAddress() (gas: 16488) +CurationTest:testERC20Curation() (gas: 59908) +CurationTest:testNativeTokenCuration() (gas: 60085) +CurationTest:testNativeTokenCurationToContractAcceptor() (gas: 37466) +LogbookNFTSVGTest:testTokenURI(uint8,uint8,uint16) (runs: 256, μ: 2019505, ~: 1310779) +LogbookTest:testClaim() (gas: 135608) +LogbookTest:testDonate(uint96) (runs: 256, μ: 155485, ~: 156936) +LogbookTest:testDonateWithCommission(uint96,uint96) (runs: 256, μ: 150402, ~: 140444) +LogbookTest:testFork(uint96,string) (runs: 256, μ: 450748, ~: 453928) +LogbookTest:testForkRecursively(uint8,uint96) (runs: 256, μ: 4613856, ~: 1014389) +LogbookTest:testForkWithCommission(uint96,string,uint256) (runs: 256, μ: 469806, ~: 257636) +LogbookTest:testMulticall() (gas: 284999) +LogbookTest:testPublicSale() (gas: 204837) +LogbookTest:testPublish(string) (runs: 256, μ: 264065, ~: 263590) +LogbookTest:testPublishEn1000() (gas: 243477) +LogbookTest:testPublishEn140() (gas: 221241) +LogbookTest:testPublishEn200() (gas: 222826) +LogbookTest:testPublishEn2000() (gas: 270020) +LogbookTest:testPublishEn300() (gas: 225284) +LogbookTest:testPublishEn50() (gas: 218722) +LogbookTest:testPublishEn500() (gas: 230268) +LogbookTest:testPublishEn5000() (gas: 348496) +LogbookTest:testPublishZh100() (gas: 224502) +LogbookTest:testPublishZh20() (gas: 218704) +LogbookTest:testPublishZh200() (gas: 231104) +LogbookTest:testPublishZh2000() (gas: 371155) +LogbookTest:testPublishZh50() (gas: 221152) +LogbookTest:testPublishZh500() (gas: 250956) +LogbookTest:testPublishZh5000() (gas: 607690) +LogbookTest:testSetDescription() (gas: 140760) +LogbookTest:testSetForkPrice() (gas: 153925) +LogbookTest:testSetTitle() (gas: 168680) +LogbookTest:testSplitRoyalty(uint8,uint8,uint96) (runs: 256, μ: 2012966, ~: 636792) +LogbookTest:testWithdraw() (gas: 7284400) +SnapperTest:testCannotInitRegionByNotOwner() (gas: 11365) +SnapperTest:testCannotReInitRegion() (gas: 14373) +SnapperTest:testCannotTakeSnapshotBeforeInit() (gas: 15717) +SnapperTest:testCannotTakeSnapshotByNotOwner() (gas: 12478) +SnapperTest:testCannotTakeSnapshotWrongLastBlock() (gas: 49242) +SnapperTest:testCannotTakeSnapshotWrongSnapshotBlock() (gas: 23899) +SnapperTest:testInitRegion(uint256) (runs: 256, μ: 114408, ~: 114408) +SnapperTest:testTakeSnapshot() (gas: 47831) +TheSpaceTest:testBatchBid() (gas: 690308) +TheSpaceTest:testBatchSetPixels(uint16,uint8) (runs: 256, μ: 368725, ~: 370338) +TheSpaceTest:testBidDefaultedToken() (gas: 409416) +TheSpaceTest:testBidExistingToken() (gas: 355023) +TheSpaceTest:testBidNewToken() (gas: 301184) +TheSpaceTest:testCanTransferFromIfSettleTax() (gas: 355069) +TheSpaceTest:testCannotBidExceedAllowance() (gas: 60910) +TheSpaceTest:testCannotBidOutBoundTokens() (gas: 260482) +TheSpaceTest:testCannotBidPriceTooLow() (gas: 341674) +TheSpaceTest:testCannotGetTaxWithNonExistingToken() (gas: 16401) +TheSpaceTest:testCannotGetTokenURIInLogicContract() (gas: 298473) +TheSpaceTest:testCannotSetColorByAttacker() (gas: 302848) +TheSpaceTest:testCannotSetConfigByAttacker() (gas: 12053) +TheSpaceTest:testCannotSetPixel(uint256) (runs: 256, μ: 312357, ~: 312357) +TheSpaceTest:testCannotSetPriceByNonOwner() (gas: 302924) +TheSpaceTest:testCannotSetTokenImageURIByNonACLManager() (gas: 11862) +TheSpaceTest:testCannotSetTotalSupplyByAttacker() (gas: 11858) +TheSpaceTest:testCannotTransferFromIfDefault() (gas: 394147) +TheSpaceTest:testCannotUpgradeByAttacker() (gas: 11539) +TheSpaceTest:testCollectableTax() (gas: 333364) +TheSpaceTest:testDefault() (gas: 390575) +TheSpaceTest:testGetConfig() (gas: 14302) +TheSpaceTest:testGetExistingPixel() (gas: 309428) +TheSpaceTest:testGetNonExistingPixel() (gas: 60258) +TheSpaceTest:testGetNonExistingPrice() (gas: 19529) +TheSpaceTest:testGetOwner() (gas: 346931) +TheSpaceTest:testGetOwnerOfNonExistingToken() (gas: 13346) +TheSpaceTest:testGetPixelsByOwnerWithNoPixels() (gas: 24283) +TheSpaceTest:testGetPixelsByOwnerWithOnePixel() (gas: 319322) +TheSpaceTest:testGetPixelsPageByOwnerWithPixels() (gas: 585976) +TheSpaceTest:testGetPrice() (gas: 298001) +TheSpaceTest:testGetTax() (gas: 375416) +TheSpaceTest:testGetTokenImageURI() (gas: 14307) +TheSpaceTest:testGetTokenURI() (gas: 330962) +TheSpaceTest:testSetColor() (gas: 328848) +TheSpaceTest:testSetMintTax() (gas: 269237) +TheSpaceTest:testSetPixel(uint256) (runs: 256, μ: 398816, ~: 398816) +TheSpaceTest:testSetPrice(uint256) (runs: 256, μ: 302152, ~: 302152) +TheSpaceTest:testSetPriceByOperator(uint256) (runs: 256, μ: 352105, ~: 352105) +TheSpaceTest:testSetPriceTooHigh() (gas: 312004) +TheSpaceTest:testSetTaxRate() (gas: 345451) +TheSpaceTest:testSetTokenImageURI() (gas: 353313) +TheSpaceTest:testSetTotalSupply(uint256) (runs: 256, μ: 349701, ~: 349708) +TheSpaceTest:testSetTreasuryShare() (gas: 381788) +TheSpaceTest:testSettleTax() (gas: 336965) +TheSpaceTest:testTaxCalculation() (gas: 397405) +TheSpaceTest:testTokenShouldBeDefaulted() (gas: 323029) +TheSpaceTest:testTotalSupply() (gas: 7613) +TheSpaceTest:testUpgradeTo() (gas: 3215197) +TheSpaceTest:testWithdrawTreasury() (gas: 352672) +TheSpaceTest:testWithdrawUBI() (gas: 375819) \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index dc41503..8ebc7dd 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -npx lint-staged - -# && make snapshot && git add .gas-snapshot \ No newline at end of file +npx lint-staged && make snapshot && git add .gas-snapshot \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3e05b0f..72a65af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ }, "devDependencies": { "@types/node": "^20.9.0", - "ethers": "^6.8.1", + "ethers": "^5.6.1", "husky": "^8.0.3", "lint-staged": "^15.1.0", "prettier": "^3.0.3", @@ -24,12 +24,6 @@ "solidity-docgen": "^0.5.17" } }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", - "dev": true - }, "node_modules/@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -172,22 +166,723 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -215,30 +910,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1101,9 +1772,9 @@ } }, "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", "dev": true }, "node_modules/ajv": { @@ -1230,6 +1901,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1252,6 +1935,12 @@ "node": ">=8" } }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -1635,6 +2324,27 @@ "node": ">=0.10.0" } }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -1676,14 +2386,14 @@ } }, "node_modules/ethers": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.1.tgz", - "integrity": "sha512-iEKm6zox5h1lDn6scuRWdIdFJUCGg3+/aQWu0F4K0GVyEZiktFkqrJbRjTn1FlYEPz7RKA707D6g5Kdk6j7Ljg==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", "dev": true, "funding": [ { "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" }, { "type": "individual", @@ -1691,24 +2401,38 @@ } ], "dependencies": { - "@adraffy/ens-normalize": "1.10.0", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", - "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", - "ws": "8.5.0" - }, - "engines": { - "node": ">=14.0.0" + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" } }, - "node_modules/ethers/node_modules/@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", - "dev": true - }, "node_modules/eventemitter3": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", @@ -2018,6 +2742,27 @@ "node": ">=8" } }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -2587,6 +3332,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3154,6 +3911,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3889,12 +4652,6 @@ } } }, - "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, "node_modules/type-fest": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", @@ -4071,12 +4828,12 @@ "dev": true }, "node_modules/ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true, "engines": { - "node": ">=10.0.0" + "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", @@ -4117,12 +4874,6 @@ } }, "dependencies": { - "@adraffy/ens-normalize": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz", - "integrity": "sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==", - "dev": true - }, "@babel/code-frame": { "version": "7.22.13", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", @@ -4245,6 +4996,407 @@ "@jridgewell/trace-mapping": "0.3.9" } }, + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, "@jridgewell/resolve-uri": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", @@ -4267,21 +5419,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "dev": true, - "requires": { - "@noble/hashes": "1.3.2" - } - }, - "@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "dev": true - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4947,9 +6084,9 @@ "dev": true }, "aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", "dev": true }, "ajv": { @@ -5045,6 +6182,18 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "dev": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5064,6 +6213,12 @@ "fill-range": "^7.0.1" } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true + }, "cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -5338,6 +6493,29 @@ "jake": "^10.8.5" } }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -5366,26 +6544,41 @@ "dev": true }, "ethers": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.8.1.tgz", - "integrity": "sha512-iEKm6zox5h1lDn6scuRWdIdFJUCGg3+/aQWu0F4K0GVyEZiktFkqrJbRjTn1FlYEPz7RKA707D6g5Kdk6j7Ljg==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", "dev": true, "requires": { - "@adraffy/ens-normalize": "1.10.0", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "18.15.13", - "aes-js": "4.0.0-beta.5", - "tslib": "2.4.0", - "ws": "8.5.0" - }, - "dependencies": { - "@types/node": { - "version": "18.15.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", - "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==", - "dev": true - } + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" } }, "eventemitter3": { @@ -5619,6 +6812,27 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -6036,6 +7250,18 @@ "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", "dev": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true + }, "minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -6409,6 +7635,12 @@ "queue-microtask": "^1.2.2" } }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -6949,12 +8181,6 @@ "yn": "3.1.1" } }, - "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", - "dev": true - }, "type-fest": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", @@ -7084,9 +8310,9 @@ "dev": true }, "ws": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 8c726d8..2805079 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ }, "devDependencies": { "@types/node": "^20.9.0", - "ethers": "^6.8.1", + "ethers": "^5.6.1", "husky": "^8.0.3", "lint-staged": "^15.1.0", "prettier": "^3.0.3", diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 0b081a8..0b7f226 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -21,7 +21,7 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.operator(), address(newOperator)); } - function testUpgradeRegistryByAttacker() public { + function testCannotUpgradeRegistryByAttacker() public { vm.startPrank(ATTACKER); vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); @@ -189,7 +189,7 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.tokenURI(_tokenId), "new uri"); } - function testTransfer() public { + function testSetBoardPropertiesAfterTransfer() public { // mint uint256 _tokenId = _mintBoard(); @@ -272,7 +272,7 @@ contract BillboardTest is BillboardTestBase { registry.transferFrom(USER_B, USER_C, _tokenId); } - function testTransferByOperator() public { + function testSafeTransferByOperator() public { uint256 _tokenId = _mintBoard(); vm.startPrank(address(operator)); @@ -280,16 +280,16 @@ contract BillboardTest is BillboardTestBase { assertEq(registry.ownerOf(_tokenId), USER_A); } - function testCannotTransferByAttacker() public { + function testCannotSafeTransferByAttacker() public { uint256 _tokenId = _mintBoard(); vm.startPrank(ATTACKER); - vm.expectRevert("ERC721: caller is not token owner or approved"); - registry.transferFrom(ADMIN, ATTACKER, _tokenId); + vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + registry.safeTransferByOperator(ADMIN, ATTACKER, _tokenId); } - function testApprove() public { + function testApproveAndTransfer() public { uint256 _tokenId = _mintBoard(); vm.startPrank(ADMIN); @@ -317,12 +317,11 @@ contract BillboardTest is BillboardTestBase { /// Auction ////////////////////////////// - function testPlaceBidOnNewBoard() public { + function testPlaceBidOnNewBoard(uint96 _amount) public { vm.prank(ADMIN); operator.addToWhitelist(USER_A); uint256 _tokenId = _mintBoard(); - uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; vm.deal(USER_A, _total); @@ -362,9 +361,8 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.isWithdrawn, false); } - function testPlaceBidWithSamePrice() public { + function testPlaceBidWithSamePrices(uint96 _amount) public { (uint256 _tokenId, uint256 _prevNextAuctionId) = _mintBoardAndPlaceBid(); - uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; @@ -398,9 +396,11 @@ contract BillboardTest is BillboardTestBase { assertEq(address(registry).balance, _total * 2); } - function testPlaceBidWithHigherPrice() public { + function testPlaceBidWithHigherPrice(uint96 _amount) public { + vm.assume(_amount > 0); + vm.assume(_amount < type(uint96).max / 2); + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); - uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; @@ -424,7 +424,6 @@ contract BillboardTest is BillboardTestBase { uint256 _tokenId = _mintBoard(); vm.startPrank(ADMIN); - vm.deal(ADMIN, 1 ether); uint256 _prevBalance = ADMIN.balance; operator.placeBid{value: 0}(_tokenId, 0); @@ -502,9 +501,8 @@ contract BillboardTest is BillboardTestBase { assertEq(_newBid.isWon, false); } - function testCannotPlaceBidTwice() public { + function testCannotPlaceBidTwice(uint96 _amount) public { (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); - uint256 _amount = 1 ether; uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; @@ -530,6 +528,38 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _total}(_tokenId, _amount); } + function testClearAuctionIfAuctionEnded() public { + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _placedAt = block.timestamp; + uint256 _clearedAt = block.timestamp + registry.leaseTerm() + 1 minutes; + + // place a bid + vm.startPrank(USER_A); + vm.deal(USER_A, 0); + operator.placeBid{value: 0}(_tokenId, 0); + + // clear auction + vm.warp(_clearedAt); + operator.clearAuction(_tokenId); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.startAt, _placedAt); + assertEq(_auction.endAt, _placedAt + registry.leaseTerm()); + assertEq(_auction.leaseStartAt, _clearedAt); + assertEq(_auction.leaseEndAt, _clearedAt + registry.leaseTerm()); + assertEq(_auction.highestBidder, USER_A); + + // check bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bid.price, 0); + assertEq(_bid.tax, 0); + assertEq(_bid.placedAt, _placedAt); + assertEq(_bid.isWon, true); + assertEq(_bid.isWithdrawn, false); + } + function testCannotClearAuctionOnNewBoard() public { uint256 _mintedAt = block.timestamp; uint256 _clearedAt = _mintedAt + 1; @@ -560,6 +590,8 @@ contract BillboardTest is BillboardTestBase { operator.clearAuction(_tokenId); } + function getBids() public {} + ////////////////////////////// /// Tax & Withdraw ////////////////////////////// From 14fa0554913a58d59447b5a19ccb406f307b29fb Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 17 Nov 2023 21:50:41 +0800 Subject: [PATCH 35/55] feat(billboard): add more tests for withdraw --- .gas-snapshot | 67 +++--- src/Billboard/Billboard.sol | 18 +- src/Billboard/IBillboard.sol | 6 +- src/test/Billboard/BillboardTest.t.sol | 237 ++++++++++++++++++++- src/test/Billboard/BillboardTestBase.t.sol | 2 +- 5 files changed, 286 insertions(+), 44 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 65da3ae..b350ab5 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -9,45 +9,52 @@ ACLManagerTest:testGrantRole() (gas: 23547) ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) -BillboardTest:testAddToWhitelist() (gas: 37314) +BillboardTest:testAddToWhitelist() (gas: 37249) BillboardTest:testApproveAndTransfer() (gas: 157829) -BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11772) -BillboardTest:testCannotApproveByAttacker() (gas: 131382) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 679059) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139133) +BillboardTest:testCalculateTax() (gas: 210) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 483874, ~: 497559) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 449939) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11839) +BillboardTest:testCannotApproveByAttacker() (gas: 131427) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 679282) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139178) BillboardTest:testCannotMintBoardByAttacker() (gas: 13960) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145191) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 709756, ~: 712100) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145247) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 725916, ~: 732147) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129339) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129251) BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162160) -BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) +BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11796) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 133860) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129414) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11971) -BillboardTest:testCannotWithdrawBidByAttacker() (gas: 188) -BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 252) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 752876) -BillboardTest:testGetTokenURI() (gas: 154193) +BillboardTest:testCannotTransferByOperator() (gas: 133927) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129436) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11949) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1035780, ~: 1035780) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 842804, ~: 842804) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 721017, ~: 721017) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 480313) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 849293, ~: 849293) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 752944) +BillboardTest:testGetTokenURI() (gas: 154215) BillboardTest:testMintBoard() (gas: 220013) -BillboardTest:testMintBoardByWhitelist() (gas: 157589) -BillboardTest:testMintBoardIfOpened() (gas: 130603) -BillboardTest:testPlaceBidByWhitelist() (gas: 493304) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1005279) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 500763, ~: 503713) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 802701, ~: 802701) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 803985, ~: 807888) -BillboardTest:testPlaceBidZeroPrice() (gas: 418787) +BillboardTest:testMintBoardByWhitelist() (gas: 157567) +BillboardTest:testMintBoardIfOpened() (gas: 130581) +BillboardTest:testPlaceBidByWhitelist() (gas: 533304) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1065336) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 532879, ~: 543603) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 838439, ~: 845513) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 836369, ~: 848045) +BillboardTest:testPlaceBidZeroPrice() (gas: 418865) BillboardTest:testRemoveToWhitelist() (gas: 24992) BillboardTest:testSafeTransferByOperator() (gas: 140039) -BillboardTest:testSetBoardProperties() (gas: 284970) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 328878) +BillboardTest:testSetBoardProperties() (gas: 285015) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 328856) BillboardTest:testSetIsOpened() (gas: 15932) -BillboardTest:testSetTaxRate() (gas: 24803) -BillboardTest:testUpgradeRegistry() (gas: 2390816) -BillboardTest:testWithdrawBid() (gas: 274) -BillboardTest:testWithdrawTax() (gas: 232) +BillboardTest:testSetTaxRate() (gas: 24738) +BillboardTest:testUpgradeRegistry() (gas: 2471831) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1033494, ~: 1033494) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 566620, ~: 566620) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 787c27d..28f4eb1 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -309,7 +309,7 @@ contract Billboard is IBillboard { } function calculateTax(uint256 amount_) public view returns (uint256 tax) { - return amount_ * (registry.taxRate() / 100) * registry.leaseTerm(); + tax = (amount_ * registry.taxRate() * registry.leaseTerm()) / 1 days / 100; } /// @inheritdoc IBillboard @@ -318,7 +318,7 @@ contract Billboard is IBillboard { uint256 amount = _taxAccumulated - _taxWithdrawn; - if (amount <= 0) revert WithdrawFailed(); + if (amount <= 0) revert WithdrawFailed("zero amount"); // transfer tax to the owner registry.transferAmount(msg.sender, amount); @@ -329,12 +329,20 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { + // revert if auction is still running + IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId_, auctionId_); + if (block.timestamp < _auction.endAt) revert AuctionNotEnded(); + + // revert if auction is not cleared + if (_auction.leaseEndAt == 0) revert WithdrawFailed("auction not cleared"); + IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, auctionId_, msg.sender); uint256 amount = _bid.price + _bid.tax; - if (_bid.isWithdrawn) revert WithdrawFailed(); - if (_bid.isWon) revert WithdrawFailed(); - if (amount <= 0) revert WithdrawFailed(); + if (_bid.placedAt == 0) revert BidNotFound(); + if (_bid.isWithdrawn) revert WithdrawFailed("withdrawn"); + if (_bid.isWon) revert WithdrawFailed("won"); + if (amount <= 0) revert WithdrawFailed("zero amount"); // transfer bid price and tax back to the bidder registry.transferAmount(msg.sender, amount); diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 0117590..eec6db5 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -8,7 +8,7 @@ interface IBillboard { /// Error ////////////////////////////// - error Unauthorized(string type_); + error Unauthorized(string reason_); error BoardNotFound(); @@ -16,9 +16,11 @@ interface IBillboard { error AuctionNotEnded(); + error BidNotFound(); + error BidAlreadyPlaced(); - error WithdrawFailed(); + error WithdrawFailed(string reason_); error TransferFailed(); diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 0b7f226..bd2e4c4 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -413,9 +413,12 @@ contract BillboardTest is BillboardTestBase { assertEq(_auction.highestBidder, USER_A); // bid with USER_B + _amount = _amount * 2; + _tax = operator.calculateTax(_amount); + _total = _amount + _tax; + vm.deal(USER_B, _total); vm.startPrank(USER_B); - vm.deal(USER_B, _total * 2); - operator.placeBid{value: _total * 2}(_tokenId, _amount * 2); + operator.placeBid{value: _total}(_tokenId, _amount); _auction = registry.getAuction(_tokenId, _nextAuctionId); assertEq(_auction.highestBidder, USER_B); } @@ -596,6 +599,8 @@ contract BillboardTest is BillboardTestBase { /// Tax & Withdraw ////////////////////////////// + function testCalculateTax() public {} + function testSetTaxRate() public { vm.startPrank(ADMIN); @@ -610,11 +615,231 @@ contract BillboardTest is BillboardTestBase { operator.setTaxRate(2); } - function testWithdrawTax() public {} + function testWithdrawTax(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + uint256 _tokenId = _mintBoard(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); + + // place a bid and win auction + vm.deal(USER_A, _total); + vm.prank(USER_A); + operator.placeBid{value: _total}(_tokenId, _amount); + + uint256 _prevRegistryBalance = address(registry).balance; + uint256 _prevAdminBalance = ADMIN.balance; + + // withdraw tax + vm.prank(ADMIN); + operator.withdrawTax(); + + // check balances + assertEq(address(registry).balance, _prevRegistryBalance - _tax); + assertEq(ADMIN.balance, _prevAdminBalance + _tax); + } + + function testCannnotWithdrawTaxIfZero() public { + uint256 _tokenId = _mintBoard(); - function testCannotWithdrawTaxByAttacker() public {} + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); - function testWithdrawBid() public {} + // place a bid and win auction + vm.deal(USER_A, 0); + vm.prank(USER_A); + operator.placeBid{value: 0}(_tokenId, 0); - function testCannotWithdrawBidByAttacker() public {} + vm.prank(ADMIN); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + operator.withdrawTax(); + } + + function testCannnotWithdrawTaxIfSmallAmount(uint8 _amount) public { + uint256 _tax = operator.calculateTax(_amount); + vm.assume(_tax <= 0); + + uint256 _tokenId = _mintBoard(); + + vm.prank(ADMIN); + operator.addToWhitelist(USER_A); + + // place a bid and win auction + vm.deal(USER_A, _amount); + vm.prank(USER_A); + operator.placeBid{value: _amount}(_tokenId, _amount); + + vm.prank(ADMIN); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + operator.withdrawTax(); + } + + function testCannotWithdrawTaxByAttacker() public { + vm.startPrank(ATTACKER); + + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + operator.withdrawTax(); + } + + function testWithdrawBid(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // new auction and new bid with USER_A + vm.deal(USER_A, _total); + vm.prank(USER_A); + operator.placeBid{value: _total}(_tokenId, _amount); + + // new bid with USER_B + vm.deal(USER_B, _total); + vm.prank(USER_B); + operator.placeBid{value: _total}(_tokenId, _amount); + + // clear auction + vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + operator.clearAuction(_tokenId); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, USER_A); + + // check bid + IBillboardRegistry.Bid memory _bidA = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bidA.isWon, true); + IBillboardRegistry.Bid memory _bidB = registry.getBid(_tokenId, _nextAuctionId, USER_B); + assertEq(_bidB.isWon, false); + + // withdraw bid + vm.prank(USER_B); + operator.withdrawBid(_tokenId, _nextAuctionId); + assertEq(USER_B.balance, _total); + } + + function testCannotWithBidTwice(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // new auction and new bid with USER_A + vm.deal(USER_A, _total); + vm.prank(USER_A); + operator.placeBid{value: _total}(_tokenId, _amount); + + // new bid with USER_B + vm.deal(USER_B, _total); + vm.prank(USER_B); + operator.placeBid{value: _total}(_tokenId, _amount); + + // clear auction + vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + operator.clearAuction(_tokenId); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, USER_A); + + // withdraw bid + vm.prank(USER_B); + operator.withdrawBid(_tokenId, _nextAuctionId); + assertEq(USER_B.balance, _total); + + // withdraw bid again + vm.prank(USER_B); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "withdrawn")); + operator.withdrawBid(_tokenId, _nextAuctionId); + } + + function testCannotWithdrawBidIfWon(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // new auction and new bid with USER_A + vm.deal(USER_A, _total); + vm.prank(USER_A); + operator.placeBid{value: _total}(_tokenId, _amount); + + // clear auction + vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + operator.clearAuction(_tokenId); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.highestBidder, USER_A); + + // withdraw bid + vm.prank(USER_A); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "won")); + operator.withdrawBid(_tokenId, _nextAuctionId); + } + + function testCannotWithdrawBidIfAuctionNotEnded(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // new auction and new bid with USER_A + vm.startPrank(USER_A); + vm.deal(USER_A, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + + // auction is not ended + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + operator.withdrawBid(_tokenId, _nextAuctionId); + + // auction is ended but not cleared + vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "auction not cleared")); + operator.withdrawBid(_tokenId, _nextAuctionId); + } + + function testCannotWithdrawBidIfAuctionNotCleared(uint96 _amount) public { + vm.assume(_amount > 0.001 ether); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _tax = operator.calculateTax(_amount); + uint256 _total = _amount + _tax; + + // new auction and new bid with USER_A + vm.prank(USER_A); + vm.deal(USER_A, _total); + operator.placeBid{value: _total}(_tokenId, _amount); + + // new bid with USER_B + vm.deal(USER_B, _total); + vm.prank(USER_B); + operator.placeBid{value: _total}(_tokenId, _amount); + + // auction is ended but not cleared + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); + vm.prank(USER_B); + vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "auction not cleared")); + operator.withdrawBid(_tokenId, _nextAuctionId); + } + + function testCannotWithdrawBidIfNotFound() public { + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + + vm.prank(USER_A); + vm.expectRevert(abi.encodeWithSignature("BidNotFound()")); + operator.withdrawBid(_tokenId, _nextAuctionId); + } } diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 7e2dfe1..410174e 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -14,7 +14,7 @@ contract BillboardTestBase is Test { Billboard internal operator; BillboardRegistry internal registry; - uint256 constant TAX_RATE = 1; + uint256 constant TAX_RATE = 1; // 1% per day address constant ZERO_ADDRESS = address(0); address constant FAKE_CONTRACT = address(1); From f9a4aa38b187430a15b0a2b4642dc26329c834cd Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Sun, 19 Nov 2023 23:31:03 +0800 Subject: [PATCH 36/55] feat: add test for getBids --- .gas-snapshot | 65 +++++++++++++------------- src/test/Billboard/BillboardTest.t.sol | 44 ++++++++++++++++- 2 files changed, 76 insertions(+), 33 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index b350ab5..c7ee3dc 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,50 +10,51 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 157829) -BillboardTest:testCalculateTax() (gas: 210) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 483874, ~: 497559) +BillboardTest:testApproveAndTransfer() (gas: 157991) +BillboardTest:testCalculateTax() (gas: 232) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 483931, ~: 497616) BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 449939) -BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11839) -BillboardTest:testCannotApproveByAttacker() (gas: 131427) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) +BillboardTest:testCannotApproveByAttacker() (gas: 131449) BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 679282) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139178) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13960) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145247) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 725916, ~: 732147) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139133) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13982) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145269) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 725704, ~: 732169) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129251) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129273) BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162160) -BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11796) +BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) BillboardTest:testCannotTransferByOperator() (gas: 133927) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129436) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11949) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1035780, ~: 1035780) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129458) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1035802, ~: 1035802) BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 842804, ~: 842804) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 721017, ~: 721017) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 480313) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 849293, ~: 849293) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 721039, ~: 721039) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 480248) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 849315, ~: 849315) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 752944) -BillboardTest:testGetTokenURI() (gas: 154215) -BillboardTest:testMintBoard() (gas: 220013) -BillboardTest:testMintBoardByWhitelist() (gas: 157567) -BillboardTest:testMintBoardIfOpened() (gas: 130581) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 753046) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2931369, ~: 1514328) +BillboardTest:testGetTokenURI() (gas: 154155) +BillboardTest:testMintBoard() (gas: 220293) +BillboardTest:testMintBoardByWhitelist() (gas: 157589) +BillboardTest:testMintBoardIfOpened() (gas: 130603) BillboardTest:testPlaceBidByWhitelist() (gas: 533304) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1065336) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 532879, ~: 543603) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 838439, ~: 845513) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 836369, ~: 848045) -BillboardTest:testPlaceBidZeroPrice() (gas: 418865) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1065518) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 532959, ~: 543683) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 838205, ~: 845513) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 836484, ~: 848160) +BillboardTest:testPlaceBidZeroPrice() (gas: 418945) BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 140039) -BillboardTest:testSetBoardProperties() (gas: 285015) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 328856) +BillboardTest:testSafeTransferByOperator() (gas: 139973) +BillboardTest:testSetBoardProperties() (gas: 285177) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 329438) BillboardTest:testSetIsOpened() (gas: 15932) BillboardTest:testSetTaxRate() (gas: 24738) -BillboardTest:testUpgradeRegistry() (gas: 2471831) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1033494, ~: 1033494) +BillboardTest:testUpgradeRegistry() (gas: 2471853) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1033654, ~: 1033654) BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 566620, ~: 566620) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index bd2e4c4..c3563ef 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -593,7 +593,49 @@ contract BillboardTest is BillboardTestBase { operator.clearAuction(_tokenId); } - function getBids() public {} + function testGetBids(uint8 _bidCount, uint8 _limit, uint8 _offset) public { + vm.assume(_bidCount > 0); + vm.assume(_bidCount <= 64); + vm.assume(_limit <= _bidCount); + vm.assume(_offset <= _limit); + + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + + for (uint8 i = 0; i < _bidCount; i++) { + address _bidder = address(uint160(2000 + i)); + + vm.prank(ADMIN); + operator.addToWhitelist(_bidder); + + uint256 _amount = 1 ether + i; + uint256 _tax = operator.calculateTax(_amount); + uint256 _totalAmount = _amount + _tax; + + vm.deal(_bidder, _totalAmount); + vm.prank(_bidder); + operator.placeBid{value: _totalAmount}(_tokenId, _amount); + } + + // get bids + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + console.log(_nextAuctionId); + (uint256 _t, uint256 _l, uint256 _o, IBillboardRegistry.Bid[] memory _bids) = operator.getBids( + _tokenId, + _nextAuctionId, + _limit, + _offset + ); + uint256 _left = _t - _offset; + uint256 _size = _left > _limit ? _limit : _left; + assertEq(_t, _bidCount); + assertEq(_l, _limit); + assertEq(_bids.length, _size); + assertEq(_o, _offset); + for (uint256 i = 0; i < _size; i++) { + uint256 _amount = 1 ether + _offset + i; + assertEq(_bids[i].price, _amount); + } + } ////////////////////////////// /// Tax & Withdraw From ea58ea76f21d2d17fcbaaa65bbdef363287ae75d Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:05:04 +0800 Subject: [PATCH 37/55] feat(billboard): impl events and tests --- .gas-snapshot | 74 +++++----- src/Billboard/Billboard.sol | 9 ++ src/Billboard/BillboardRegistry.sol | 44 ++++++ src/Billboard/IBillboardRegistry.sol | 179 +++++++++++++++++++++++-- src/test/Billboard/BillboardTest.t.sol | 60 ++++++++- 5 files changed, 318 insertions(+), 48 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index c7ee3dc..b9ca49a 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,52 +10,52 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 157991) -BillboardTest:testCalculateTax() (gas: 232) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 483931, ~: 497616) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 449939) +BillboardTest:testApproveAndTransfer() (gas: 158013) +BillboardTest:testCalculateTax() (gas: 29386) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 495029, ~: 508015) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 460249) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 131449) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 679282) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139133) +BillboardTest:testCannotApproveByAttacker() (gas: 131471) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 699881) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139068) BillboardTest:testCannotMintBoardByAttacker() (gas: 13982) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145269) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 725704, ~: 732169) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145402) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 746646, ~: 752877) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129273) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162160) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129295) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162092) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 133927) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129458) +BillboardTest:testCannotTransferByOperator() (gas: 133949) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129480) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1035802, ~: 1035802) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 842804, ~: 842804) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 721039, ~: 721039) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 480248) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 849315, ~: 849315) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1068400, ~: 1068400) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 866310, ~: 866310) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 741945, ~: 741945) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 490558) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 875710, ~: 875710) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 753046) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2931369, ~: 1514328) -BillboardTest:testGetTokenURI() (gas: 154155) -BillboardTest:testMintBoard() (gas: 220293) -BillboardTest:testMintBoardByWhitelist() (gas: 157589) -BillboardTest:testMintBoardIfOpened() (gas: 130603) -BillboardTest:testPlaceBidByWhitelist() (gas: 533304) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1065518) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 532959, ~: 543683) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 838205, ~: 845513) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 836484, ~: 848160) -BillboardTest:testPlaceBidZeroPrice() (gas: 418945) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 783620) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2827763, ~: 1540041) +BillboardTest:testGetTokenURI() (gas: 156314) +BillboardTest:testMintBoard() (gas: 220337) +BillboardTest:testMintBoardByWhitelist() (gas: 157611) +BillboardTest:testMintBoardIfOpened() (gas: 130625) +BillboardTest:testPlaceBidByWhitelist() (gas: 543703) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1096931) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 555483, ~: 566206) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861923, ~: 868997) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 859879, ~: 871555) +BillboardTest:testPlaceBidZeroPrice() (gas: 429255) BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 139973) -BillboardTest:testSetBoardProperties() (gas: 285177) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 329438) +BillboardTest:testSafeTransferByOperator() (gas: 139995) +BillboardTest:testSetBoardProperties() (gas: 307920) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337266) BillboardTest:testSetIsOpened() (gas: 15932) -BillboardTest:testSetTaxRate() (gas: 24738) -BillboardTest:testUpgradeRegistry() (gas: 2471853) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1033654, ~: 1033654) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 566620, ~: 566620) +BillboardTest:testSetTaxRate() (gas: 27329) +BillboardTest:testUpgradeRegistry() (gas: 2537589) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1069195, ~: 1069195) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 581282, ~: 581282) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 28f4eb1..204edd5 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -196,6 +196,9 @@ contract Billboard is IBillboard { uint256 leaseStartAt = block.timestamp; uint256 leaseEndAt = leaseStartAt + registry.leaseTerm(); registry.setAuctionLease(tokenId_, nextAuctionId_, leaseStartAt, leaseEndAt); + + // emit AuctionCleared + registry.emitAuctionCleared(tokenId_, nextAuctionId_, _nextAuction.highestBidder, leaseStartAt, leaseEndAt); } /// @inheritdoc IBillboard @@ -325,6 +328,9 @@ contract Billboard is IBillboard { // set taxTreasury.withdrawn to taxTreasury.accumulated registry.setTaxTreasury(msg.sender, _taxAccumulated, _taxAccumulated); + + // emit TaxWithdrawn + registry.emitTaxWithdrawn(msg.sender, amount); } /// @inheritdoc IBillboard @@ -349,5 +355,8 @@ contract Billboard is IBillboard { // set bid.isWithdrawn to true registry.setBidWithdrawn(tokenId_, auctionId_, msg.sender, true); + + // emit BidWithdrawn + registry.emitBidWithdrawn(tokenId_, auctionId_, msg.sender, _bid.price, _bid.tax); } } diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 8c7ebbe..3549bf6 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -101,25 +101,30 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function setBoardName(uint256 tokenId_, string calldata name_) external isFromOperator { boards[tokenId_].name = name_; + emit BoardNameUpdated(tokenId_, name_); } /// @inheritdoc IBillboardRegistry function setBoardDescription(uint256 tokenId_, string calldata description_) external isFromOperator { boards[tokenId_].description = description_; + emit BoardDescriptionUpdated(tokenId_, description_); } /// @inheritdoc IBillboardRegistry function setBoardLocation(uint256 tokenId_, string calldata location_) external isFromOperator { boards[tokenId_].location = location_; + emit BoardLocationUpdated(tokenId_, location_); } /// @inheritdoc IBillboardRegistry function setBoardContentURI(uint256 tokenId_, string calldata contentURI_) external isFromOperator { boards[tokenId_].contentURI = contentURI_; + emit BoardContentURIUpdated(tokenId_, contentURI_); } function setBoardRedirectURI(uint256 tokenId_, string calldata redirectURI_) external isFromOperator { boards[tokenId_].redirectURI = redirectURI_; + emit BoardRedirectURIUpdated(tokenId_, redirectURI_); } ////////////////////////////// @@ -148,6 +153,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { leaseEndAt: 0, highestBidder: address(0) }); + + emit AuctionCreated(tokenId_, newAuctionId, startAt_, endAt_); } /// @inheritdoc IBillboardRegistry @@ -196,11 +203,15 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { if (highestBidder == address(0) || price_ > highestBid.price) { boardAuctions[tokenId_][auctionId_].highestBidder = bidder_; } + + emit BidCreated(tokenId_, auctionId_, bidder_, price_, tax_); } /// @inheritdoc IBillboardRegistry function setBidWon(uint256 tokenId_, uint256 auctionId_, address bidder_, bool isWon_) external isFromOperator { auctionBids[tokenId_][auctionId_][bidder_].isWon = isWon_; + + emit BidWon(tokenId_, auctionId_, bidder_); } /// @inheritdoc IBillboardRegistry @@ -228,6 +239,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function setTaxRate(uint256 taxRate_) external isFromOperator { taxRate = taxRate_; + + emit TaxRateUpdated(taxRate_); } /// @inheritdoc IBillboardRegistry @@ -253,4 +266,35 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { function transferFrom(address from_, address to_, uint256 tokenId_) public override(ERC721, IERC721) { safeTransferFrom(from_, to_, tokenId_, ""); } + + ////////////////////////////// + /// Event emission + ////////////////////////////// + + /// @inheritdoc IBillboardRegistry + function emitAuctionCleared( + uint256 tokenId_, + uint256 auctionId_, + address highestBidder_, + uint256 leaseStartAt_, + uint256 leaseEndAt_ + ) external { + emit AuctionCleared(tokenId_, auctionId_, highestBidder_, leaseStartAt_, leaseEndAt_); + } + + /// @inheritdoc IBillboardRegistry + function emitBidWithdrawn( + uint256 tokenId_, + uint256 auctionId_, + address bidder_, + uint256 price_, + uint256 tax_ + ) external { + emit BidWithdrawn(tokenId_, auctionId_, bidder_, price_, tax_); + } + + /// @inheritdoc IBillboardRegistry + function emitTaxWithdrawn(address owner_, uint256 amount_) external { + emit TaxWithdrawn(owner_, amount_); + } } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 7069c30..12322f1 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -16,15 +16,130 @@ interface IBillboardRegistry is IERC721 { /// Event ////////////////////////////// - // TODO - // mint & transfer (no need, inherted from ERC721) - // set board (name, uris, etc.) - // set tax rate - // new auction - // clear auction - // new bid - // withdraw bid - // withdraw tax + /** + * @notice Board name is updated. + * + * @param tokenId Token ID of the board. + * @param name New name of the board. + */ + event BoardNameUpdated(uint256 indexed tokenId, string name); + + /** + * @notice Board description is updated. + * + * @param tokenId Token ID of the board. + * @param description New description of the board. + */ + event BoardDescriptionUpdated(uint256 indexed tokenId, string description); + + /** + * @notice Board location is updated. + * + * @param tokenId Token ID of the board. + * @param location New location of the board. + */ + event BoardLocationUpdated(uint256 indexed tokenId, string location); + + /** + * @notice Board content URI is updated. + * + * @param tokenId Token ID of the board. + * @param contentURI New content URI of the board. + */ + event BoardContentURIUpdated(uint256 indexed tokenId, string contentURI); + + /** + * @notice Board redirect URI is updated. + * + * @param tokenId Token ID of the board. + * @param redirectURI New redirect URI of the board. + */ + event BoardRedirectURIUpdated(uint256 indexed tokenId, string redirectURI); + + /** + * @notice Global tax rate is updated. + * + * @param taxRate New tax rate. + */ + event TaxRateUpdated(uint256 taxRate); + + /** + * @notice Auction is created. + * + * @param tokenId Token ID of the board. + * @param auctionId Auction ID of the auction. + * @param startAt Start time of the auction. + * @param endAt End time of the auction. + */ + event AuctionCreated(uint256 indexed tokenId, uint256 indexed auctionId, uint256 startAt, uint256 endAt); + + /** + * @notice Auction is cleared. + * + * @param tokenId Token ID of the board. + * @param auctionId Auction ID of the auction. + * @param highestBidder Highest bidder of the auction. + * @param leaseStartAt Start time of the lease. + * @param leaseEndAt End time of the lease. + */ + event AuctionCleared( + uint256 indexed tokenId, + uint256 indexed auctionId, + address indexed highestBidder, + uint256 leaseStartAt, + uint256 leaseEndAt + ); + + /** + * @notice Bid is created. + * + * @param tokenId Token ID of the board. + * @param auctionId Auction ID of the auction. + * @param bidder Bidder of the auction. + * @param price Price of the bid. + * @param tax Tax of the bid. + */ + event BidCreated( + uint256 indexed tokenId, + uint256 indexed auctionId, + address indexed bidder, + uint256 price, + uint256 tax + ); + + /** + * @notice Bid is won. + * + * @param tokenId Token ID of the board. + * @param auctionId Auction ID of the auction. + * @param bidder Bidder of the auction. + */ + event BidWon(uint256 indexed tokenId, uint256 indexed auctionId, address indexed bidder); + + /** + * @notice Bid is withdrawn. + * + * @param tokenId Token ID of the board. + * @param auctionId Auction ID of the auction. + * @param bidder Bidder of the auction. + * @param price Price of the bid. + * @param tax Tax of the bid. + */ + event BidWithdrawn( + uint256 indexed tokenId, + uint256 indexed auctionId, + address indexed bidder, + uint256 price, + uint256 tax + ); + + /** + * @notice Tax is withdrawn. + * + * @param owner Owner of the treasury. + * @param amount Amount of the tax. + */ + event TaxWithdrawn(address indexed owner, uint256 amount); ////////////////////////////// /// Struct @@ -249,4 +364,50 @@ interface IBillboardRegistry is IERC721 { * @param withdrawn_ Withdrawn tax. */ function setTaxTreasury(address owner_, uint256 accumulated_, uint256 withdrawn_) external; + + ////////////////////////////// + /// Event emission + ////////////////////////////// + + /** + * @notice Emit `AuctionCleared` event. + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of an auction. + * @param highestBidder_ Highest bidder of an auction. + * @param leaseStartAt_ Start time of an board lease. + * @param leaseEndAt_ End time of an board lease. + */ + function emitAuctionCleared( + uint256 tokenId_, + uint256 auctionId_, + address highestBidder_, + uint256 leaseStartAt_, + uint256 leaseEndAt_ + ) external; + + /** + * @notice Emit `BidWithdrawn` event. + * + * @param tokenId_ Token ID of a board. + * @param auctionId_ Auction ID of an auction. + * @param bidder_ Bidder of an auction. + * @param price_ Price of a bid. + * @param tax_ Tax of a bid. + */ + function emitBidWithdrawn( + uint256 tokenId_, + uint256 auctionId_, + address bidder_, + uint256 price_, + uint256 tax_ + ) external; + + /** + * @notice Emit `TaxWithdrawn` event. + * + * @param owner_ Address of a treasury owner. + * @param amount_ Amount. + */ + function emitTaxWithdrawn(address owner_, uint256 amount_) external; } diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index c3563ef..c572a0f 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -145,10 +145,24 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); + vm.expectEmit(true, true, false, false); + emit IBillboardRegistry.BoardNameUpdated(_tokenId, "name"); operator.setBoardName(_tokenId, "name"); + + vm.expectEmit(true, true, false, false); + emit IBillboardRegistry.BoardDescriptionUpdated(_tokenId, "description"); operator.setBoardDescription(_tokenId, "description"); + + vm.expectEmit(true, true, false, false); + emit IBillboardRegistry.BoardLocationUpdated(_tokenId, "location"); operator.setBoardLocation(_tokenId, "location"); + + vm.expectEmit(true, true, false, false); + emit IBillboardRegistry.BoardContentURIUpdated(_tokenId, "uri"); operator.setBoardContentURI(_tokenId, "uri"); + + vm.expectEmit(true, true, false, false); + emit IBillboardRegistry.BoardRedirectURIUpdated(_tokenId, "redirect URI"); operator.setBoardRedirectURI(_tokenId, "redirect URI"); IBillboardRegistry.Board memory board = operator.getBoard(1); @@ -332,6 +346,21 @@ contract BillboardTest is BillboardTestBase { uint256 _prevOperatorBalance = address(operator).balance; uint256 _prevRegistryBalance = address(registry).balance; + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCreated(_tokenId, _prevNextActionId + 1, block.timestamp, block.timestamp); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.BidCreated(_tokenId, _prevNextActionId + 1, USER_A, _amount, _tax); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.BidWon(_tokenId, _prevNextActionId + 1, USER_A); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId, + _prevNextActionId + 1, + USER_A, + block.timestamp, + block.timestamp + registry.leaseTerm() + ); + vm.prank(USER_A); operator.placeBid{value: _total}(_tokenId, _amount); @@ -532,7 +561,7 @@ contract BillboardTest is BillboardTestBase { } function testClearAuctionIfAuctionEnded() public { - (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); uint256 _placedAt = block.timestamp; uint256 _clearedAt = block.timestamp + registry.leaseTerm() + 1 minutes; @@ -542,6 +571,15 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: 0}(_tokenId, 0); // clear auction + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId, + _prevAuctionId + 1, + USER_A, + _clearedAt, + _clearedAt + registry.leaseTerm() + ); + vm.warp(_clearedAt); operator.clearAuction(_tokenId); @@ -641,11 +679,23 @@ contract BillboardTest is BillboardTestBase { /// Tax & Withdraw ////////////////////////////// - function testCalculateTax() public {} + function testCalculateTax() public { + uint256 _amount = 100; + uint256 _taxRate = 10; // 10% per day + + vm.startPrank(ADMIN); + operator.setTaxRate(_taxRate); + + uint256 _tax = operator.calculateTax(_amount); + assertEq(_tax, (_amount * _taxRate * 14) / 100); + } function testSetTaxRate() public { vm.startPrank(ADMIN); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.TaxRateUpdated(2); + operator.setTaxRate(2); assertEq(operator.getTaxRate(), 2); } @@ -676,6 +726,9 @@ contract BillboardTest is BillboardTestBase { uint256 _prevAdminBalance = ADMIN.balance; // withdraw tax + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.TaxWithdrawn(ADMIN, _tax); + vm.prank(ADMIN); operator.withdrawTax(); @@ -759,6 +812,9 @@ contract BillboardTest is BillboardTestBase { assertEq(_bidB.isWon, false); // withdraw bid + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.BidWithdrawn(_tokenId, _nextAuctionId, USER_B, _amount, _tax); + vm.prank(USER_B); operator.withdrawBid(_tokenId, _nextAuctionId); assertEq(USER_B.balance, _total); From 827b8372c96c0142c513c782ca9393bd84b9d911 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:34:26 +0800 Subject: [PATCH 38/55] feat(billboard): add tests for ERC721.Approval and Transfer events --- .gas-snapshot | 14 +++++++------- src/test/Billboard/BillboardTest.t.sol | 21 ++++++++++++++++++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index b9ca49a..f32e3d2 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,9 +10,9 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 158013) +BillboardTest:testApproveAndTransfer() (gas: 163591) BillboardTest:testCalculateTax() (gas: 29386) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 495029, ~: 508015) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 494337, ~: 508015) BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 460249) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) BillboardTest:testCannotApproveByAttacker() (gas: 131471) @@ -36,19 +36,19 @@ BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 490558) BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 875710, ~: 875710) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) BillboardTest:testClearAuctionIfAuctionEnded() (gas: 783620) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2827763, ~: 1540041) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2871040, ~: 1540041) BillboardTest:testGetTokenURI() (gas: 156314) -BillboardTest:testMintBoard() (gas: 220337) +BillboardTest:testMintBoard() (gas: 225083) BillboardTest:testMintBoardByWhitelist() (gas: 157611) BillboardTest:testMintBoardIfOpened() (gas: 130625) BillboardTest:testPlaceBidByWhitelist() (gas: 543703) BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1096931) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 555483, ~: 566206) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861923, ~: 868997) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 557853, ~: 568576) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861845, ~: 868997) BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 859879, ~: 871555) BillboardTest:testPlaceBidZeroPrice() (gas: 429255) BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 139995) +BillboardTest:testSafeTransferByOperator() (gas: 142371) BillboardTest:testSetBoardProperties() (gas: 307920) BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337266) BillboardTest:testSetIsOpened() (gas: 15932) diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index c572a0f..993a4f3 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; import "./BillboardTestBase.t.sol"; +import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; contract BillboardTest is BillboardTestBase { ////////////////////////////// @@ -89,6 +90,8 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); // mint + vm.expectEmit(true, true, true, true); + emit IERC721.Transfer(address(0), ADMIN, 1); operator.mintBoard(ADMIN); assertEq(registry.balanceOf(ADMIN), 1); @@ -105,6 +108,8 @@ contract BillboardTest is BillboardTestBase { assertEq(board.redirectURI, ""); // mint again for checking id generator + vm.expectEmit(true, true, true, true); + emit IERC721.Transfer(address(0), ADMIN, 2); operator.mintBoard(ADMIN); assertEq(registry.balanceOf(ADMIN), 2); board = operator.getBoard(2); @@ -289,6 +294,9 @@ contract BillboardTest is BillboardTestBase { function testSafeTransferByOperator() public { uint256 _tokenId = _mintBoard(); + vm.expectEmit(true, true, true, true); + emit IERC721.Transfer(ADMIN, USER_A, _tokenId); + vm.startPrank(address(operator)); registry.safeTransferByOperator(ADMIN, USER_A, _tokenId); assertEq(registry.ownerOf(_tokenId), USER_A); @@ -306,16 +314,20 @@ contract BillboardTest is BillboardTestBase { function testApproveAndTransfer() public { uint256 _tokenId = _mintBoard(); - vm.startPrank(ADMIN); + vm.expectEmit(true, true, true, true); + emit IERC721.Approval(ADMIN, USER_A, _tokenId); + vm.prank(ADMIN); registry.approve(USER_A, _tokenId); assertEq(registry.getApproved(_tokenId), USER_A); - vm.stopPrank(); - vm.startPrank(USER_A); + vm.expectEmit(true, true, true, true); + emit IERC721.Transfer(ADMIN, USER_A, _tokenId); + vm.prank(USER_A); registry.transferFrom(ADMIN, USER_A, _tokenId); IBillboardRegistry.Board memory board = operator.getBoard(_tokenId); assertEq(board.creator, ADMIN); + assertEq(registry.ownerOf(_tokenId), USER_A); } function testCannotApproveByAttacker() public { @@ -335,6 +347,9 @@ contract BillboardTest is BillboardTestBase { vm.prank(ADMIN); operator.addToWhitelist(USER_A); + vm.expectEmit(true, false, false, false); + emit IERC721.Transfer(address(0), ADMIN, 1); + uint256 _tokenId = _mintBoard(); uint256 _tax = operator.calculateTax(_amount); uint256 _total = _amount + _tax; From 6e68e0048eccf4787c388f2282f657e027ab51bc Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:42:41 +0800 Subject: [PATCH 39/55] feat(billboard): add tests for ERC721 name & symbol --- .gas-snapshot | 8 ++++---- src/test/Billboard/BillboardTest.t.sol | 4 +++- src/test/Billboard/BillboardTestBase.t.sol | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index f32e3d2..141f9a4 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -36,7 +36,7 @@ BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 490558) BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 875710, ~: 875710) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) BillboardTest:testClearAuctionIfAuctionEnded() (gas: 783620) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2871040, ~: 1540041) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2979552, ~: 1548645) BillboardTest:testGetTokenURI() (gas: 156314) BillboardTest:testMintBoard() (gas: 225083) BillboardTest:testMintBoardByWhitelist() (gas: 157611) @@ -44,8 +44,8 @@ BillboardTest:testMintBoardIfOpened() (gas: 130625) BillboardTest:testPlaceBidByWhitelist() (gas: 543703) BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1096931) BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 557853, ~: 568576) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861845, ~: 868997) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 859879, ~: 871555) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861923, ~: 868997) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 859723, ~: 871555) BillboardTest:testPlaceBidZeroPrice() (gas: 429255) BillboardTest:testRemoveToWhitelist() (gas: 24992) BillboardTest:testSafeTransferByOperator() (gas: 142371) @@ -53,7 +53,7 @@ BillboardTest:testSetBoardProperties() (gas: 307920) BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337266) BillboardTest:testSetIsOpened() (gas: 15932) BillboardTest:testSetTaxRate() (gas: 27329) -BillboardTest:testUpgradeRegistry() (gas: 2537589) +BillboardTest:testUpgradeRegistry() (gas: 2547606) BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1069195, ~: 1069195) BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 581282, ~: 581282) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 993a4f3..d8c1e8c 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -13,8 +13,10 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); // deploy new operator - Billboard newOperator = new Billboard(payable(registry), TAX_RATE, "BLBD", "BLBD"); + Billboard newOperator = new Billboard(payable(registry), TAX_RATE, "Billboard2", "BLBD2"); assertEq(newOperator.admin(), ADMIN); + assertEq(registry.name(), "Billboard"); // registry is not changed + assertEq(registry.symbol(), "BLBD"); // registry is not changed // upgrade registry's operator assertEq(registry.operator(), address(operator)); diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 410174e..7a26dec 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -30,10 +30,12 @@ contract BillboardTestBase is Test { vm.startPrank(ADMIN); // deploy operator & registry - operator = new Billboard(payable(address(0)), TAX_RATE, "BLBD", "BLBD"); + operator = new Billboard(payable(address(0)), TAX_RATE, "Billboard", "BLBD"); registry = operator.registry(); assertEq(operator.admin(), ADMIN); assertEq(registry.operator(), address(operator)); + assertEq(registry.name(), "Billboard"); + assertEq(registry.symbol(), "BLBD"); vm.stopPrank(); } From d0454afb290e32c3ae65d2dcfcb4d72eb0638f9b Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:53:35 +0800 Subject: [PATCH 40/55] feat(billboard): add scripts for static analyzers and billboard deployment --- .env.local.example | 3 ++- .env.polygon-mainnet.example | 1 + .env.polygon-mumbai.example | 3 ++- .vscode/settings.json | 4 +++- Makefile | 12 +++++++++++- README.md | 6 ++++++ foundry.toml | 1 + slither.config.json | 3 +++ 8 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 slither.config.json diff --git a/.env.local.example b/.env.local.example index 1b1086a..ff963a6 100644 --- a/.env.local.example +++ b/.env.local.example @@ -16,4 +16,5 @@ THESPACE_TEAM_TOKENS= THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= -THESPACE_LP_TOKENS= \ No newline at end of file +THESPACE_LP_TOKENS= +BILLBOARD_REGISTRY_ADDRESS= diff --git a/.env.polygon-mainnet.example b/.env.polygon-mainnet.example index 7b5fc35..f940fcf 100644 --- a/.env.polygon-mainnet.example +++ b/.env.polygon-mainnet.example @@ -18,3 +18,4 @@ THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= +BILLBOARD_REGISTRY_ADDRESS= diff --git a/.env.polygon-mumbai.example b/.env.polygon-mumbai.example index c768d11..40dfc38 100644 --- a/.env.polygon-mumbai.example +++ b/.env.polygon-mumbai.example @@ -17,4 +17,5 @@ THESPACE_TEAM_TOKENS= THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= -THESPACE_LP_TOKENS= \ No newline at end of file +THESPACE_LP_TOKENS= +BILLBOARD_REGISTRY_ADDRESS= diff --git a/.vscode/settings.json b/.vscode/settings.json index 05a475b..831a723 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,7 @@ "solidity.formatter": "prettier", "[solidity]": { "editor.defaultFormatter": "NomicFoundation.hardhat-solidity" - } + }, + "solidity.packageDefaultDependenciesContractsDirectory": "src", + "solidity.packageDefaultDependenciesDirectory": "lib" } \ No newline at end of file diff --git a/Makefile b/Makefile index e899a63..63eabd9 100644 --- a/Makefile +++ b/Makefile @@ -11,10 +11,16 @@ coverage :; forge coverage --report=summary build: clean forge build test: - forge test --gas-report + forge test --gas-report -vvv trace: clean forge test -vvvvv --gas-report +# Static Analyzers +analyze-logbook :; slither src/Logbook/Logbook.sol +analyze-the-space :; slither src/TheSpace/TheSpace.sol +analyze-curation :; slither src/Curation/Curation.sol +analyze-billboard :; slither src/Billboard/Billboard.sol + # Deployments ## Logbook deploy-logbook: clean @@ -36,3 +42,7 @@ deploy-snapper: clean ## Curation deploy-curation: clean @forge create Curation --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} + +## Billboard +deploy-billboard: clean + @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 "Billboard" "BLBD" --legacy \ No newline at end of file diff --git a/README.md b/README.md index 4b8133f..0feeb83 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,12 @@ Testing make test ``` +Static Analyzers + +```bash +make analyze-billboard +``` + ## Deployment ### Deploy on Local Node: diff --git a/foundry.toml b/foundry.toml index e25d440..0106e48 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,6 +9,7 @@ remappings = [ ] verbosity = 3 gas_reports = ["*"] +solc_version = "0.8.22" [profile.ci] fuzz_runs = 1024 diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 0000000..532595d --- /dev/null +++ b/slither.config.json @@ -0,0 +1,3 @@ +{ + "filter_paths": "lib" +} From 10ae7eb6bb58afbb668ceb700daee081f28a5317 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:34:58 +0800 Subject: [PATCH 41/55] feat(billboard): deploy to mumbai --- .env.local.example | 2 +- .env.polygon-mainnet.example | 2 +- .env.polygon-mumbai.example | 2 +- Makefile | 2 +- README.md | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.env.local.example b/.env.local.example index ff963a6..1019df2 100644 --- a/.env.local.example +++ b/.env.local.example @@ -17,4 +17,4 @@ THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= -BILLBOARD_REGISTRY_ADDRESS= +BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 \ No newline at end of file diff --git a/.env.polygon-mainnet.example b/.env.polygon-mainnet.example index f940fcf..4c65c90 100644 --- a/.env.polygon-mainnet.example +++ b/.env.polygon-mainnet.example @@ -18,4 +18,4 @@ THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= -BILLBOARD_REGISTRY_ADDRESS= +BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 diff --git a/.env.polygon-mumbai.example b/.env.polygon-mumbai.example index 40dfc38..676c67a 100644 --- a/.env.polygon-mumbai.example +++ b/.env.polygon-mumbai.example @@ -18,4 +18,4 @@ THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= -BILLBOARD_REGISTRY_ADDRESS= +BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 diff --git a/Makefile b/Makefile index 63eabd9..1a07db0 100644 --- a/Makefile +++ b/Makefile @@ -45,4 +45,4 @@ deploy-curation: clean ## Billboard deploy-billboard: clean - @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 "Billboard" "BLBD" --legacy \ No newline at end of file + @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 "Billboard" "BLBD" --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} \ No newline at end of file diff --git a/README.md b/README.md index 0feeb83..04e0ed6 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ | SpaceToken | Polygon Mainnet | [0x264808855b0a6a5a318d238c6ee9f299179f27fc](https://polygonscan.com/address/0x264808855b0a6a5a318d238c6ee9f299179f27fc) | | TheSpace | Polygon Mainnet | [0x9b71045ac2a1563dc5ff8e0c537413a6aae16cd1](https://polygonscan.com/address/0x9b71045ac2a1563dc5ff8e0c537413a6aae16cd1) | | TheSpaceRegistry | Polygon Mainnet | [0x8da7a7a48ebbd870358f2fd824e52e5142f44257](https://polygonscan.com/address/0x8da7a7a48ebbd870358f2fd824e52e5142f44257) | +| Billboard | Polygon Mumbai | [0x88EA16c2a69f50B9bc2E8f7684D425f33f29225F](https://mumbai.polygonscan.com/address/0x88EA16c2a69f50B9bc2E8f7684D425f33f29225F) | +| Billboard | Polygon Mainnet | / | In the "Contract" tab of Polygonscan/Etherscan, you can see the contract code and ABI. From 001e7b21f1656a0ff77255079adccb17ad3e2d60 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 21 Nov 2023 19:29:51 +0800 Subject: [PATCH 42/55] feat(ci): add gas diff --- .gas-snapshot | 76 +++++++++++++------------- .github/workflows/foundry-gas-diff.yml | 57 +++++++++++++++++++ Makefile | 7 ++- 3 files changed, 99 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/foundry-gas-diff.yml diff --git a/.gas-snapshot b/.gas-snapshot index 141f9a4..2346290 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,52 +10,52 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 163591) -BillboardTest:testCalculateTax() (gas: 29386) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 494337, ~: 508015) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 460249) +BillboardTest:testApproveAndTransfer() (gas: 163857) +BillboardTest:testCalculateTax() (gas: 29505) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 423914, ~: 437412) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 389527) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 131471) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 699881) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139068) +BillboardTest:testCannotApproveByAttacker() (gas: 131509) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 605205) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139265) BillboardTest:testCannotMintBoardByAttacker() (gas: 13982) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145402) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 746646, ~: 752877) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145581) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 651713, ~: 657944) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129295) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162092) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129333) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162733) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 133949) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129480) +BillboardTest:testCannotTransferByOperator() (gas: 133987) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129518) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 1068400, ~: 1068400) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 866310, ~: 866310) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 741945, ~: 741945) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 490558) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 875710, ~: 875710) -BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21732) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 783620) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2979552, ~: 1548645) -BillboardTest:testGetTokenURI() (gas: 156314) -BillboardTest:testMintBoard() (gas: 225083) -BillboardTest:testMintBoardByWhitelist() (gas: 157611) -BillboardTest:testMintBoardIfOpened() (gas: 130625) -BillboardTest:testPlaceBidByWhitelist() (gas: 543703) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 1096931) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 557853, ~: 568576) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 861923, ~: 868997) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 859723, ~: 871555) -BillboardTest:testPlaceBidZeroPrice() (gas: 429255) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 935324, ~: 935324) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 771783, ~: 771783) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 647088, ~: 647088) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 420082) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 741996, ~: 741996) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 650374) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2880898, ~: 1456587) +BillboardTest:testGetTokenURI() (gas: 156380) +BillboardTest:testMintBoard() (gas: 225615) +BillboardTest:testMintBoardByWhitelist() (gas: 157649) +BillboardTest:testMintBoardIfOpened() (gas: 130663) +BillboardTest:testPlaceBidByWhitelist() (gas: 473122) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937696) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 487592, ~: 498469) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 767470, ~: 774544) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 765287, ~: 776963) +BillboardTest:testPlaceBidZeroPrice() (gas: 358655) BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 142371) -BillboardTest:testSetBoardProperties() (gas: 307920) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337266) +BillboardTest:testSafeTransferByOperator() (gas: 142409) +BillboardTest:testSetBoardProperties() (gas: 308843) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 339408) BillboardTest:testSetIsOpened() (gas: 15932) -BillboardTest:testSetTaxRate() (gas: 27329) -BillboardTest:testUpgradeRegistry() (gas: 2547606) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 1069195, ~: 1069195) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 581282, ~: 581282) +BillboardTest:testSetTaxRate() (gas: 27307) +BillboardTest:testUpgradeRegistry() (gas: 2592983) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935985, ~: 935985) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 510679, ~: 510679) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/.github/workflows/foundry-gas-diff.yml b/.github/workflows/foundry-gas-diff.yml new file mode 100644 index 0000000..617d604 --- /dev/null +++ b/.github/workflows/foundry-gas-diff.yml @@ -0,0 +1,57 @@ +name: Report gas diff + +on: + push: + branches-ignore: + - master + - main + - develop + pull_request: + # Optionally configure to run only for changes in specific files. For example: + # paths: + # - src/** + # - test/** + # - foundry.toml + # - remappings.txt + # - .github/workflows/foundry-gas-diff.yml + +jobs: + compare_gas_reports: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install Foundry + uses: onbjerg/foundry-toolchain@v1 + with: + version: nightly + + - name: Env + run: cp .env.local.example .env.local + + # Add any step generating a gas report to a temporary file named gasreport.ansi. For example: + - name: Run tests + run: FOUNDRY_PROFILE=ci make gas-report > gasreport.ansi # <- this file name should be unique in your repository! + env: + # make fuzzing semi-deterministic to avoid noisy gas cost estimation + # due to non-deterministic fuzzing (but still use pseudo-random fuzzing seeds) + FOUNDRY_FUZZ_SEED: 0x${{ github.event.pull_request.base.sha || github.sha }} + + - name: Compare gas reports + uses: Rubilmax/foundry-gas-diff@v3.16 + with: + summaryQuantile: 0.9 # only display the 10% most significant gas diffs in the summary (defaults to 20%) + sortCriteria: avg,max # sort diff rows by criteria + sortOrders: desc,asc # and directions + ignore: test-foundry/**/* # filter out gas reports from specific paths (test/ is included by default) + id: gas_diff + + - name: Add gas diff to sticky comment + if: github.event_name == 'pull_request' || github.event_name == 'pull_request_target' + uses: marocchino/sticky-pull-request-comment@v2 + with: + # delete the comment in case changes no longer impact gas costs + delete: ${{ !steps.gas_diff.outputs.markdown }} + message: ${{ steps.gas_diff.outputs.markdown }} diff --git a/Makefile b/Makefile index 1a07db0..2dd085c 100644 --- a/Makefile +++ b/Makefile @@ -6,14 +6,15 @@ update:; forge update # Build & test clean :; forge clean -snapshot :; forge snapshot --gas-report +snapshot :; forge snapshot +gas-report :; forge test --gas-report coverage :; forge coverage --report=summary build: clean forge build test: - forge test --gas-report -vvv + forge test -vvv trace: clean - forge test -vvvvv --gas-report + forge test -vvvvv # Static Analyzers analyze-logbook :; slither src/Logbook/Logbook.sol From 10389c732b16b0bf9d0123ad5abc321449786fa0 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 21 Nov 2023 19:37:20 +0800 Subject: [PATCH 43/55] fix(ci): run tests --- .github/workflows/foundry-gas-diff.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/foundry-gas-diff.yml b/.github/workflows/foundry-gas-diff.yml index 617d604..1a5053b 100644 --- a/.github/workflows/foundry-gas-diff.yml +++ b/.github/workflows/foundry-gas-diff.yml @@ -23,11 +23,18 @@ jobs: with: submodules: recursive + - uses: actions/setup-node@v2 + - name: Install dev dependencies + run: npm install + - name: Install Foundry - uses: onbjerg/foundry-toolchain@v1 + uses: foundry-rs/foundry-toolchain@v1 with: version: nightly + - name: Run lint check + run: npm run lint:check + - name: Env run: cp .env.local.example .env.local From 903742f463a6ba6736d5202450aa9f40667a4acc Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 21 Nov 2023 20:55:04 +0800 Subject: [PATCH 44/55] feat(billboard): pack Auction timestamps to uint64 for gas optimzation --- .github/workflows/foundry-gas-diff.yml | 8 -------- src/Billboard/Billboard.sol | 12 ++++++------ src/Billboard/BillboardRegistry.sol | 14 +++++++------- src/Billboard/IBillboardRegistry.sol | 22 +++++++++++----------- src/test/Billboard/BillboardTest.t.sol | 15 ++++++++++----- 5 files changed, 34 insertions(+), 37 deletions(-) diff --git a/.github/workflows/foundry-gas-diff.yml b/.github/workflows/foundry-gas-diff.yml index 1a5053b..d370265 100644 --- a/.github/workflows/foundry-gas-diff.yml +++ b/.github/workflows/foundry-gas-diff.yml @@ -6,14 +6,6 @@ on: - master - main - develop - pull_request: - # Optionally configure to run only for changes in specific files. For example: - # paths: - # - src/** - # - test/** - # - foundry.toml - # - remappings.txt - # - .github/workflows/foundry-gas-diff.yml jobs: compare_gas_reports: diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 204edd5..c8ee82e 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -193,8 +193,8 @@ contract Billboard is IBillboard { registry.setBidWon(tokenId_, nextAuctionId_, _nextAuction.highestBidder, true); // set auction lease - uint256 leaseStartAt = block.timestamp; - uint256 leaseEndAt = leaseStartAt + registry.leaseTerm(); + uint64 leaseStartAt = uint64(block.timestamp); + uint64 leaseEndAt = uint64(leaseStartAt + registry.leaseTerm()); registry.setAuctionLease(tokenId_, nextAuctionId_, leaseStartAt, leaseEndAt); // emit AuctionCleared @@ -213,7 +213,7 @@ contract Billboard is IBillboard { // create new auction and new bid first, // then clear auction and transfer ownership to the bidder immediately. if (_nextAuction.startAt == 0) { - uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, block.timestamp); + uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp)); _clearAuction(tokenId_, _boardCreator, _auctionId); return; } @@ -223,7 +223,7 @@ contract Billboard is IBillboard { // then create new auction and new bid if (block.timestamp >= _nextAuction.endAt) { _clearAuction(tokenId_, _boardCreator, _nextAuctionId); - _newAuctionAndBid(tokenId_, amount_, block.timestamp + registry.leaseTerm()); + _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp + registry.leaseTerm())); return; } // if next auction is not ended, @@ -240,8 +240,8 @@ contract Billboard is IBillboard { } } - function _newAuctionAndBid(uint256 tokenId_, uint256 amount_, uint256 endAt_) private returns (uint256 auctionId) { - uint256 _startAt = block.timestamp; + function _newAuctionAndBid(uint256 tokenId_, uint256 amount_, uint64 endAt_) private returns (uint256 auctionId) { + uint64 _startAt = uint64(block.timestamp); uint256 _tax = calculateTax(amount_); auctionId = registry.newAuction(tokenId_, _startAt, endAt_); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 3549bf6..040d234 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -15,7 +15,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { Counters.Counter private _tokenIds; uint256 public taxRate; - uint256 public leaseTerm = 14 days; + uint64 public leaseTerm = 14 days; // tokenId => Board mapping(uint256 => Board) public boards; @@ -139,8 +139,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function newAuction( uint256 tokenId_, - uint256 startAt_, - uint256 endAt_ + uint64 startAt_, + uint64 endAt_ ) external isFromOperator returns (uint256 newAuctionId) { nextBoardAuctionId[tokenId_]++; @@ -161,8 +161,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { function setAuctionLease( uint256 tokenId_, uint256 auctionId_, - uint256 leaseStartAt_, - uint256 leaseEndAt_ + uint64 leaseStartAt_, + uint64 leaseEndAt_ ) external isFromOperator { boardAuctions[tokenId_][auctionId_].leaseStartAt = leaseStartAt_; boardAuctions[tokenId_][auctionId_].leaseEndAt = leaseEndAt_; @@ -276,8 +276,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 tokenId_, uint256 auctionId_, address highestBidder_, - uint256 leaseStartAt_, - uint256 leaseEndAt_ + uint64 leaseStartAt_, + uint64 leaseEndAt_ ) external { emit AuctionCleared(tokenId_, auctionId_, highestBidder_, leaseStartAt_, leaseEndAt_); } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 12322f1..b5a04f4 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -71,7 +71,7 @@ interface IBillboardRegistry is IERC721 { * @param startAt Start time of the auction. * @param endAt End time of the auction. */ - event AuctionCreated(uint256 indexed tokenId, uint256 indexed auctionId, uint256 startAt, uint256 endAt); + event AuctionCreated(uint256 indexed tokenId, uint256 indexed auctionId, uint64 startAt, uint64 endAt); /** * @notice Auction is cleared. @@ -86,8 +86,8 @@ interface IBillboardRegistry is IERC721 { uint256 indexed tokenId, uint256 indexed auctionId, address indexed highestBidder, - uint256 leaseStartAt, - uint256 leaseEndAt + uint64 leaseStartAt, + uint64 leaseEndAt ); /** @@ -155,10 +155,10 @@ interface IBillboardRegistry is IERC721 { } struct Auction { - uint256 startAt; // timestamp - uint256 endAt; // timestamp - uint256 leaseStartAt; // timestamp - uint256 leaseEndAt; // timestamp + uint64 startAt; // timestamp + uint64 endAt; // timestamp + uint64 leaseStartAt; // timestamp + uint64 leaseEndAt; // timestamp address highestBidder; } @@ -271,7 +271,7 @@ interface IBillboardRegistry is IERC721 { * @param startAt_ Start time of an auction. * @param endAt_ End time of an auction. */ - function newAuction(uint256 tokenId_, uint256 startAt_, uint256 endAt_) external returns (uint256 auctionId); + function newAuction(uint256 tokenId_, uint64 startAt_, uint64 endAt_) external returns (uint256 auctionId); /** * @notice Set the data of an auction @@ -281,7 +281,7 @@ interface IBillboardRegistry is IERC721 { * @param leaseStartAt_ Start time of an board lease. * @param leaseEndAt_ End time of an board lease. */ - function setAuctionLease(uint256 tokenId_, uint256 auctionId_, uint256 leaseStartAt_, uint256 leaseEndAt_) external; + function setAuctionLease(uint256 tokenId_, uint256 auctionId_, uint64 leaseStartAt_, uint64 leaseEndAt_) external; /** * @notice Get bid count of an auction @@ -382,8 +382,8 @@ interface IBillboardRegistry is IERC721 { uint256 tokenId_, uint256 auctionId_, address highestBidder_, - uint256 leaseStartAt_, - uint256 leaseEndAt_ + uint64 leaseStartAt_, + uint64 leaseEndAt_ ) external; /** diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index d8c1e8c..36dacf3 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -364,7 +364,12 @@ contract BillboardTest is BillboardTestBase { uint256 _prevRegistryBalance = address(registry).balance; vm.expectEmit(true, true, true, true); - emit IBillboardRegistry.AuctionCreated(_tokenId, _prevNextActionId + 1, block.timestamp, block.timestamp); + emit IBillboardRegistry.AuctionCreated( + _tokenId, + _prevNextActionId + 1, + uint64(block.timestamp), + uint64(block.timestamp) + ); vm.expectEmit(true, true, true, true); emit IBillboardRegistry.BidCreated(_tokenId, _prevNextActionId + 1, USER_A, _amount, _tax); vm.expectEmit(true, true, true, true); @@ -374,8 +379,8 @@ contract BillboardTest is BillboardTestBase { _tokenId, _prevNextActionId + 1, USER_A, - block.timestamp, - block.timestamp + registry.leaseTerm() + uint64(block.timestamp), + uint64(block.timestamp + registry.leaseTerm()) ); vm.prank(USER_A); @@ -579,8 +584,8 @@ contract BillboardTest is BillboardTestBase { function testClearAuctionIfAuctionEnded() public { (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); - uint256 _placedAt = block.timestamp; - uint256 _clearedAt = block.timestamp + registry.leaseTerm() + 1 minutes; + uint64 _placedAt = uint64(block.timestamp); + uint64 _clearedAt = uint64(block.timestamp) + registry.leaseTerm() + 1 minutes; // place a bid vm.startPrank(USER_A); From cf881056e1a8770e7bce8106102482b3ae02f1fb Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:44:41 +0800 Subject: [PATCH 45/55] feat(billboard): make lastTokenId public --- .gas-snapshot | 76 ++++++++++++++--------------- src/Billboard/Billboard.sol | 6 +-- src/Billboard/BillboardRegistry.sol | 9 ++-- 3 files changed, 44 insertions(+), 47 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 2346290..8121701 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,52 +10,52 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 163857) -BillboardTest:testCalculateTax() (gas: 29505) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 423914, ~: 437412) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 389527) +BillboardTest:testApproveAndTransfer() (gas: 164045) +BillboardTest:testCalculateTax() (gas: 29439) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 424231, ~: 437543) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 389746) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 131509) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 605205) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139265) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13982) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145581) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 651713, ~: 657944) +BillboardTest:testCannotApproveByAttacker() (gas: 131697) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 605694) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139540) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13970) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 145713) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 652059, ~: 658290) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129333) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162733) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 129499) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162855) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 133987) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129518) +BillboardTest:testCannotTransferByOperator() (gas: 134175) +BillboardTest:testCannotTransferToZeroAddress() (gas: 129706) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 935324, ~: 935324) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 771783, ~: 771783) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 647088, ~: 647088) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 420082) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 741996, ~: 741996) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 935690, ~: 935690) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 772282, ~: 772282) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 647468, ~: 647468) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 420497) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 742287, ~: 742287) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 650374) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2880898, ~: 1456587) -BillboardTest:testGetTokenURI() (gas: 156380) -BillboardTest:testMintBoard() (gas: 225615) -BillboardTest:testMintBoardByWhitelist() (gas: 157649) -BillboardTest:testMintBoardIfOpened() (gas: 130663) -BillboardTest:testPlaceBidByWhitelist() (gas: 473122) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937696) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 487592, ~: 498469) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 767470, ~: 774544) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 765287, ~: 776963) -BillboardTest:testPlaceBidZeroPrice() (gas: 358655) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 650687) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2814114, ~: 1451611) +BillboardTest:testGetTokenURI() (gas: 156524) +BillboardTest:testMintBoard() (gas: 225991) +BillboardTest:testMintBoardByWhitelist() (gas: 157825) +BillboardTest:testMintBoardIfOpened() (gas: 130863) +BillboardTest:testPlaceBidByWhitelist() (gas: 473253) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 938084) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 488033, ~: 498752) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 767947, ~: 775021) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 765873, ~: 777549) +BillboardTest:testPlaceBidZeroPrice() (gas: 358961) BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 142409) -BillboardTest:testSetBoardProperties() (gas: 308843) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 339408) +BillboardTest:testSafeTransferByOperator() (gas: 142575) +BillboardTest:testSetBoardProperties() (gas: 308855) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 339487) BillboardTest:testSetIsOpened() (gas: 15932) -BillboardTest:testSetTaxRate() (gas: 27307) -BillboardTest:testUpgradeRegistry() (gas: 2592983) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935985, ~: 935985) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 510679, ~: 510679) +BillboardTest:testSetTaxRate() (gas: 27263) +BillboardTest:testUpgradeRegistry() (gas: 2590942) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 936329, ~: 936329) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 510766, ~: 510766) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index c8ee82e..c26e093 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -39,7 +39,7 @@ contract Billboard is IBillboard { } modifier isFromWhitelist() { - if (whitelist[msg.sender] != true) { + if (!whitelist[msg.sender]) { revert Unauthorized("whitelist"); } _; @@ -94,7 +94,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external returns (uint256 tokenId) { - if (isOpened || whitelist[msg.sender] == true) { + if (isOpened || whitelist[msg.sender]) { tokenId = registry.mintBoard(to_); } else { revert Unauthorized("whitelist"); @@ -140,7 +140,7 @@ contract Billboard is IBillboard { uint256 tokenId_, uint256 auctionId_ ) external view returns (IBillboardRegistry.Auction memory auction) { - return registry.getAuction(tokenId_, auctionId_); + auction = registry.getAuction(tokenId_, auctionId_); } /// @inheritdoc IBillboard diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 040d234..083695d 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -12,7 +12,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // access control address public operator; - Counters.Counter private _tokenIds; + Counters.Counter public lastTokenId; uint256 public taxRate; uint64 public leaseTerm = 14 days; @@ -70,8 +70,8 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function mintBoard(address to_) external isFromOperator returns (uint256 tokenId) { - _tokenIds.increment(); - tokenId = _tokenIds.current(); + lastTokenId.increment(); + tokenId = lastTokenId.current(); _safeMint(to_, tokenId); @@ -83,9 +83,6 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { contentURI: "", redirectURI: "" }); - - // TODO - // emit Mint(newBoardId, to_); } /// @inheritdoc IBillboardRegistry From 4d13fcb55ace35bca45e9942c9a9d2ee683ce0d4 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:42:23 +0800 Subject: [PATCH 46/55] feat(billboard): add clearAuctions --- .gas-snapshot | 77 +++++++++++----------- src/Billboard/Billboard.sol | 7 ++ src/Billboard/IBillboard.sol | 7 ++ src/test/Billboard/BillboardTest.t.sol | 74 +++++++++++++++++++++ src/test/Billboard/BillboardTestBase.t.sol | 1 - 5 files changed, 127 insertions(+), 39 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 8121701..d6eedf7 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -9,53 +9,54 @@ ACLManagerTest:testGrantRole() (gas: 23547) ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) -BillboardTest:testAddToWhitelist() (gas: 37249) -BillboardTest:testApproveAndTransfer() (gas: 164045) +BillboardTest:testAddToWhitelist() (gas: 37205) +BillboardTest:testApproveAndTransfer() (gas: 162759) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 424231, ~: 437543) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 389746) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 420946, ~: 434258) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386461) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 131697) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 605694) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 139540) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13970) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 145713) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 652059, ~: 658290) -BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11883) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 129499) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 162855) +BillboardTest:testCannotApproveByAttacker() (gas: 130412) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604409) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136255) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13993) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 142428) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650773, ~: 657004) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11861) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 128214) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 159548) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 134175) -BillboardTest:testCannotTransferToZeroAddress() (gas: 129706) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11862) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 935690, ~: 935690) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 772282, ~: 772282) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 647468, ~: 647468) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 420497) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 742287, ~: 742287) +BillboardTest:testCannotTransferByOperator() (gas: 132890) +BillboardTest:testCannotTransferToZeroAddress() (gas: 128377) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11885) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934384, ~: 934384) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 770975, ~: 770975) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 646138, ~: 646138) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419189) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 740936, ~: 740936) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 650687) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2814114, ~: 1451611) -BillboardTest:testGetTokenURI() (gas: 156524) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649435) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1205928) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2877775, ~: 1456013) +BillboardTest:testGetTokenURI() (gas: 155305) BillboardTest:testMintBoard() (gas: 225991) BillboardTest:testMintBoardByWhitelist() (gas: 157825) BillboardTest:testMintBoardIfOpened() (gas: 130863) -BillboardTest:testPlaceBidByWhitelist() (gas: 473253) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 938084) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 488033, ~: 498752) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 767947, ~: 775021) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 765873, ~: 777549) -BillboardTest:testPlaceBidZeroPrice() (gas: 358961) -BillboardTest:testRemoveToWhitelist() (gas: 24992) -BillboardTest:testSafeTransferByOperator() (gas: 142575) -BillboardTest:testSetBoardProperties() (gas: 308855) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 339487) -BillboardTest:testSetIsOpened() (gas: 15932) +BillboardTest:testPlaceBidByWhitelist() (gas: 469968) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 936799) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 486781, ~: 497500) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766505, ~: 773735) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764587, ~: 776263) +BillboardTest:testPlaceBidZeroPrice() (gas: 357676) +BillboardTest:testRemoveToWhitelist() (gas: 24939) +BillboardTest:testSafeTransferByOperator() (gas: 141290) +BillboardTest:testSetBoardProperties() (gas: 305548) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 338157) +BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testUpgradeRegistry() (gas: 2590942) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 936329, ~: 936329) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 510766, ~: 510766) +BillboardTest:testUpgradeRegistry() (gas: 2637423) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935022, ~: 935022) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509481, ~: 509481) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index c26e093..d813c76 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -168,6 +168,13 @@ contract Billboard is IBillboard { _clearAuction(tokenId_, _boardCreator, _nextAuctionId); } + /// @inheritdoc IBillboard + function clearAuctions(uint256[] calldata tokenIds_) external { + for (uint256 i = 0; i < tokenIds_.length; i++) { + clearAuction(tokenIds_[i]); + } + } + function _clearAuction(uint256 tokenId_, address boardCreator_, uint256 nextAuctionId_) private { IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, nextAuctionId_); IBillboardRegistry.Bid memory _highestBid = registry.getBid( diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index eec6db5..72b4f8c 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -142,6 +142,13 @@ interface IBillboard { */ function clearAuction(uint256 tokenId_) external; + /** + * @notice Clear the next auction of mutiple boards. + * + * @param tokenIds_ Token IDs of boards. + */ + function clearAuctions(uint256[] calldata tokenIds_) external; + /** * @notice Place bid for the next auction of a board. * diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 36dacf3..23fdabf 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -623,6 +623,80 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.isWithdrawn, false); } + function testClearAuctionsIfAuctionEnded() public { + (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); + (uint256 _tokenId2, uint256 _prevAuctionId2) = _mintBoardAndPlaceBid(); + + uint64 _placedAt = uint64(block.timestamp); + uint64 _clearedAt = uint64(block.timestamp) + registry.leaseTerm() + 1 minutes; + + // place bids + vm.startPrank(USER_A); + vm.deal(USER_A, 0); + operator.placeBid{value: 0}(_tokenId, 0); + + vm.startPrank(USER_B); + vm.deal(USER_B, 0); + operator.placeBid{value: 0}(_tokenId2, 0); + + // clear auction + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId, + _prevAuctionId + 1, + USER_A, + _clearedAt, + _clearedAt + registry.leaseTerm() + ); + vm.expectEmit(true, true, true, true); + emit IBillboardRegistry.AuctionCleared( + _tokenId2, + _prevAuctionId2 + 1, + USER_B, + _clearedAt, + _clearedAt + registry.leaseTerm() + ); + + vm.warp(_clearedAt); + + uint256[] memory _tokenIds = new uint256[](2); + _tokenIds[0] = _tokenId; + _tokenIds[1] = _tokenId2; + operator.clearAuctions(_tokenIds); + + // check auction + uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); + IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); + assertEq(_auction.startAt, _placedAt); + assertEq(_auction.endAt, _placedAt + registry.leaseTerm()); + assertEq(_auction.leaseStartAt, _clearedAt); + assertEq(_auction.leaseEndAt, _clearedAt + registry.leaseTerm()); + assertEq(_auction.highestBidder, USER_A); + + uint256 _nextAuctionId2 = registry.nextBoardAuctionId(_tokenId2); + IBillboardRegistry.Auction memory _auction2 = registry.getAuction(_tokenId2, _nextAuctionId2); + assertEq(_auction2.startAt, _placedAt); + assertEq(_auction2.endAt, _placedAt + registry.leaseTerm()); + assertEq(_auction2.leaseStartAt, _clearedAt); + assertEq(_auction2.leaseEndAt, _clearedAt + registry.leaseTerm()); + assertEq(_auction2.highestBidder, USER_B); + + // check bid + IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); + assertEq(_bid.price, 0); + assertEq(_bid.tax, 0); + assertEq(_bid.placedAt, _placedAt); + assertEq(_bid.isWon, true); + assertEq(_bid.isWithdrawn, false); + + IBillboardRegistry.Bid memory _bid2 = registry.getBid(_tokenId2, _nextAuctionId2, USER_B); + assertEq(_bid2.price, 0); + assertEq(_bid2.tax, 0); + assertEq(_bid2.placedAt, _placedAt); + assertEq(_bid2.isWon, true); + assertEq(_bid2.isWithdrawn, false); + } + function testCannotClearAuctionOnNewBoard() public { uint256 _mintedAt = block.timestamp; uint256 _clearedAt = _mintedAt + 1; diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index 7a26dec..b866779 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -43,7 +43,6 @@ contract BillboardTestBase is Test { function _mintBoard() public returns (uint256 tokenId) { vm.prank(ADMIN); tokenId = operator.mintBoard(ADMIN); - assertEq(registry.balanceOf(ADMIN), 1); } function _mintBoardAndPlaceBid() public returns (uint256 tokenId, uint256 _nextAuctionId) { From 58ff978f48561a250ce3e11dcdbaa2b60f209428 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 22 Nov 2023 16:58:30 +0800 Subject: [PATCH 47/55] feat(billboard): refund overpaid on placeBid --- .gas-snapshot | 42 +++++++++++++------------- src/Billboard/Billboard.sol | 10 ++++++ src/test/Billboard/BillboardTest.t.sol | 5 +-- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index d6eedf7..a18c822 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -12,15 +12,15 @@ ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) BillboardTest:testApproveAndTransfer() (gas: 162759) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 420946, ~: 434258) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386461) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 421050, ~: 434362) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386565) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) BillboardTest:testCannotApproveByAttacker() (gas: 130412) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604409) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604617) BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136255) BillboardTest:testCannotMintBoardByAttacker() (gas: 13993) BillboardTest:testCannotPlaceBidByAttacker() (gas: 142428) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650773, ~: 657004) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650981, ~: 657212) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11861) BillboardTest:testCannotSafeTransferByAttacker() (gas: 128214) BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 159548) @@ -29,34 +29,34 @@ BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) BillboardTest:testCannotTransferByOperator() (gas: 132890) BillboardTest:testCannotTransferToZeroAddress() (gas: 128377) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11885) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934384, ~: 934384) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 770975, ~: 770975) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 646138, ~: 646138) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419189) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 740936, ~: 740936) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934696, ~: 934696) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 771287, ~: 771287) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 646346, ~: 646346) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419293) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 741144, ~: 741144) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649435) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1205928) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2877775, ~: 1456013) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649643) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1206344) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 3055023, ~: 1465106) BillboardTest:testGetTokenURI() (gas: 155305) BillboardTest:testMintBoard() (gas: 225991) BillboardTest:testMintBoardByWhitelist() (gas: 157825) BillboardTest:testMintBoardIfOpened() (gas: 130863) -BillboardTest:testPlaceBidByWhitelist() (gas: 469968) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 936799) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 486781, ~: 497500) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766505, ~: 773735) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764587, ~: 776263) -BillboardTest:testPlaceBidZeroPrice() (gas: 357676) +BillboardTest:testPlaceBidByWhitelist() (gas: 470072) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937111) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519199, ~: 529681) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766817, ~: 774047) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764899, ~: 776575) +BillboardTest:testPlaceBidZeroPrice() (gas: 357780) BillboardTest:testRemoveToWhitelist() (gas: 24939) BillboardTest:testSafeTransferByOperator() (gas: 141290) BillboardTest:testSetBoardProperties() (gas: 305548) BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 338157) BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testUpgradeRegistry() (gas: 2637423) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935022, ~: 935022) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509481, ~: 509481) +BillboardTest:testUpgradeRegistry() (gas: 2662891) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935334, ~: 935334) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509585, ~: 509585) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index d813c76..7878c13 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -259,10 +259,20 @@ contract Billboard is IBillboard { } function _lockBidPriceAndTax(uint256 amount_) private { + // transfer bid price and tax to the registry (bool _success, ) = address(registry).call{value: amount_}(""); if (!_success) { revert TransferFailed(); } + + // refund if overpaid + uint256 _overpaid = msg.value - amount_; + if (_overpaid > 0) { + (bool _refundSuccess, ) = msg.sender.call{value: _overpaid}(""); + if (!_refundSuccess) { + revert TransferFailed(); + } + } } /// @inheritdoc IBillboard diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 23fdabf..6a1dcf6 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -354,8 +354,9 @@ contract BillboardTest is BillboardTestBase { uint256 _tokenId = _mintBoard(); uint256 _tax = operator.calculateTax(_amount); + uint256 _overpaid = 0.1 ether; uint256 _total = _amount + _tax; - vm.deal(USER_A, _total); + vm.deal(USER_A, _total + _overpaid); uint256 _prevNextActionId = registry.nextBoardAuctionId(_tokenId); uint256 _prevCreatorBalance = ADMIN.balance; @@ -384,7 +385,7 @@ contract BillboardTest is BillboardTestBase { ); vm.prank(USER_A); - operator.placeBid{value: _total}(_tokenId, _amount); + operator.placeBid{value: _total + _overpaid}(_tokenId, _amount); // check balances assertEq(ADMIN.balance, _prevCreatorBalance + _amount); From 7e28b4b75cf439e5833489e9a64b62afbe5fbf41 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 22 Nov 2023 19:20:19 +0800 Subject: [PATCH 48/55] feat(ci): run test with gas report --- .gas-snapshot | 8 ++++---- .github/workflows/test.yml | 2 +- src/test/Billboard/BillboardTest.t.sol | 1 - 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index a18c822..c0d5a33 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -12,7 +12,7 @@ ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) BillboardTest:testApproveAndTransfer() (gas: 162759) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 421050, ~: 434362) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 420531, ~: 434362) BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386565) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) BillboardTest:testCannotApproveByAttacker() (gas: 130412) @@ -37,15 +37,15 @@ BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 741144, ~: 7411 BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649643) BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1206344) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 3055023, ~: 1465106) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2790498, ~: 1448206) BillboardTest:testGetTokenURI() (gas: 155305) BillboardTest:testMintBoard() (gas: 225991) BillboardTest:testMintBoardByWhitelist() (gas: 157825) BillboardTest:testMintBoardIfOpened() (gas: 130863) BillboardTest:testPlaceBidByWhitelist() (gas: 470072) BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937111) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519199, ~: 529681) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766817, ~: 774047) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519355, ~: 529681) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766973, ~: 774047) BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764899, ~: 776575) BillboardTest:testPlaceBidZeroPrice() (gas: 357780) BillboardTest:testRemoveToWhitelist() (gas: 24939) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f7f3cf5..9d98105 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,4 +34,4 @@ jobs: run: make build - name: Run tests - run: FOUNDRY_PROFILE=ci make test + run: FOUNDRY_PROFILE=ci make gas-report diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 6a1dcf6..211a9c0 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -753,7 +753,6 @@ contract BillboardTest is BillboardTestBase { // get bids uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); - console.log(_nextAuctionId); (uint256 _t, uint256 _l, uint256 _o, IBillboardRegistry.Bid[] memory _bids) = operator.getBids( _tokenId, _nextAuctionId, From ff9409abf1c022ac81d56ef96792a88888fecc90 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 23 Nov 2023 17:13:49 +0800 Subject: [PATCH 49/55] feat(billboard): use "require" instead of custom errors --- .gas-snapshot | 89 +++++++++++++------------- src/Billboard/Billboard.sol | 58 ++++++----------- src/Billboard/BillboardRegistry.sol | 8 +-- src/Billboard/IBillboard.sol | 20 ------ src/Billboard/IBillboardRegistry.sol | 8 --- src/test/Billboard/BillboardTest.t.sol | 86 +++++++++++++++---------- 6 files changed, 121 insertions(+), 148 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index c0d5a33..14d1ca4 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -10,53 +10,54 @@ ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) -BillboardTest:testApproveAndTransfer() (gas: 162759) +BillboardTest:testApproveAndTransfer() (gas: 162735) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 420531, ~: 434362) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 386565) -BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11794) -BillboardTest:testCannotApproveByAttacker() (gas: 130412) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604617) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136255) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13993) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 142428) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650981, ~: 657212) -BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11861) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 128214) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 159548) -BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11751) -BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11763) -BillboardTest:testCannotTransferByOperator() (gas: 132890) -BillboardTest:testCannotTransferToZeroAddress() (gas: 128377) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11885) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934696, ~: 934696) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 771287, ~: 771287) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 646346, ~: 646346) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419293) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 741144, ~: 741144) -BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21710) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649643) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1206344) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2790498, ~: 1448206) -BillboardTest:testGetTokenURI() (gas: 155305) -BillboardTest:testMintBoard() (gas: 225991) -BillboardTest:testMintBoardByWhitelist() (gas: 157825) -BillboardTest:testMintBoardIfOpened() (gas: 130863) -BillboardTest:testPlaceBidByWhitelist() (gas: 470072) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937111) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519355, ~: 529681) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766973, ~: 774047) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764899, ~: 776575) -BillboardTest:testPlaceBidZeroPrice() (gas: 357780) -BillboardTest:testRemoveToWhitelist() (gas: 24939) -BillboardTest:testSafeTransferByOperator() (gas: 141290) -BillboardTest:testSetBoardProperties() (gas: 305548) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 338157) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 419677, ~: 433681) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 385862) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11137) +BillboardTest:testCannotApproveByAttacker() (gas: 130388) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604134) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136029) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13332) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 141747) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650687, ~: 656918) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11204) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 127555) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 156298) +BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11094) +BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11106) +BillboardTest:testCannotTransferByOperator() (gas: 132888) +BillboardTest:testCannotTransferToZeroAddress() (gas: 128375) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11228) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934036, ~: 934036) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 770628, ~: 770628) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 645425, ~: 645425) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419086) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 740484, ~: 740484) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21053) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649619) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1206340) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2871675, ~: 1453869) +BillboardTest:testGetTokenURI() (gas: 155303) +BillboardTest:testMintBoard() (gas: 225987) +BillboardTest:testMintBoardByWhitelist() (gas: 157167) +BillboardTest:testMintBoardIfOpened() (gas: 130861) +BillboardTest:testPlaceBidByWhitelist() (gas: 470026) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937087) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519419, ~: 529745) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766815, ~: 774045) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764942, ~: 776618) +BillboardTest:testPlaceBidZeroPrice() (gas: 357801) +BillboardTest:testRemoveToWhitelist() (gas: 24957) +BillboardTest:testSafeTransferByOperator() (gas: 141354) +BillboardTest:testSetBoardProperties() (gas: 305524) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 334252) BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testUpgradeRegistry() (gas: 2662891) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935334, ~: 935334) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509585, ~: 509585) +BillboardTest:testSomethin() (gas: 1698254) +BillboardTest:testUpgradeRegistry() (gas: 2725063) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935332, ~: 935332) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509539, ~: 509539) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 7878c13..a08dd21 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -32,31 +32,23 @@ contract Billboard is IBillboard { ////////////////////////////// modifier isFromAdmin() { - if (msg.sender != admin) { - revert Unauthorized("admin"); - } + require(msg.sender == admin, "Admin"); _; } modifier isFromWhitelist() { - if (!whitelist[msg.sender]) { - revert Unauthorized("whitelist"); - } + require(whitelist[msg.sender], "Whitelist"); _; } modifier isFromBoardCreator(uint256 tokenId_) { (address _boardCreator, , , , , ) = registry.boards(tokenId_); - if (_boardCreator != msg.sender) { - revert Unauthorized("creator"); - } + require(_boardCreator == msg.sender, "Creator"); _; } modifier isFromBoardTenant(uint256 tokenId_) { - if (msg.sender != registry.ownerOf(tokenId_)) { - revert Unauthorized("tenant"); - } + require(msg.sender == registry.ownerOf(tokenId_), "Tenant"); _; } @@ -94,11 +86,9 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function mintBoard(address to_) external returns (uint256 tokenId) { - if (isOpened || whitelist[msg.sender]) { - tokenId = registry.mintBoard(to_); - } else { - revert Unauthorized("whitelist"); - } + require(isOpened || whitelist[msg.sender], "Whitelist"); + + tokenId = registry.mintBoard(to_); } /// @inheritdoc IBillboard @@ -147,16 +137,16 @@ contract Billboard is IBillboard { function clearAuction(uint256 tokenId_) public { // revert if board not found (address _boardCreator, , , , , ) = registry.boards(tokenId_); - if (_boardCreator == address(0)) revert BoardNotFound(); + require(_boardCreator != address(0), "Board not found"); // revert if it's a new board uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); - if (_nextAuctionId == 0) revert AuctionNotFound(); + require(_nextAuctionId != 0, "Auction not found"); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); // revert if auction is still running - if (block.timestamp < _nextAuction.endAt) revert AuctionNotEnded(); + require(block.timestamp >= _nextAuction.endAt, "Auction not ended"); // reclaim ownership to board creator if no auction address _prevOwner = registry.ownerOf(tokenId_); @@ -211,7 +201,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external payable isFromWhitelist { (address _boardCreator, , , , , ) = registry.boards(tokenId_); - if (_boardCreator == address(0)) revert BoardNotFound(); + require(_boardCreator != address(0), "Board not found"); uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); @@ -236,9 +226,7 @@ contract Billboard is IBillboard { // if next auction is not ended, // push new bid to next auction else { - if (registry.getBid(tokenId_, _nextAuctionId, msg.sender).placedAt != 0) { - revert BidAlreadyPlaced(); - } + require(registry.getBid(tokenId_, _nextAuctionId, msg.sender).placedAt == 0, "Bid already placed"); uint256 _tax = calculateTax(amount_); registry.newBid(tokenId_, _nextAuctionId, msg.sender, amount_, _tax); @@ -261,17 +249,13 @@ contract Billboard is IBillboard { function _lockBidPriceAndTax(uint256 amount_) private { // transfer bid price and tax to the registry (bool _success, ) = address(registry).call{value: amount_}(""); - if (!_success) { - revert TransferFailed(); - } + require(_success, "Transfer failed"); // refund if overpaid uint256 _overpaid = msg.value - amount_; if (_overpaid > 0) { (bool _refundSuccess, ) = msg.sender.call{value: _overpaid}(""); - if (!_refundSuccess) { - revert TransferFailed(); - } + require(_refundSuccess, "Transfer failed"); } } @@ -338,7 +322,7 @@ contract Billboard is IBillboard { uint256 amount = _taxAccumulated - _taxWithdrawn; - if (amount <= 0) revert WithdrawFailed("zero amount"); + require(amount > 0, "Zero amount"); // transfer tax to the owner registry.transferAmount(msg.sender, amount); @@ -354,18 +338,18 @@ contract Billboard is IBillboard { function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { // revert if auction is still running IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId_, auctionId_); - if (block.timestamp < _auction.endAt) revert AuctionNotEnded(); + require(block.timestamp >= _auction.endAt, "Auction not ended"); // revert if auction is not cleared - if (_auction.leaseEndAt == 0) revert WithdrawFailed("auction not cleared"); + require(_auction.leaseEndAt != 0, "Auction not cleared"); IBillboardRegistry.Bid memory _bid = registry.getBid(tokenId_, auctionId_, msg.sender); uint256 amount = _bid.price + _bid.tax; - if (_bid.placedAt == 0) revert BidNotFound(); - if (_bid.isWithdrawn) revert WithdrawFailed("withdrawn"); - if (_bid.isWon) revert WithdrawFailed("won"); - if (amount <= 0) revert WithdrawFailed("zero amount"); + require(_bid.placedAt != 0, "Bid not found"); + require(!_bid.isWithdrawn, "Bid already withdrawn"); + require(!_bid.isWon, "Bid already won"); + require(amount > 0, "Zero amount"); // transfer bid price and tax back to the bidder registry.transferAmount(msg.sender, amount); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 083695d..9f6ff02 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -50,9 +50,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { ////////////////////////////// modifier isFromOperator() { - if (msg.sender != operator) { - revert Unauthorized("operator"); - } + require(msg.sender == operator, "Operator"); _; } @@ -224,9 +222,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function transferAmount(address to_, uint256 amount_) external isFromOperator { (bool _success, ) = to_.call{value: amount_}(""); - if (!_success) { - revert TransferFailed(); - } + require(_success, "transfer failed"); } ////////////////////////////// diff --git a/src/Billboard/IBillboard.sol b/src/Billboard/IBillboard.sol index 72b4f8c..ad44fd1 100644 --- a/src/Billboard/IBillboard.sol +++ b/src/Billboard/IBillboard.sol @@ -4,26 +4,6 @@ pragma solidity ^0.8.20; import "./IBillboardRegistry.sol"; interface IBillboard { - ////////////////////////////// - /// Error - ////////////////////////////// - - error Unauthorized(string reason_); - - error BoardNotFound(); - - error AuctionNotFound(); - - error AuctionNotEnded(); - - error BidNotFound(); - - error BidAlreadyPlaced(); - - error WithdrawFailed(string reason_); - - error TransferFailed(); - ////////////////////////////// /// Upgradability ////////////////////////////// diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index b5a04f4..7143428 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -4,14 +4,6 @@ pragma solidity ^0.8.20; import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; interface IBillboardRegistry is IERC721 { - ////////////////////////////// - /// Error - ////////////////////////////// - - error Unauthorized(string type_); - - error TransferFailed(); - ////////////////////////////// /// Event ////////////////////////////// diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 211a9c0..556005d 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -27,7 +27,7 @@ contract BillboardTest is BillboardTestBase { function testCannotUpgradeRegistryByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + vm.expectRevert("Admin"); operator.setRegistryOperator(FAKE_CONTRACT); } @@ -48,7 +48,7 @@ contract BillboardTest is BillboardTestBase { function testCannotSetIsOpenedByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + vm.expectRevert("Admin"); operator.setIsOpened(true); } @@ -63,7 +63,7 @@ contract BillboardTest is BillboardTestBase { function testCannotAddToWhitelistByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + vm.expectRevert("Admin"); operator.addToWhitelist(USER_A); } @@ -80,7 +80,7 @@ contract BillboardTest is BillboardTestBase { function testCannotRemoveToWhitelistByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + vm.expectRevert("Admin"); operator.removeFromWhitelist(USER_B); } @@ -129,7 +129,7 @@ contract BillboardTest is BillboardTestBase { function testMintBoardByWhitelist() public { vm.prank(USER_A); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + vm.expectRevert("Whitelist"); operator.mintBoard(USER_A); vm.prank(ADMIN); @@ -143,7 +143,7 @@ contract BillboardTest is BillboardTestBase { function testCannotMintBoardByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + vm.expectRevert("Whitelist"); operator.mintBoard(ATTACKER); } @@ -185,19 +185,19 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardName(_tokenId, "name"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardDescription(_tokenId, "description"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardLocation(_tokenId, "location"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "tenant")); + vm.expectRevert("Tenant"); operator.setBoardContentURI(_tokenId, "uri"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "tenant")); + vm.expectRevert("Tenant"); operator.setBoardRedirectURI(_tokenId, "redirect URI"); } @@ -227,13 +227,13 @@ contract BillboardTest is BillboardTestBase { vm.stopPrank(); vm.startPrank(USER_A); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardName(_tokenId, "name by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardDescription(_tokenId, "description by a"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardLocation(_tokenId, "location by a"); operator.setBoardContentURI(_tokenId, "uri by a"); @@ -255,13 +255,13 @@ contract BillboardTest is BillboardTestBase { vm.stopPrank(); vm.startPrank(USER_B); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardName(_tokenId, "name by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardDescription(_tokenId, "description by b"); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "creator")); + vm.expectRevert("Creator"); operator.setBoardLocation(_tokenId, "location by b"); operator.setBoardContentURI(_tokenId, "uri by b"); @@ -309,7 +309,7 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "operator")); + vm.expectRevert("Operator"); registry.safeTransferByOperator(ADMIN, ATTACKER, _tokenId); } @@ -413,6 +413,26 @@ contract BillboardTest is BillboardTestBase { assertEq(_bid.isWithdrawn, false); } + function testSomethin() public { + (uint256 _tokenId, ) = _mintBoardAndPlaceBid(); + (uint256 _tokenId2, ) = _mintBoardAndPlaceBid(); + (uint256 _tokenId3, ) = _mintBoardAndPlaceBid(); + + vm.startPrank(USER_A); + operator.placeBid{value: 0}(_tokenId, 0); + operator.placeBid{value: 0}(_tokenId2, 0); + + vm.startPrank(USER_B); + operator.placeBid{value: 0}(_tokenId3, 0); + + vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + uint256[] memory _tokenIds = new uint256[](3); + _tokenIds[0] = _tokenId; + _tokenIds[1] = _tokenId2; + _tokenIds[2] = _tokenId3; + operator.clearAuctions(_tokenIds); + } + function testPlaceBidWithSamePrices(uint96 _amount) public { (uint256 _tokenId, uint256 _prevNextAuctionId) = _mintBoardAndPlaceBid(); uint256 _tax = operator.calculateTax(_amount); @@ -567,7 +587,7 @@ contract BillboardTest is BillboardTestBase { assertEq(USER_A.balance, 0); vm.deal(USER_A, _total); - vm.expectRevert(abi.encodeWithSignature("BidAlreadyPlaced()")); + vm.expectRevert("Bid already placed"); operator.placeBid{value: _total}(_tokenId, _amount); } @@ -579,7 +599,7 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ATTACKER); vm.deal(ATTACKER, _total); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "whitelist")); + vm.expectRevert("Whitelist"); operator.placeBid{value: _total}(_tokenId, _amount); } @@ -707,7 +727,7 @@ contract BillboardTest is BillboardTestBase { // clear auction vm.warp(_clearedAt); - vm.expectRevert(abi.encodeWithSignature("AuctionNotFound()")); + vm.expectRevert("Auction not found"); operator.clearAuction(_tokenId); } @@ -720,11 +740,11 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: 0}(_tokenId, 0); // try to clear auction - vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + vm.expectRevert("Auction not ended"); operator.clearAuction(_tokenId); vm.warp(block.timestamp + registry.leaseTerm() - 1 seconds); - vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + vm.expectRevert("Auction not ended"); operator.clearAuction(_tokenId); } @@ -799,7 +819,7 @@ contract BillboardTest is BillboardTestBase { function testCannotSetTaxRateByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("Unauthorized(string)", "admin")); + vm.expectRevert("Admin"); operator.setTaxRate(2); } @@ -845,7 +865,7 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: 0}(_tokenId, 0); vm.prank(ADMIN); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + vm.expectRevert("Zero amount"); operator.withdrawTax(); } @@ -864,14 +884,14 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _amount}(_tokenId, _amount); vm.prank(ADMIN); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + vm.expectRevert("Zero amount"); operator.withdrawTax(); } function testCannotWithdrawTaxByAttacker() public { vm.startPrank(ATTACKER); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "zero amount")); + vm.expectRevert("Zero amount"); operator.withdrawTax(); } @@ -949,7 +969,7 @@ contract BillboardTest is BillboardTestBase { // withdraw bid again vm.prank(USER_B); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "withdrawn")); + vm.expectRevert("Bid already withdrawn"); operator.withdrawBid(_tokenId, _nextAuctionId); } @@ -976,7 +996,7 @@ contract BillboardTest is BillboardTestBase { // withdraw bid vm.prank(USER_A); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "won")); + vm.expectRevert("Bid already won"); operator.withdrawBid(_tokenId, _nextAuctionId); } @@ -994,12 +1014,12 @@ contract BillboardTest is BillboardTestBase { // auction is not ended uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); - vm.expectRevert(abi.encodeWithSignature("AuctionNotEnded()")); + vm.expectRevert("Auction not ended"); operator.withdrawBid(_tokenId, _nextAuctionId); // auction is ended but not cleared vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "auction not cleared")); + vm.expectRevert("Auction not cleared"); operator.withdrawBid(_tokenId, _nextAuctionId); } @@ -1024,7 +1044,7 @@ contract BillboardTest is BillboardTestBase { uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); vm.prank(USER_B); - vm.expectRevert(abi.encodeWithSignature("WithdrawFailed(string)", "auction not cleared")); + vm.expectRevert("Auction not cleared"); operator.withdrawBid(_tokenId, _nextAuctionId); } @@ -1033,7 +1053,7 @@ contract BillboardTest is BillboardTestBase { uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); vm.prank(USER_A); - vm.expectRevert(abi.encodeWithSignature("BidNotFound()")); + vm.expectRevert("Bid not found"); operator.withdrawBid(_tokenId, _nextAuctionId); } } From e2975f11fae6c22711ab168c341d2b74c56f96df Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Thu, 23 Nov 2023 19:12:58 +0800 Subject: [PATCH 50/55] feat(billboard): skip if auction is already cleared --- .gas-snapshot | 44 ++++++++++++++++++------------------- src/Billboard/Billboard.sol | 9 +++++++- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 14d1ca4..e867790 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -12,15 +12,15 @@ ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) BillboardTest:testApproveAndTransfer() (gas: 162735) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 419677, ~: 433681) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 385862) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 419891, ~: 433722) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 385903) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11137) BillboardTest:testCannotApproveByAttacker() (gas: 130388) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 604134) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 585072) BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136029) BillboardTest:testCannotMintBoardByAttacker() (gas: 13332) BillboardTest:testCannotPlaceBidByAttacker() (gas: 141747) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 650687, ~: 656918) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 631625, ~: 637856) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11204) BillboardTest:testCannotSafeTransferByAttacker() (gas: 127555) BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 156298) @@ -29,35 +29,35 @@ BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11106) BillboardTest:testCannotTransferByOperator() (gas: 132888) BillboardTest:testCannotTransferToZeroAddress() (gas: 128375) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11228) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 934036, ~: 934036) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 770628, ~: 770628) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 645425, ~: 645425) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419086) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 740484, ~: 740484) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 915015, ~: 915015) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 751566, ~: 751566) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 626363, ~: 626363) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419127) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 721463, ~: 721463) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21053) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 649619) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1206340) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2871675, ~: 1453869) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 630598) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1168298) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2724918, ~: 1356638) BillboardTest:testGetTokenURI() (gas: 155303) BillboardTest:testMintBoard() (gas: 225987) BillboardTest:testMintBoardByWhitelist() (gas: 157167) BillboardTest:testMintBoardIfOpened() (gas: 130861) -BillboardTest:testPlaceBidByWhitelist() (gas: 470026) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 937087) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519419, ~: 529745) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 766815, ~: 774045) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 764942, ~: 776618) -BillboardTest:testPlaceBidZeroPrice() (gas: 357801) +BillboardTest:testPlaceBidByWhitelist() (gas: 470067) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 918066) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519460, ~: 529786) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 747753, ~: 754983) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 745880, ~: 757556) +BillboardTest:testPlaceBidZeroPrice() (gas: 357842) BillboardTest:testRemoveToWhitelist() (gas: 24957) BillboardTest:testSafeTransferByOperator() (gas: 141354) BillboardTest:testSetBoardProperties() (gas: 305524) BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 334252) BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testSomethin() (gas: 1698254) -BillboardTest:testUpgradeRegistry() (gas: 2725063) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 935332, ~: 935332) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509539, ~: 509539) +BillboardTest:testSomethin() (gas: 1641191) +BillboardTest:testUpgradeRegistry() (gas: 2729870) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 916311, ~: 916311) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509580, ~: 509580) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index a08dd21..0d69c9f 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -167,13 +167,20 @@ contract Billboard is IBillboard { function _clearAuction(uint256 tokenId_, address boardCreator_, uint256 nextAuctionId_) private { IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, nextAuctionId_); + + // skip if auction is already cleared + if (_nextAuction.leaseEndAt != 0) { + return; + } + + address _prevOwner = registry.ownerOf(tokenId_); + IBillboardRegistry.Bid memory _highestBid = registry.getBid( tokenId_, nextAuctionId_, _nextAuction.highestBidder ); - address _prevOwner = registry.ownerOf(tokenId_); if (_highestBid.price > 0) { // transfer bid price to board owner (previous tenant or creator) registry.transferAmount(_prevOwner, _highestBid.price); From a346b1f0bc39428afb0739828444594266a07889 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:44:29 +0800 Subject: [PATCH 51/55] feat(billboard): remove unused TaxTreasury.owner --- .gas-snapshot | 26 +++++++++++++------------- src/Billboard/Billboard.sol | 4 ++-- src/Billboard/IBillboardRegistry.sol | 1 - 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index e867790..1aa269d 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -12,8 +12,8 @@ ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) BillboardTest:testApproveAndTransfer() (gas: 162735) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 419891, ~: 433722) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 385903) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 417758, ~: 431155) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 383624) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11137) BillboardTest:testCannotApproveByAttacker() (gas: 130388) BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 585072) @@ -29,23 +29,23 @@ BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11106) BillboardTest:testCannotTransferByOperator() (gas: 132888) BillboardTest:testCannotTransferToZeroAddress() (gas: 128375) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11228) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 915015, ~: 915015) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 912727, ~: 912727) BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 751566, ~: 751566) BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 626363, ~: 626363) BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419127) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 721463, ~: 721463) -BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 21053) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 719175, ~: 719175) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 18774) BillboardTest:testClearAuctionIfAuctionEnded() (gas: 630598) BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1168298) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2724918, ~: 1356638) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2888923, ~: 1434807) BillboardTest:testGetTokenURI() (gas: 155303) BillboardTest:testMintBoard() (gas: 225987) BillboardTest:testMintBoardByWhitelist() (gas: 157167) BillboardTest:testMintBoardIfOpened() (gas: 130861) -BillboardTest:testPlaceBidByWhitelist() (gas: 470067) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 918066) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 519460, ~: 529786) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 747753, ~: 754983) +BillboardTest:testPlaceBidByWhitelist() (gas: 467779) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 915778) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 517306, ~: 527498) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 747909, ~: 754983) BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 745880, ~: 757556) BillboardTest:testPlaceBidZeroPrice() (gas: 357842) BillboardTest:testRemoveToWhitelist() (gas: 24957) @@ -55,9 +55,9 @@ BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 334252) BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) BillboardTest:testSomethin() (gas: 1641191) -BillboardTest:testUpgradeRegistry() (gas: 2729870) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 916311, ~: 916311) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 509580, ~: 509580) +BillboardTest:testUpgradeRegistry() (gas: 2725044) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 914023, ~: 914023) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 507001, ~: 507001) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 0d69c9f..4f2cd1b 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -186,7 +186,7 @@ contract Billboard is IBillboard { registry.transferAmount(_prevOwner, _highestBid.price); // transfer bid tax to board creator's tax treasury - (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(boardCreator_); + (uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(boardCreator_); registry.setTaxTreasury(boardCreator_, _taxAccumulated + _highestBid.tax, _taxWithdrawn); } @@ -325,7 +325,7 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function withdrawTax() external { - (, uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(msg.sender); + (uint256 _taxAccumulated, uint256 _taxWithdrawn) = registry.taxTreasury(msg.sender); uint256 amount = _taxAccumulated - _taxWithdrawn; diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 7143428..a6a1778 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -163,7 +163,6 @@ interface IBillboardRegistry is IERC721 { } struct TaxTreasury { - address owner; uint256 accumulated; uint256 withdrawn; } From 292835ae5586ca7f56d3a05922dd7fd7faebf760 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:48:37 +0800 Subject: [PATCH 52/55] feat(billboard): use getBoard instead of destructing --- .gas-snapshot | 52 ++++++++++++++++++------------------- src/Billboard/Billboard.sol | 22 ++++++++-------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index 1aa269d..f6dd653 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -12,52 +12,52 @@ ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 37205) BillboardTest:testApproveAndTransfer() (gas: 162735) BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 417758, ~: 431155) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 383624) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 418314, ~: 431711) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 384181) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11137) BillboardTest:testCannotApproveByAttacker() (gas: 130388) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 585072) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136029) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 587279) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136576) BillboardTest:testCannotMintBoardByAttacker() (gas: 13332) BillboardTest:testCannotPlaceBidByAttacker() (gas: 141747) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 631625, ~: 637856) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 633286, ~: 639517) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11204) BillboardTest:testCannotSafeTransferByAttacker() (gas: 127555) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 156298) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 157909) BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11094) BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11106) BillboardTest:testCannotTransferByOperator() (gas: 132888) BillboardTest:testCannotTransferToZeroAddress() (gas: 128375) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11228) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 912727, ~: 912727) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 751566, ~: 751566) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 626363, ~: 626363) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419127) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 719175, ~: 719175) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 914945, ~: 914945) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 753227, ~: 753227) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 627476, ~: 627476) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419684) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 720845, ~: 720845) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 18774) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 630598) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1168298) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2888923, ~: 1434807) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 632267) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1171641) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2900467, ~: 1438660) BillboardTest:testGetTokenURI() (gas: 155303) BillboardTest:testMintBoard() (gas: 225987) BillboardTest:testMintBoardByWhitelist() (gas: 157167) BillboardTest:testMintBoardIfOpened() (gas: 130861) -BillboardTest:testPlaceBidByWhitelist() (gas: 467779) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 915778) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 517306, ~: 527498) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 747909, ~: 754983) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 745880, ~: 757556) -BillboardTest:testPlaceBidZeroPrice() (gas: 357842) +BillboardTest:testPlaceBidByWhitelist() (gas: 468335) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 917448) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 517862, ~: 528054) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 749336, ~: 756644) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 747541, ~: 759217) +BillboardTest:testPlaceBidZeroPrice() (gas: 358399) BillboardTest:testRemoveToWhitelist() (gas: 24957) BillboardTest:testSafeTransferByOperator() (gas: 141354) -BillboardTest:testSetBoardProperties() (gas: 305524) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 334252) +BillboardTest:testSetBoardProperties() (gas: 307136) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337474) BillboardTest:testSetIsOpened() (gas: 15978) BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testSomethin() (gas: 1641191) -BillboardTest:testUpgradeRegistry() (gas: 2725044) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 914023, ~: 914023) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 507001, ~: 507001) +BillboardTest:testSomethin() (gas: 1646208) +BillboardTest:testUpgradeRegistry() (gas: 2672107) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 916241, ~: 916241) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 507557, ~: 507557) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 4f2cd1b..80cb9d9 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -42,8 +42,8 @@ contract Billboard is IBillboard { } modifier isFromBoardCreator(uint256 tokenId_) { - (address _boardCreator, , , , , ) = registry.boards(tokenId_); - require(_boardCreator == msg.sender, "Creator"); + IBillboardRegistry.Board memory _board = registry.getBoard(tokenId_); + require(_board.creator == msg.sender, "Creator"); _; } @@ -136,8 +136,8 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function clearAuction(uint256 tokenId_) public { // revert if board not found - (address _boardCreator, , , , , ) = registry.boards(tokenId_); - require(_boardCreator != address(0), "Board not found"); + IBillboardRegistry.Board memory _board = registry.getBoard(tokenId_); + require(_board.creator != address(0), "Board not found"); // revert if it's a new board uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); @@ -150,12 +150,12 @@ contract Billboard is IBillboard { // reclaim ownership to board creator if no auction address _prevOwner = registry.ownerOf(tokenId_); - if (_nextAuction.startAt == 0 && _prevOwner != _boardCreator) { - registry.safeTransferByOperator(_prevOwner, _boardCreator, tokenId_); + if (_nextAuction.startAt == 0 && _prevOwner != _board.creator) { + registry.safeTransferByOperator(_prevOwner, _board.creator, tokenId_); return; } - _clearAuction(tokenId_, _boardCreator, _nextAuctionId); + _clearAuction(tokenId_, _board.creator, _nextAuctionId); } /// @inheritdoc IBillboard @@ -207,8 +207,8 @@ contract Billboard is IBillboard { /// @inheritdoc IBillboard function placeBid(uint256 tokenId_, uint256 amount_) external payable isFromWhitelist { - (address _boardCreator, , , , , ) = registry.boards(tokenId_); - require(_boardCreator != address(0), "Board not found"); + IBillboardRegistry.Board memory _board = registry.getBoard(tokenId_); + require(_board.creator != address(0), "Board not found"); uint256 _nextAuctionId = registry.nextBoardAuctionId(tokenId_); IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); @@ -218,7 +218,7 @@ contract Billboard is IBillboard { // then clear auction and transfer ownership to the bidder immediately. if (_nextAuction.startAt == 0) { uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp)); - _clearAuction(tokenId_, _boardCreator, _auctionId); + _clearAuction(tokenId_, _board.creator, _auctionId); return; } @@ -226,7 +226,7 @@ contract Billboard is IBillboard { // clear auction first, // then create new auction and new bid if (block.timestamp >= _nextAuction.endAt) { - _clearAuction(tokenId_, _boardCreator, _nextAuctionId); + _clearAuction(tokenId_, _board.creator, _nextAuctionId); _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp + registry.leaseTerm())); return; } From 363c16b3b7f0a9becc45ab896c79d18429ffa9a4 Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:53:19 +0800 Subject: [PATCH 53/55] feat(billboard): mtigate securiry risks --- .gas-snapshot | 98 ++++++++++++++-------------- src/Billboard/Billboard.sol | 7 +- src/Billboard/BillboardRegistry.sol | 8 ++- src/Billboard/IBillboardRegistry.sol | 5 ++ 4 files changed, 64 insertions(+), 54 deletions(-) diff --git a/.gas-snapshot b/.gas-snapshot index f6dd653..43d756e 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -9,55 +9,55 @@ ACLManagerTest:testGrantRole() (gas: 23547) ACLManagerTest:testRenounceRole() (gas: 27841) ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) -BillboardTest:testAddToWhitelist() (gas: 37205) -BillboardTest:testApproveAndTransfer() (gas: 162735) -BillboardTest:testCalculateTax() (gas: 29439) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 418314, ~: 431711) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 384181) -BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 11137) -BillboardTest:testCannotApproveByAttacker() (gas: 130388) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 587279) -BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136576) -BillboardTest:testCannotMintBoardByAttacker() (gas: 13332) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 141747) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 633286, ~: 639517) -BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 11204) -BillboardTest:testCannotSafeTransferByAttacker() (gas: 127555) -BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 157909) -BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 11094) -BillboardTest:testCannotSetTaxRateByAttacker() (gas: 11106) -BillboardTest:testCannotTransferByOperator() (gas: 132888) -BillboardTest:testCannotTransferToZeroAddress() (gas: 128375) -BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 11228) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 914945, ~: 914945) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 753227, ~: 753227) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 627476, ~: 627476) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 419684) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 720845, ~: 720845) -BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 18774) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 632267) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1171641) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2900467, ~: 1438660) -BillboardTest:testGetTokenURI() (gas: 155303) -BillboardTest:testMintBoard() (gas: 225987) -BillboardTest:testMintBoardByWhitelist() (gas: 157167) -BillboardTest:testMintBoardIfOpened() (gas: 130861) -BillboardTest:testPlaceBidByWhitelist() (gas: 468335) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 917448) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 517862, ~: 528054) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 749336, ~: 756644) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 747541, ~: 759217) -BillboardTest:testPlaceBidZeroPrice() (gas: 358399) -BillboardTest:testRemoveToWhitelist() (gas: 24957) -BillboardTest:testSafeTransferByOperator() (gas: 141354) -BillboardTest:testSetBoardProperties() (gas: 307136) -BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 337474) -BillboardTest:testSetIsOpened() (gas: 15978) -BillboardTest:testSetTaxRate() (gas: 27263) -BillboardTest:testSomethin() (gas: 1646208) -BillboardTest:testUpgradeRegistry() (gas: 2672107) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 916241, ~: 916241) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 507557, ~: 507557) +BillboardTest:testAddToWhitelist() (gas: 35114) +BillboardTest:testApproveAndTransfer() (gas: 162512) +BillboardTest:testCalculateTax() (gas: 22822) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 410878, ~: 424702) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 377863) +BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 9037) +BillboardTest:testCannotApproveByAttacker() (gas: 130271) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 578827) +BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136253) +BillboardTest:testCannotMintBoardByAttacker() (gas: 13321) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 139222) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 624744, ~: 630975) +BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 9104) +BillboardTest:testCannotSafeTransferByAttacker() (gas: 127438) +BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 157292) +BillboardTest:testCannotSetIsOpenedByAttacker() (gas: 8994) +BillboardTest:testCannotSetTaxRateByAttacker() (gas: 9006) +BillboardTest:testCannotTransferByOperator() (gas: 132771) +BillboardTest:testCannotTransferToZeroAddress() (gas: 128258) +BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 9128) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 903306, ~: 903306) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 743847, ~: 743847) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 619025, ~: 619025) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 413160) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 710721, ~: 710721) +BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 16677) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 622677) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1156582) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2773780, ~: 1419565) +BillboardTest:testGetTokenURI() (gas: 154980) +BillboardTest:testMintBoard() (gas: 225541) +BillboardTest:testMintBoardByWhitelist() (gas: 154942) +BillboardTest:testMintBoardIfOpened() (gas: 145715) +BillboardTest:testPlaceBidByWhitelist() (gas: 461423) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 906529) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 510724, ~: 520900) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 739847, ~: 747077) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 738385, ~: 750061) +BillboardTest:testPlaceBidZeroPrice() (gas: 354275) +BillboardTest:testRemoveToWhitelist() (gas: 23207) +BillboardTest:testSafeTransferByOperator() (gas: 141237) +BillboardTest:testSetBoardProperties() (gas: 305883) +BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 335509) +BillboardTest:testSetIsOpened() (gas: 22661) +BillboardTest:testSetTaxRate() (gas: 22909) +BillboardTest:testSomethin() (gas: 1626769) +BillboardTest:testUpgradeRegistry() (gas: 2968149) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 904808, ~: 904808) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 500265, ~: 500265) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index 80cb9d9..e5a9f7a 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -6,12 +6,11 @@ import "./IBillboard.sol"; import "./IBillboardRegistry.sol"; contract Billboard is IBillboard { - BillboardRegistry public registry; - // access control - bool public isOpened = false; - address public admin; + BillboardRegistry public immutable registry; + address public immutable admin; mapping(address => bool) public whitelist; + bool public isOpened = false; constructor(address payable registry_, uint256 taxRate_, string memory name_, string memory symbol_) { admin = msg.sender; diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index 9f6ff02..dba6b2f 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -15,7 +15,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { Counters.Counter public lastTokenId; uint256 public taxRate; - uint64 public leaseTerm = 14 days; + uint64 public constant leaseTerm = 14 days; // tokenId => Board mapping(uint256 => Board) public boards; @@ -41,6 +41,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { string memory name_, string memory symbol_ ) ERC721(name_, symbol_) { + require(operator_ != address(0), "Zero address"); operator = operator_; taxRate = taxRate_; } @@ -59,7 +60,11 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function setOperator(address operator_) external isFromOperator { + require(operator_ != address(0), "Zero address"); + operator = operator_; + + emit OperatorUpdated(operator_); } ////////////////////////////// @@ -221,6 +226,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { /// @inheritdoc IBillboardRegistry function transferAmount(address to_, uint256 amount_) external isFromOperator { + require(to_ != address(0), "Zero address"); (bool _success, ) = to_.call{value: amount_}(""); require(_success, "transfer failed"); } diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index a6a1778..3ba5c81 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -8,6 +8,11 @@ interface IBillboardRegistry is IERC721 { /// Event ////////////////////////////// + /** + * @notice Operator is updated. + */ + event OperatorUpdated(address indexed operator); + /** * @notice Board name is updated. * From 4f4c923fae377249adc341789679ce3707ad3b1d Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:35:23 +0800 Subject: [PATCH 54/55] feat(billboard): change leaseTerm from block.timestamp to block.number --- .env.local.example | 3 +- .env.polygon-mainnet.example | 1 + .env.polygon-mumbai.example | 1 + .gas-snapshot | 48 ++++++++-------- Makefile | 2 +- src/Billboard/Billboard.sol | 26 +++++---- src/Billboard/BillboardRegistry.sol | 8 ++- src/Billboard/IBillboardRegistry.sol | 10 ++-- src/test/Billboard/BillboardTest.t.sol | 66 +++++++++++----------- src/test/Billboard/BillboardTestBase.t.sol | 5 +- 10 files changed, 91 insertions(+), 79 deletions(-) diff --git a/.env.local.example b/.env.local.example index 1019df2..2da0e79 100644 --- a/.env.local.example +++ b/.env.local.example @@ -17,4 +17,5 @@ THESPACE_INCENTIVES_ADDRESS= THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= -BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 \ No newline at end of file +BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 +BILLBOARD_LEASE_TERM= \ No newline at end of file diff --git a/.env.polygon-mainnet.example b/.env.polygon-mainnet.example index 4c65c90..884f4a3 100644 --- a/.env.polygon-mainnet.example +++ b/.env.polygon-mainnet.example @@ -19,3 +19,4 @@ THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 +BILLBOARD_LEASE_TERM= \ No newline at end of file diff --git a/.env.polygon-mumbai.example b/.env.polygon-mumbai.example index 676c67a..e86c70d 100644 --- a/.env.polygon-mumbai.example +++ b/.env.polygon-mumbai.example @@ -19,3 +19,4 @@ THESPACE_INCENTIVES_TOKENS= THESPACE_LP_ADDRESS= THESPACE_LP_TOKENS= BILLBOARD_REGISTRY_ADDRESS=0x0000000000000000000000000000000000000000 +BILLBOARD_LEASE_TERM= \ No newline at end of file diff --git a/.gas-snapshot b/.gas-snapshot index 43d756e..13abd07 100644 --- a/.gas-snapshot +++ b/.gas-snapshot @@ -11,16 +11,16 @@ ACLManagerTest:testRoles() (gas: 15393) ACLManagerTest:testTransferRole() (gas: 21528) BillboardTest:testAddToWhitelist() (gas: 35114) BillboardTest:testApproveAndTransfer() (gas: 162512) -BillboardTest:testCalculateTax() (gas: 22822) -BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 410878, ~: 424702) -BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 377863) +BillboardTest:testCalculateTax() (gas: 21782) +BillboardTest:testCannnotWithdrawTaxIfSmallAmount(uint8) (runs: 256, μ: 418269, ~: 424925) +BillboardTest:testCannnotWithdrawTaxIfZero() (gas: 379035) BillboardTest:testCannotAddToWhitelistByAttacker() (gas: 9037) BillboardTest:testCannotApproveByAttacker() (gas: 130271) -BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 578827) +BillboardTest:testCannotClearAuctionIfAuctionNotEnded() (gas: 579292) BillboardTest:testCannotClearAuctionOnNewBoard() (gas: 136253) BillboardTest:testCannotMintBoardByAttacker() (gas: 13321) -BillboardTest:testCannotPlaceBidByAttacker() (gas: 139222) -BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 624744, ~: 630975) +BillboardTest:testCannotPlaceBidByAttacker() (gas: 138273) +BillboardTest:testCannotPlaceBidTwice(uint96) (runs: 256, μ: 623750, ~: 630370) BillboardTest:testCannotRemoveToWhitelistByAttacker() (gas: 9104) BillboardTest:testCannotSafeTransferByAttacker() (gas: 127438) BillboardTest:testCannotSetBoardProprtiesByAttacker() (gas: 157292) @@ -29,35 +29,35 @@ BillboardTest:testCannotSetTaxRateByAttacker() (gas: 9006) BillboardTest:testCannotTransferByOperator() (gas: 132771) BillboardTest:testCannotTransferToZeroAddress() (gas: 128258) BillboardTest:testCannotUpgradeRegistryByAttacker() (gas: 9128) -BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 903306, ~: 903306) -BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 743847, ~: 743847) -BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 619025, ~: 619025) -BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 413160) -BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 710721, ~: 710721) +BillboardTest:testCannotWithBidTwice(uint96) (runs: 256, μ: 901993, ~: 901993) +BillboardTest:testCannotWithdrawBidIfAuctionNotCleared(uint96) (runs: 256, μ: 742413, ~: 742413) +BillboardTest:testCannotWithdrawBidIfAuctionNotEnded(uint96) (runs: 256, μ: 618541, ~: 618541) +BillboardTest:testCannotWithdrawBidIfNotFound() (gas: 414332) +BillboardTest:testCannotWithdrawBidIfWon(uint96) (runs: 256, μ: 710358, ~: 710358) BillboardTest:testCannotWithdrawTaxByAttacker() (gas: 16677) -BillboardTest:testClearAuctionIfAuctionEnded() (gas: 622677) -BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1156582) -BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2773780, ~: 1419565) +BillboardTest:testClearAuctionIfAuctionEnded() (gas: 623626) +BillboardTest:testClearAuctionsIfAuctionEnded() (gas: 1156359) +BillboardTest:testGetBids(uint8,uint8,uint8) (runs: 256, μ: 2878685, ~: 1412103) BillboardTest:testGetTokenURI() (gas: 154980) BillboardTest:testMintBoard() (gas: 225541) BillboardTest:testMintBoardByWhitelist() (gas: 154942) BillboardTest:testMintBoardIfOpened() (gas: 145715) -BillboardTest:testPlaceBidByWhitelist() (gas: 461423) -BillboardTest:testPlaceBidIfAuctionEnded() (gas: 906529) -BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 510724, ~: 520900) -BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 739847, ~: 747077) -BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 738385, ~: 750061) -BillboardTest:testPlaceBidZeroPrice() (gas: 354275) +BillboardTest:testPlaceBidByWhitelist() (gas: 461646) +BillboardTest:testPlaceBidIfAuctionEnded() (gas: 905458) +BillboardTest:testPlaceBidOnNewBoard(uint96) (runs: 256, μ: 510257, ~: 521365) +BillboardTest:testPlaceBidWithHigherPrice(uint96) (runs: 256, μ: 736177, ~: 744573) +BillboardTest:testPlaceBidWithSamePrices(uint96) (runs: 256, μ: 735897, ~: 748506) +BillboardTest:testPlaceBidZeroPrice() (gas: 355447) BillboardTest:testRemoveToWhitelist() (gas: 23207) BillboardTest:testSafeTransferByOperator() (gas: 141237) BillboardTest:testSetBoardProperties() (gas: 305883) BillboardTest:testSetBoardPropertiesAfterTransfer() (gas: 335509) BillboardTest:testSetIsOpened() (gas: 22661) BillboardTest:testSetTaxRate() (gas: 22909) -BillboardTest:testSomethin() (gas: 1626769) -BillboardTest:testUpgradeRegistry() (gas: 2968149) -BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 904808, ~: 904808) -BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 500265, ~: 500265) +BillboardTest:testSomethin() (gas: 1624285) +BillboardTest:testUpgradeRegistry() (gas: 2935587) +BillboardTest:testWithdrawBid(uint96) (runs: 256, μ: 903495, ~: 903495) +BillboardTest:testWithdrawTax(uint96) (runs: 256, μ: 500488, ~: 500488) CurationTest:testCannotCurateERC20CurateZeroAmount() (gas: 12194) CurationTest:testCannotCurateERC20EmptyURI() (gas: 15797) CurationTest:testCannotCurateERC20IfNotApproval() (gas: 21624) diff --git a/Makefile b/Makefile index 2dd085c..60089b0 100644 --- a/Makefile +++ b/Makefile @@ -46,4 +46,4 @@ deploy-curation: clean ## Billboard deploy-billboard: clean - @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 "Billboard" "BLBD" --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} \ No newline at end of file + @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 ${BILLBOARD_LEASE_TERM} "Billboard" "BLBD" --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} \ No newline at end of file diff --git a/src/Billboard/Billboard.sol b/src/Billboard/Billboard.sol index e5a9f7a..17f85c2 100644 --- a/src/Billboard/Billboard.sol +++ b/src/Billboard/Billboard.sol @@ -12,7 +12,13 @@ contract Billboard is IBillboard { mapping(address => bool) public whitelist; bool public isOpened = false; - constructor(address payable registry_, uint256 taxRate_, string memory name_, string memory symbol_) { + constructor( + address payable registry_, + uint256 taxRate_, + uint64 leaseTerm_, + string memory name_, + string memory symbol_ + ) { admin = msg.sender; whitelist[msg.sender] = true; @@ -22,7 +28,7 @@ contract Billboard is IBillboard { } // deploy operator and registry else { - registry = new BillboardRegistry(address(this), taxRate_, name_, symbol_); + registry = new BillboardRegistry(address(this), taxRate_, leaseTerm_, name_, symbol_); } } @@ -145,7 +151,7 @@ contract Billboard is IBillboard { IBillboardRegistry.Auction memory _nextAuction = registry.getAuction(tokenId_, _nextAuctionId); // revert if auction is still running - require(block.timestamp >= _nextAuction.endAt, "Auction not ended"); + require(block.number >= _nextAuction.endAt, "Auction not ended"); // reclaim ownership to board creator if no auction address _prevOwner = registry.ownerOf(tokenId_); @@ -196,7 +202,7 @@ contract Billboard is IBillboard { registry.setBidWon(tokenId_, nextAuctionId_, _nextAuction.highestBidder, true); // set auction lease - uint64 leaseStartAt = uint64(block.timestamp); + uint64 leaseStartAt = uint64(block.number); uint64 leaseEndAt = uint64(leaseStartAt + registry.leaseTerm()); registry.setAuctionLease(tokenId_, nextAuctionId_, leaseStartAt, leaseEndAt); @@ -216,7 +222,7 @@ contract Billboard is IBillboard { // create new auction and new bid first, // then clear auction and transfer ownership to the bidder immediately. if (_nextAuction.startAt == 0) { - uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp)); + uint256 _auctionId = _newAuctionAndBid(tokenId_, amount_, uint64(block.number)); _clearAuction(tokenId_, _board.creator, _auctionId); return; } @@ -224,9 +230,9 @@ contract Billboard is IBillboard { // if next auction is ended, // clear auction first, // then create new auction and new bid - if (block.timestamp >= _nextAuction.endAt) { + if (block.number >= _nextAuction.endAt) { _clearAuction(tokenId_, _board.creator, _nextAuctionId); - _newAuctionAndBid(tokenId_, amount_, uint64(block.timestamp + registry.leaseTerm())); + _newAuctionAndBid(tokenId_, amount_, uint64(block.number + registry.leaseTerm())); return; } // if next auction is not ended, @@ -242,7 +248,7 @@ contract Billboard is IBillboard { } function _newAuctionAndBid(uint256 tokenId_, uint256 amount_, uint64 endAt_) private returns (uint256 auctionId) { - uint64 _startAt = uint64(block.timestamp); + uint64 _startAt = uint64(block.number); uint256 _tax = calculateTax(amount_); auctionId = registry.newAuction(tokenId_, _startAt, endAt_); @@ -319,7 +325,7 @@ contract Billboard is IBillboard { } function calculateTax(uint256 amount_) public view returns (uint256 tax) { - tax = (amount_ * registry.taxRate() * registry.leaseTerm()) / 1 days / 100; + tax = (amount_ * registry.taxRate()) / 100; } /// @inheritdoc IBillboard @@ -344,7 +350,7 @@ contract Billboard is IBillboard { function withdrawBid(uint256 tokenId_, uint256 auctionId_) external { // revert if auction is still running IBillboardRegistry.Auction memory _auction = registry.getAuction(tokenId_, auctionId_); - require(block.timestamp >= _auction.endAt, "Auction not ended"); + require(block.number >= _auction.endAt, "Auction not ended"); // revert if auction is not cleared require(_auction.leaseEndAt != 0, "Auction not cleared"); diff --git a/src/Billboard/BillboardRegistry.sol b/src/Billboard/BillboardRegistry.sol index dba6b2f..575907b 100644 --- a/src/Billboard/BillboardRegistry.sol +++ b/src/Billboard/BillboardRegistry.sol @@ -15,7 +15,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { Counters.Counter public lastTokenId; uint256 public taxRate; - uint64 public constant leaseTerm = 14 days; + uint64 public leaseTerm; // tokenId => Board mapping(uint256 => Board) public boards; @@ -38,12 +38,14 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { constructor( address operator_, uint256 taxRate_, + uint64 leaseTerm_, string memory name_, string memory symbol_ ) ERC721(name_, symbol_) { require(operator_ != address(0), "Zero address"); operator = operator_; taxRate = taxRate_; + leaseTerm = leaseTerm_; } ////////////////////////////// @@ -186,7 +188,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { uint256 price_, uint256 tax_ ) external isFromOperator { - Bid memory _bid = Bid({price: price_, tax: tax_, placedAt: block.timestamp, isWithdrawn: false, isWon: false}); + Bid memory _bid = Bid({price: price_, tax: tax_, placedAt: block.number, isWithdrawn: false, isWon: false}); // add to auction bids auctionBids[tokenId_][auctionId_][bidder_] = _bid; @@ -197,7 +199,7 @@ contract BillboardRegistry is IBillboardRegistry, ERC721 { // set auction highest bidder if no highest bidder or price is higher. // // Note: for same price, the first bidder will always be - // the highest bidder since the block.timestamp is always greater. + // the highest bidder since the block.number is always greater. address highestBidder = boardAuctions[tokenId_][auctionId_].highestBidder; Bid memory highestBid = auctionBids[tokenId_][auctionId_][highestBidder]; if (highestBidder == address(0) || price_ > highestBid.price) { diff --git a/src/Billboard/IBillboardRegistry.sol b/src/Billboard/IBillboardRegistry.sol index 3ba5c81..c21360b 100644 --- a/src/Billboard/IBillboardRegistry.sol +++ b/src/Billboard/IBillboardRegistry.sol @@ -152,17 +152,17 @@ interface IBillboardRegistry is IERC721 { } struct Auction { - uint64 startAt; // timestamp - uint64 endAt; // timestamp - uint64 leaseStartAt; // timestamp - uint64 leaseEndAt; // timestamp + uint64 startAt; // block number + uint64 endAt; // block number + uint64 leaseStartAt; // block number + uint64 leaseEndAt; // block number address highestBidder; } struct Bid { uint256 price; uint256 tax; - uint256 placedAt; // timestamp + uint256 placedAt; // block number bool isWon; bool isWithdrawn; } diff --git a/src/test/Billboard/BillboardTest.t.sol b/src/test/Billboard/BillboardTest.t.sol index 556005d..dc7a121 100644 --- a/src/test/Billboard/BillboardTest.t.sol +++ b/src/test/Billboard/BillboardTest.t.sol @@ -13,7 +13,7 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(ADMIN); // deploy new operator - Billboard newOperator = new Billboard(payable(registry), TAX_RATE, "Billboard2", "BLBD2"); + Billboard newOperator = new Billboard(payable(registry), TAX_RATE, LEASE_TERM, "Billboard2", "BLBD2"); assertEq(newOperator.admin(), ADMIN); assertEq(registry.name(), "Billboard"); // registry is not changed assertEq(registry.symbol(), "BLBD"); // registry is not changed @@ -368,8 +368,8 @@ contract BillboardTest is BillboardTestBase { emit IBillboardRegistry.AuctionCreated( _tokenId, _prevNextActionId + 1, - uint64(block.timestamp), - uint64(block.timestamp) + uint64(block.number), + uint64(block.number) ); vm.expectEmit(true, true, true, true); emit IBillboardRegistry.BidCreated(_tokenId, _prevNextActionId + 1, USER_A, _amount, _tax); @@ -380,8 +380,8 @@ contract BillboardTest is BillboardTestBase { _tokenId, _prevNextActionId + 1, USER_A, - uint64(block.timestamp), - uint64(block.timestamp + registry.leaseTerm()) + uint64(block.number), + uint64(block.number + registry.leaseTerm()) ); vm.prank(USER_A); @@ -398,17 +398,17 @@ contract BillboardTest is BillboardTestBase { IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); assertEq(_prevNextActionId, 0); assertEq(_nextAuctionId, _prevNextActionId + 1); - assertEq(_auction.startAt, block.timestamp); - assertEq(_auction.endAt, block.timestamp); - assertEq(_auction.leaseStartAt, block.timestamp); - assertEq(_auction.leaseEndAt, block.timestamp + registry.leaseTerm()); + assertEq(_auction.startAt, block.number); + assertEq(_auction.endAt, block.number); + assertEq(_auction.leaseStartAt, block.number); + assertEq(_auction.leaseEndAt, block.number + registry.leaseTerm()); assertEq(_auction.highestBidder, USER_A); // check bid IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); assertEq(_bid.price, _amount); assertEq(_bid.tax, _tax); - assertEq(_bid.placedAt, block.timestamp); + assertEq(_bid.placedAt, block.number); assertEq(_bid.isWon, true); assertEq(_bid.isWithdrawn, false); } @@ -425,7 +425,7 @@ contract BillboardTest is BillboardTestBase { vm.startPrank(USER_B); operator.placeBid{value: 0}(_tokenId3, 0); - vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + vm.roll(block.number + registry.leaseTerm() + 1); uint256[] memory _tokenIds = new uint256[](3); _tokenIds[0] = _tokenId; _tokenIds[1] = _tokenId2; @@ -458,10 +458,10 @@ contract BillboardTest is BillboardTestBase { // check if bids exist IBillboardRegistry.Bid memory _bidA = registry.getBid(_tokenId, _nextAuctionId, USER_A); - assertEq(_bidA.placedAt, block.timestamp); + assertEq(_bidA.placedAt, block.number); assertEq(_bidA.isWon, false); IBillboardRegistry.Bid memory _bidB = registry.getBid(_tokenId, _nextAuctionId, USER_A); - assertEq(_bidB.placedAt, block.timestamp); + assertEq(_bidB.placedAt, block.number); assertEq(_bidB.isWon, false); // check registry balance @@ -516,7 +516,7 @@ contract BillboardTest is BillboardTestBase { // check bid IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, ADMIN); - assertEq(_bid.placedAt, block.timestamp); + assertEq(_bid.placedAt, block.number); assertEq(_bid.isWon, true); } @@ -550,10 +550,10 @@ contract BillboardTest is BillboardTestBase { uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); IBillboardRegistry.Auction memory _auction = registry.getAuction(_tokenId, _nextAuctionId); assertEq(_auction.highestBidder, USER_A); - assertEq(_auction.endAt, block.timestamp + registry.leaseTerm()); + assertEq(_auction.endAt, block.number + registry.leaseTerm()); // make auction ended - vm.warp(_auction.endAt + 1 seconds); + vm.roll(_auction.endAt + 1); // place a bid with USER_B vm.startPrank(USER_B); @@ -565,7 +565,7 @@ contract BillboardTest is BillboardTestBase { IBillboardRegistry.Auction memory _newAuction = registry.getAuction(_tokenId, _newNextAuctionId); assertEq(_newNextAuctionId, _nextAuctionId + 1); assertEq(_newAuction.highestBidder, USER_B); - assertEq(_newAuction.endAt, block.timestamp + registry.leaseTerm()); + assertEq(_newAuction.endAt, block.number + registry.leaseTerm()); // USER_A won the previous auction IBillboardRegistry.Bid memory _bid = registry.getBid(_tokenId, _nextAuctionId, USER_A); @@ -605,8 +605,8 @@ contract BillboardTest is BillboardTestBase { function testClearAuctionIfAuctionEnded() public { (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); - uint64 _placedAt = uint64(block.timestamp); - uint64 _clearedAt = uint64(block.timestamp) + registry.leaseTerm() + 1 minutes; + uint64 _placedAt = uint64(block.number); + uint64 _clearedAt = uint64(block.number) + registry.leaseTerm() + 1; // place a bid vm.startPrank(USER_A); @@ -623,7 +623,7 @@ contract BillboardTest is BillboardTestBase { _clearedAt + registry.leaseTerm() ); - vm.warp(_clearedAt); + vm.roll(_clearedAt); operator.clearAuction(_tokenId); // check auction @@ -648,8 +648,8 @@ contract BillboardTest is BillboardTestBase { (uint256 _tokenId, uint256 _prevAuctionId) = _mintBoardAndPlaceBid(); (uint256 _tokenId2, uint256 _prevAuctionId2) = _mintBoardAndPlaceBid(); - uint64 _placedAt = uint64(block.timestamp); - uint64 _clearedAt = uint64(block.timestamp) + registry.leaseTerm() + 1 minutes; + uint64 _placedAt = uint64(block.number); + uint64 _clearedAt = uint64(block.number) + registry.leaseTerm() + 1; // place bids vm.startPrank(USER_A); @@ -678,7 +678,7 @@ contract BillboardTest is BillboardTestBase { _clearedAt + registry.leaseTerm() ); - vm.warp(_clearedAt); + vm.roll(_clearedAt); uint256[] memory _tokenIds = new uint256[](2); _tokenIds[0] = _tokenId; @@ -719,14 +719,14 @@ contract BillboardTest is BillboardTestBase { } function testCannotClearAuctionOnNewBoard() public { - uint256 _mintedAt = block.timestamp; + uint256 _mintedAt = block.number; uint256 _clearedAt = _mintedAt + 1; uint256 _tokenId = _mintBoard(); vm.startPrank(ADMIN); // clear auction - vm.warp(_clearedAt); + vm.roll(_clearedAt); vm.expectRevert("Auction not found"); operator.clearAuction(_tokenId); } @@ -743,7 +743,7 @@ contract BillboardTest is BillboardTestBase { vm.expectRevert("Auction not ended"); operator.clearAuction(_tokenId); - vm.warp(block.timestamp + registry.leaseTerm() - 1 seconds); + vm.roll(block.number + registry.leaseTerm() - 1); vm.expectRevert("Auction not ended"); operator.clearAuction(_tokenId); } @@ -797,13 +797,13 @@ contract BillboardTest is BillboardTestBase { function testCalculateTax() public { uint256 _amount = 100; - uint256 _taxRate = 10; // 10% per day + uint256 _taxRate = 10; // 10% per lease term vm.startPrank(ADMIN); operator.setTaxRate(_taxRate); uint256 _tax = operator.calculateTax(_amount); - assertEq(_tax, (_amount * _taxRate * 14) / 100); + assertEq(_tax, (_amount * _taxRate) / 100); } function testSetTaxRate() public { @@ -913,7 +913,7 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _total}(_tokenId, _amount); // clear auction - vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + vm.roll(block.number + registry.leaseTerm() + 1); operator.clearAuction(_tokenId); // check auction @@ -954,7 +954,7 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _total}(_tokenId, _amount); // clear auction - vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + vm.roll(block.number + registry.leaseTerm() + 1); operator.clearAuction(_tokenId); // check auction @@ -986,7 +986,7 @@ contract BillboardTest is BillboardTestBase { operator.placeBid{value: _total}(_tokenId, _amount); // clear auction - vm.warp(block.timestamp + registry.leaseTerm() + 1 minutes); + vm.roll(block.number + registry.leaseTerm() + 1); operator.clearAuction(_tokenId); // check auction @@ -1018,7 +1018,7 @@ contract BillboardTest is BillboardTestBase { operator.withdrawBid(_tokenId, _nextAuctionId); // auction is ended but not cleared - vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); + vm.roll(block.number + registry.leaseTerm() + 1); vm.expectRevert("Auction not cleared"); operator.withdrawBid(_tokenId, _nextAuctionId); } @@ -1042,7 +1042,7 @@ contract BillboardTest is BillboardTestBase { // auction is ended but not cleared uint256 _nextAuctionId = registry.nextBoardAuctionId(_tokenId); - vm.warp(block.timestamp + registry.leaseTerm() + 1 seconds); + vm.roll(block.number + registry.leaseTerm() + 1); vm.prank(USER_B); vm.expectRevert("Auction not cleared"); operator.withdrawBid(_tokenId, _nextAuctionId); diff --git a/src/test/Billboard/BillboardTestBase.t.sol b/src/test/Billboard/BillboardTestBase.t.sol index b866779..2ca6d08 100644 --- a/src/test/Billboard/BillboardTestBase.t.sol +++ b/src/test/Billboard/BillboardTestBase.t.sol @@ -14,7 +14,8 @@ contract BillboardTestBase is Test { Billboard internal operator; BillboardRegistry internal registry; - uint256 constant TAX_RATE = 1; // 1% per day + uint256 constant TAX_RATE = 1; // 1% per lease term + uint64 constant LEASE_TERM = 100; // 100 blocks address constant ZERO_ADDRESS = address(0); address constant FAKE_CONTRACT = address(1); @@ -30,7 +31,7 @@ contract BillboardTestBase is Test { vm.startPrank(ADMIN); // deploy operator & registry - operator = new Billboard(payable(address(0)), TAX_RATE, "Billboard", "BLBD"); + operator = new Billboard(payable(address(0)), TAX_RATE, LEASE_TERM, "Billboard", "BLBD"); registry = operator.registry(); assertEq(operator.admin(), ADMIN); assertEq(registry.operator(), address(operator)); From 89efae2296c122ca72f0bcc684641bb3bf93f6ba Mon Sep 17 00:00:00 2001 From: robertu <4065233+robertu7@users.noreply.github.com> Date: Wed, 6 Dec 2023 14:29:59 +0800 Subject: [PATCH 55/55] feat(billboard): set default tax rate to 7% --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 60089b0..d29c0b5 100644 --- a/Makefile +++ b/Makefile @@ -46,4 +46,4 @@ deploy-curation: clean ## Billboard deploy-billboard: clean - @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 1 ${BILLBOARD_LEASE_TERM} "Billboard" "BLBD" --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} \ No newline at end of file + @forge create Billboard --rpc-url ${ETH_RPC_URL} --private-key ${DEPLOYER_PRIVATE_KEY} --constructor-args ${BILLBOARD_REGISTRY_ADDRESS} 7 ${BILLBOARD_LEASE_TERM} "Billboard" "BLBD" --legacy --verify --etherscan-api-key ${ETHERSCAN_API_KEY} \ No newline at end of file