From e87b28e8bdabb3f4b830fd0f24481f8596936a57 Mon Sep 17 00:00:00 2001 From: eladmallel Date: Thu, 19 Dec 2024 11:59:46 -0500 Subject: [PATCH 1/7] ah: add bidder sanctions check --- .../contracts/NounsAuctionHouseV3.sol | 580 ++++++++++++++++++ .../chainalysis/IChainalysisSanctionsList.sol | 7 + .../interfaces/INounsAuctionHouseV3.sol | 158 +++++ 3 files changed, 745 insertions(+) create mode 100644 packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol create mode 100644 packages/nouns-contracts/contracts/external/chainalysis/IChainalysisSanctionsList.sol create mode 100644 packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV3.sol diff --git a/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol b/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol new file mode 100644 index 0000000000..c14b6a8db6 --- /dev/null +++ b/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title The Nouns DAO auction house + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +// LICENSE +// NounsAuctionHouse.sol is a modified version of Zora's AuctionHouse.sol: +// https://github.com/ourzora/auction-house/blob/54a12ec1a6cf562e49f0a4917990474b11350a2d/contracts/AuctionHouse.sol +// +// AuctionHouse.sol source code Copyright Zora licensed under the GPL-3.0 license. +// With modifications by Nounders DAO. + +pragma solidity ^0.8.19; + +import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; +import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol'; +import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; +import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; +import { INounsAuctionHouseV3 } from './interfaces/INounsAuctionHouseV3.sol'; +import { INounsToken } from './interfaces/INounsToken.sol'; +import { IWETH } from './interfaces/IWETH.sol'; +import { IChainalysisSanctionsList } from './external/chainalysis/IChainalysisSanctionsList.sol'; + +/** + * @dev The contract inherits from PausableUpgradeable & ReentrancyGuardUpgradeable most of all the keep the same + * storage layout as the NounsAuctionHouse contract + */ +contract NounsAuctionHouseV3 is + INounsAuctionHouseV3, + PausableUpgradeable, + ReentrancyGuardUpgradeable, + OwnableUpgradeable +{ + /// @notice A hard-coded cap on time buffer to prevent accidental auction disabling if set with a very high value. + uint56 public constant MAX_TIME_BUFFER = 1 days; + + /// @notice The Nouns ERC721 token contract + INounsToken public immutable nouns; + + /// @notice The address of the WETH contract + address public immutable weth; + + /// @notice The duration of a single auction + uint256 public immutable duration; + + /// @notice The minimum price accepted in an auction + uint192 public reservePrice; + + /// @notice The minimum amount of time left in an auction after a new bid is created + uint56 public timeBuffer; + + /// @notice The minimum percentage difference between the last bid amount and the current bid + uint8 public minBidIncrementPercentage; + + /// @notice The active auction + INounsAuctionHouseV3.AuctionV2 public auctionStorage; + + /// @notice The Nouns price feed state + mapping(uint256 => SettlementState) settlementHistory; + + /// @notice The contract used to verify bidders are not sanctioned wallets + IChainalysisSanctionsList public sanctionsOracle; + + constructor(INounsToken _nouns, address _weth, uint256 _duration) initializer { + nouns = _nouns; + weth = _weth; + duration = _duration; + } + + /** + * @notice Initialize the auction house and base contracts, + * populate configuration values, and pause the contract. + * @dev This function can only be called once. + */ + function initialize( + uint192 _reservePrice, + uint56 _timeBuffer, + uint8 _minBidIncrementPercentage + ) external initializer { + __Pausable_init(); + __ReentrancyGuard_init(); + __Ownable_init(); + + _pause(); + + reservePrice = _reservePrice; + timeBuffer = _timeBuffer; + minBidIncrementPercentage = _minBidIncrementPercentage; + } + + /** + * @notice Settle the current auction, mint a new Noun, and put it up for auction. + */ + function settleCurrentAndCreateNewAuction() external override whenNotPaused { + _settleAuction(); + _createAuction(); + } + + /** + * @notice Settle the current auction. + * @dev This function can only be called when the contract is paused. + */ + function settleAuction() external override whenPaused { + _settleAuction(); + } + + /** + * @notice Create a bid for a Noun, with a given amount. + * @dev This contract only accepts payment in ETH. + */ + function createBid(uint256 nounId) external payable override { + createBid(nounId, 0); + } + + /** + * @notice Create a bid for a Noun, with a given amount. + * @param nounId id of the Noun to bid on + * @param clientId the client which facilitate this action + * @dev This contract only accepts payment in ETH. + */ + function createBid(uint256 nounId, uint32 clientId) public payable override { + INounsAuctionHouseV3.AuctionV2 memory _auction = auctionStorage; + + (uint192 _reservePrice, uint56 _timeBuffer, uint8 _minBidIncrementPercentage) = ( + reservePrice, + timeBuffer, + minBidIncrementPercentage + ); + + _requireNotSanctioned(msg.sender); + require(_auction.nounId == nounId, 'Noun not up for auction'); + require(block.timestamp < _auction.endTime, 'Auction expired'); + require(msg.value >= _reservePrice, 'Must send at least reservePrice'); + require( + msg.value >= _auction.amount + ((_auction.amount * _minBidIncrementPercentage) / 100), + 'Must send more than last bid by minBidIncrementPercentage amount' + ); + + auctionStorage.clientId = clientId; + auctionStorage.amount = uint128(msg.value); + auctionStorage.bidder = payable(msg.sender); + + // Extend the auction if the bid was received within `timeBuffer` of the auction end time + bool extended = _auction.endTime - block.timestamp < _timeBuffer; + + emit AuctionBid(_auction.nounId, msg.sender, msg.value, extended); + if (clientId > 0) emit AuctionBidWithClientId(_auction.nounId, msg.value, clientId); + + if (extended) { + auctionStorage.endTime = _auction.endTime = uint40(block.timestamp + _timeBuffer); + emit AuctionExtended(_auction.nounId, _auction.endTime); + } + + address payable lastBidder = _auction.bidder; + + // Refund the last bidder, if applicable + if (lastBidder != address(0)) { + _safeTransferETHWithFallback(lastBidder, _auction.amount); + } + } + + /** + * @notice Get the current auction. + */ + function auction() external view returns (AuctionV2View memory) { + return + AuctionV2View({ + nounId: auctionStorage.nounId, + amount: auctionStorage.amount, + startTime: auctionStorage.startTime, + endTime: auctionStorage.endTime, + bidder: auctionStorage.bidder, + settled: auctionStorage.settled + }); + } + + /** + * @notice Pause the Nouns auction house. + * @dev This function can only be called by the owner when the + * contract is unpaused. While no new auctions can be started when paused, + * anyone can settle an ongoing auction. + */ + function pause() external override onlyOwner { + _pause(); + } + + /** + * @notice Unpause the Nouns auction house. + * @dev This function can only be called by the owner when the + * contract is paused. If required, this function will start a new auction. + */ + function unpause() external override onlyOwner { + _unpause(); + + if (auctionStorage.startTime == 0 || auctionStorage.settled) { + _createAuction(); + } + } + + /** + * @notice Set the auction time buffer. + * @dev Only callable by the owner. + */ + function setTimeBuffer(uint56 _timeBuffer) external override onlyOwner { + require(_timeBuffer <= MAX_TIME_BUFFER, 'timeBuffer too large'); + + timeBuffer = _timeBuffer; + + emit AuctionTimeBufferUpdated(_timeBuffer); + } + + /** + * @notice Set the auction reserve price. + * @dev Only callable by the owner. + */ + function setReservePrice(uint192 _reservePrice) external override onlyOwner { + reservePrice = _reservePrice; + + emit AuctionReservePriceUpdated(_reservePrice); + } + + /** + * @notice Set the auction minimum bid increment percentage. + * @dev Only callable by the owner. + */ + function setMinBidIncrementPercentage(uint8 _minBidIncrementPercentage) external override onlyOwner { + require(_minBidIncrementPercentage > 0, 'must be greater than zero'); + + minBidIncrementPercentage = _minBidIncrementPercentage; + + emit AuctionMinBidIncrementPercentageUpdated(_minBidIncrementPercentage); + } + + /** + * @notice Set the sanctions oracle address. + * @dev Only callable by the owner. + */ + function setSanctionsOracle(address newSanctionsOracle) external onlyOwner { + sanctionsOracle = IChainalysisSanctionsList(newSanctionsOracle); + + emit SanctionsOracleSet(newSanctionsOracle); + } + + /** + * @notice Create an auction. + * @dev Store the auction details in the `auction` state variable and emit an AuctionCreated event. + * If the mint reverts, the minter was updated without pausing this contract first. To remedy this, + * catch the revert and pause this contract. + */ + function _createAuction() internal { + try nouns.mint() returns (uint256 nounId) { + uint40 startTime = uint40(block.timestamp); + uint40 endTime = startTime + uint40(duration); + + auctionStorage = AuctionV2({ + nounId: uint96(nounId), + clientId: 0, + amount: 0, + startTime: startTime, + endTime: endTime, + bidder: payable(0), + settled: false + }); + + emit AuctionCreated(nounId, startTime, endTime); + } catch Error(string memory) { + _pause(); + } + } + + /** + * @notice Settle an auction, finalizing the bid and paying out to the owner. + * @dev If there are no bids, the Noun is burned. + */ + function _settleAuction() internal { + INounsAuctionHouseV3.AuctionV2 memory _auction = auctionStorage; + + require(_auction.startTime != 0, "Auction hasn't begun"); + require(!_auction.settled, 'Auction has already been settled'); + require(block.timestamp >= _auction.endTime, "Auction hasn't completed"); + + auctionStorage.settled = true; + + if (_auction.bidder == address(0)) { + nouns.burn(_auction.nounId); + } else { + nouns.transferFrom(address(this), _auction.bidder, _auction.nounId); + } + + if (_auction.amount > 0) { + _safeTransferETHWithFallback(owner(), _auction.amount); + } + + SettlementState storage settlementState = settlementHistory[_auction.nounId]; + settlementState.blockTimestamp = uint32(block.timestamp); + settlementState.amount = ethPriceToUint64(_auction.amount); + settlementState.winner = _auction.bidder; + if (_auction.clientId > 0) settlementState.clientId = _auction.clientId; + + emit AuctionSettled(_auction.nounId, _auction.bidder, _auction.amount); + if (_auction.clientId > 0) emit AuctionSettledWithClientId(_auction.nounId, _auction.clientId); + } + + /** + * @notice Transfer ETH. If the ETH transfer fails, wrap the ETH and try send it as WETH. + */ + function _safeTransferETHWithFallback(address to, uint256 amount) internal { + if (!_safeTransferETH(to, amount)) { + IWETH(weth).deposit{ value: amount }(); + IERC20(weth).transfer(to, amount); + } + } + + /** + * @notice Transfer ETH and return the success status. + * @dev This function only forwards 30,000 gas to the callee. + */ + function _safeTransferETH(address to, uint256 value) internal returns (bool) { + bool success; + assembly { + success := call(30000, to, value, 0, 0, 0, 0) + } + return success; + } + + /** + * @notice Revert if `sanctionsOracle` is set and `account` is sanctioned. + */ + function _requireNotSanctioned(address account) internal view { + IChainalysisSanctionsList sanctionsOracle_ = sanctionsOracle; + if (address(sanctionsOracle_) != address(0)) { + require(!sanctionsOracle_.isSanctioned(account), 'Sanctioned bidder'); + } + } + + /** + * @notice Set historic prices; only callable by the owner, which in Nouns is the treasury (timelock) contract. + * @dev This function lowers auction price accuracy from 18 decimals to 10 decimals, as part of the price history + * bit packing, to save gas. + * @param settlements The list of historic prices to set. + */ + function setPrices(SettlementNoClientId[] memory settlements) external onlyOwner { + for (uint256 i = 0; i < settlements.length; ++i) { + SettlementState storage settlementState = settlementHistory[settlements[i].nounId]; + settlementState.blockTimestamp = settlements[i].blockTimestamp; + settlementState.amount = ethPriceToUint64(settlements[i].amount); + settlementState.winner = settlements[i].winner; + } + } + + /** + * @notice Warm up the settlement state for a range of Noun IDs. + * @dev Helps lower the gas cost of auction settlement when storing settlement data + * thanks to the state slot being non-zero. + * @dev Only writes to slots where blockTimestamp is zero, meaning it will not overwrite existing data. + * @dev Skips Nounder reward nouns. + * @param startId the first Noun ID to warm up. + * @param endId end Noun ID (up to, but not including). + */ + function warmUpSettlementState(uint256 startId, uint256 endId) external { + for (uint256 i = startId; i < endId; ++i) { + // Skipping Nounder rewards, no need to warm up those slots since they are never used. + if (i <= 1820 && i % 10 == 0) continue; + + SettlementState storage settlementState = settlementHistory[i]; + if (settlementState.blockTimestamp == 0) { + settlementState.blockTimestamp = 1; + settlementState.slotWarmedUp = true; + } + } + } + + /** + * @notice Get past auction settlements. + * @dev Returns up to `auctionCount` settlements in reverse order, meaning settlements[0] will be the most recent auction price. + * Includes auctions with no bids (blockTimestamp will be > 1) + * @param auctionCount The number of price observations to get. + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlements( + uint256 auctionCount, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements) { + uint256 latestNounId = auctionStorage.nounId; + if (!auctionStorage.settled && latestNounId > 0) { + latestNounId -= 1; + } + + settlements = new Settlement[](auctionCount); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = latestNounId; actualCount < auctionCount; --id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) { + if (id == 0) break; + continue; + } + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + + if (id == 0) break; + } + + if (auctionCount > actualCount) { + // this assembly trims the observations array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /** + * @notice Get past auction prices. + * @dev Returns prices in reverse order, meaning prices[0] will be the most recent auction price. + * Skips auctions where there was no winner, i.e. no bids. + * Skips nounder rewards noun ids. + * Reverts if getting a empty data for an auction that happened, e.g. historic data not filled + * Reverts if there's not enough auction data, i.e. reached noun id 0 + * @param auctionCount The number of price observations to get. + * @return prices An array of uint256 prices. + */ + function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices) { + uint256 latestNounId = auctionStorage.nounId; + if (!auctionStorage.settled && latestNounId > 0) { + latestNounId -= 1; + } + + prices = new uint256[](auctionCount); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = latestNounId; id > 0 && actualCount < auctionCount; --id) { + if (id <= 1820 && id % 10 == 0) continue; // Skip Nounder reward nouns + + settlementState = settlementHistory[id]; + require(settlementState.blockTimestamp > 1, 'Missing data'); + if (settlementState.winner == address(0)) continue; // Skip auctions with no bids + + prices[actualCount] = uint64PriceToUint256(settlementState.amount); + ++actualCount; + } + + require(auctionCount == actualCount, 'Not enough history'); + } + + /** + * @notice Get all past auction settlements starting at `startId` and settled before or at `endTimestamp`. + * @param startId the first Noun ID to get prices for. + * @param endTimestamp the latest timestamp for auctions + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlementsFromIdtoTimestamp( + uint256 startId, + uint256 endTimestamp, + bool skipEmptyValues + ) public view returns (Settlement[] memory settlements) { + uint256 maxId = auctionStorage.nounId; + require(startId <= maxId, 'startId too large'); + settlements = new Settlement[](maxId - startId + 1); + uint256 actualCount = 0; + SettlementState memory settlementState; + for (uint256 id = startId; id <= maxId; ++id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; + + // don't include the currently auctioned noun if it hasn't settled + if ((id == maxId) && (settlementState.blockTimestamp <= 1)) continue; + + if (settlementState.blockTimestamp > endTimestamp) break; + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + } + + if (settlements.length > actualCount) { + // this assembly trims the settlements array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /** + * @notice Get a range of past auction settlements. + * @dev Returns prices in chronological order, as opposed to `getSettlements(count)` which returns prices in reverse order. + * Includes auctions with no bids (blockTimestamp will be > 1) + * @param startId the first Noun ID to get prices for. + * @param endId end Noun ID (up to, but not including). + * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data + * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, + * the Noun ID of that auction, the winning bid amount, and the winner's address. + */ + function getSettlements( + uint256 startId, + uint256 endId, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements) { + settlements = new Settlement[](endId - startId); + uint256 actualCount = 0; + + SettlementState memory settlementState; + for (uint256 id = startId; id < endId; ++id) { + settlementState = settlementHistory[id]; + + if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; + + settlements[actualCount] = Settlement({ + blockTimestamp: settlementState.blockTimestamp, + amount: uint64PriceToUint256(settlementState.amount), + winner: settlementState.winner, + nounId: id, + clientId: settlementState.clientId + }); + ++actualCount; + } + + if (settlements.length > actualCount) { + // this assembly trims the settlements array, getting rid of unused cells + assembly { + mstore(settlements, actualCount) + } + } + } + + /*** + * @notice Get the client ID that facilitated the winning bid for a Noun. Returns 0 if there is no settlement data + * for the Noun in question, or if the winning bid was not facilitated by a registered client. + */ + function biddingClient(uint256 nounId) external view returns (uint32) { + return settlementHistory[nounId].clientId; + } + + /** + * @dev Convert an ETH price of 256 bits with 18 decimals, to 64 bits with 10 decimals. + * Max supported value is 1844674407.3709551615 ETH. + * + */ + function ethPriceToUint64(uint256 ethPrice) internal pure returns (uint64) { + return uint64(ethPrice / 1e8); + } + + /** + * @dev Convert a 64 bit 10 decimal price to a 256 bit 18 decimal price. + */ + function uint64PriceToUint256(uint64 price) internal pure returns (uint256) { + return uint256(price) * 1e8; + } +} diff --git a/packages/nouns-contracts/contracts/external/chainalysis/IChainalysisSanctionsList.sol b/packages/nouns-contracts/contracts/external/chainalysis/IChainalysisSanctionsList.sol new file mode 100644 index 0000000000..54a14b8f65 --- /dev/null +++ b/packages/nouns-contracts/contracts/external/chainalysis/IChainalysisSanctionsList.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.19; + +interface IChainalysisSanctionsList { + function isSanctioned(address addr) external view returns (bool); +} diff --git a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV3.sol b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV3.sol new file mode 100644 index 0000000000..b51ad53f82 --- /dev/null +++ b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV3.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-3.0 + +/// @title Interface for Noun Auction Houses V2 + +/********************************* + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░██░░░████░░██░░░████░░░ * + * ░░██████░░░████████░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░██░░██░░░████░░██░░░████░░░ * + * ░░░░░░█████████░░█████████░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * + *********************************/ + +pragma solidity ^0.8.19; + +interface INounsAuctionHouseV3 { + struct AuctionV2 { + // ID for the Noun (ERC721 token ID) + uint96 nounId; + // ID of the client that facilitated the latest bid, used for client rewards + uint32 clientId; + // The current highest bid amount + uint128 amount; + // The time that the auction started + uint40 startTime; + // The time that the auction is scheduled to end + uint40 endTime; + // The address of the current highest bid + address payable bidder; + // Whether or not the auction has been settled + bool settled; + } + + /// @dev We use this struct as the return value of the `auction` function, to maintain backwards compatibility. + struct AuctionV2View { + // ID for the Noun (ERC721 token ID) + uint96 nounId; + // The current highest bid amount + uint128 amount; + // The time that the auction started + uint40 startTime; + // The time that the auction is scheduled to end + uint40 endTime; + // The address of the current highest bid + address payable bidder; + // Whether or not the auction has been settled + bool settled; + } + + struct SettlementState { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, with 10 decimal places (reducing accuracy to save bits). + uint64 amount; + // The address of the auction winner. + address winner; + // ID of the client that facilitated the winning bid, used for client rewards. + uint32 clientId; + // Used only to warm up the storage slot for clientId without setting the clientId value. + bool slotWarmedUp; + } + + struct Settlement { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, converted from 10 decimal places to 18, for better client UX. + uint256 amount; + // The address of the auction winner. + address winner; + // ID for the Noun (ERC721 token ID). + uint256 nounId; + // ID of the client that facilitated the winning bid, used for client rewards + uint32 clientId; + } + + /// @dev Using this struct when setting historic prices, and excluding clientId to save gas. + struct SettlementNoClientId { + // The block.timestamp when the auction was settled. + uint32 blockTimestamp; + // The winning bid amount, converted from 10 decimal places to 18, for better client UX. + uint256 amount; + // The address of the auction winner. + address winner; + // ID for the Noun (ERC721 token ID). + uint256 nounId; + } + + event AuctionCreated(uint256 indexed nounId, uint256 startTime, uint256 endTime); + + event AuctionBid(uint256 indexed nounId, address sender, uint256 value, bool extended); + + event AuctionBidWithClientId(uint256 indexed nounId, uint256 value, uint32 indexed clientId); + + event AuctionExtended(uint256 indexed nounId, uint256 endTime); + + event AuctionSettled(uint256 indexed nounId, address winner, uint256 amount); + + event AuctionSettledWithClientId(uint256 indexed nounId, uint32 indexed clientId); + + event AuctionTimeBufferUpdated(uint256 timeBuffer); + + event AuctionReservePriceUpdated(uint256 reservePrice); + + event AuctionMinBidIncrementPercentageUpdated(uint256 minBidIncrementPercentage); + + event SanctionsOracleSet(address newSanctionsOracle); + + function settleAuction() external; + + function settleCurrentAndCreateNewAuction() external; + + function createBid(uint256 nounId) external payable; + + function createBid(uint256 nounId, uint32 clientId) external payable; + + function pause() external; + + function unpause() external; + + function setTimeBuffer(uint56 timeBuffer) external; + + function setReservePrice(uint192 reservePrice) external; + + function setMinBidIncrementPercentage(uint8 minBidIncrementPercentage) external; + + function setSanctionsOracle(address newSanctionsOracle) external; + + function auction() external view returns (AuctionV2View memory); + + function getSettlements( + uint256 auctionCount, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices); + + function getSettlements( + uint256 startId, + uint256 endId, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function getSettlementsFromIdtoTimestamp( + uint256 startId, + uint256 endTimestamp, + bool skipEmptyValues + ) external view returns (Settlement[] memory settlements); + + function warmUpSettlementState(uint256 startId, uint256 endId) external; + + function duration() external view returns (uint256); + + function biddingClient(uint256 nounId) external view returns (uint32 clientId); +} From 84a5716d5625ae3cbbf850fd336616c9ae3a07a2 Mon Sep 17 00:00:00 2001 From: eladmallel Date: Tue, 24 Dec 2024 09:58:35 -0500 Subject: [PATCH 2/7] ah: add mainnet fork tests --- .../interfaces/INounsAuctionHouseV2.sol | 12 + packages/nouns-contracts/foundry.toml | 5 +- .../foundry/Upgrade/UpgradeMainnetFork.t.sol | 361 +++++------------- 3 files changed, 120 insertions(+), 258 deletions(-) diff --git a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol index fbba25ade6..90dcc3cbc6 100644 --- a/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol +++ b/packages/nouns-contracts/contracts/interfaces/INounsAuctionHouseV2.sol @@ -17,6 +17,8 @@ pragma solidity ^0.8.19; +import { INounsToken } from './INounsToken.sol'; + interface INounsAuctionHouseV2 { struct AuctionV2 { // ID for the Noun (ERC721 token ID) @@ -151,4 +153,14 @@ interface INounsAuctionHouseV2 { function duration() external view returns (uint256); function biddingClient(uint256 nounId) external view returns (uint32 clientId); + + function minBidIncrementPercentage() external view returns (uint8); + + function nouns() external view returns (INounsToken); + + function weth() external view returns (address); + + function reservePrice() external view returns (uint192); + + function timeBuffer() external view returns (uint56); } diff --git a/packages/nouns-contracts/foundry.toml b/packages/nouns-contracts/foundry.toml index c2251bef55..e2adb97997 100644 --- a/packages/nouns-contracts/foundry.toml +++ b/packages/nouns-contracts/foundry.toml @@ -4,8 +4,9 @@ libs = ['lib', '../../node_modules'] cache_path = 'foundry-cache' out = 'foundry-out' solc_version = '0.8.23' -fs_permissions = [{ access = "read", path = "./"}] +fs_permissions = [{ access = "read", path = "./" }] ignored_warnings_from = ["contracts/test/Multicall2.sol"] +evm_version = 'shanghai' [profile.lite] -optimizer = false \ No newline at end of file +optimizer = false diff --git a/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol index fd36ae6539..8d57476342 100644 --- a/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol +++ b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol @@ -2,17 +2,25 @@ pragma solidity ^0.8.19; import 'forge-std/Test.sol'; -import { Strings } from '@openzeppelin/contracts/utils/Strings.sol'; -import { NounsDAOLogicV4 } from '../../../contracts/governance/NounsDAOLogicV4.sol'; -import { ProposeDAOUpgradeMainnet } from '../../../script/DAOUpgrade/ProposeDAOUpgradeMainnet.s.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; -import { NounsDAOData } from '../../../contracts/governance/data/NounsDAOData.sol'; -import { DeployAuctionHouseV2Mainnet } from '../../../script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol'; -import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; -import { NounsAuctionHousePreV2Migration } from '../../../contracts/NounsAuctionHousePreV2Migration.sol'; -import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; +import { NounsAuctionHouseV3 } from '../../../contracts/NounsAuctionHouseV3.sol'; +import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { INounsAuctionHouseV3 } from '../../../contracts/interfaces/INounsAuctionHouseV3.sol'; +import { IChainalysisSanctionsList } from '../../../contracts/external/chainalysis/IChainalysisSanctionsList.sol'; + +contract ChainalysisSanctionsListMock is IChainalysisSanctionsList { + mapping(address => bool) public sanctioned; + + function isSanctioned(address addr) external view returns (bool) { + return sanctioned[addr]; + } + + function setSanctioned(address addr, bool value) public { + sanctioned[addr] = value; + } +} abstract contract UpgradeMainnetForkBaseTest is Test { address public constant NOUNDERS = 0x2573C60a6D127755aA2DC85e342F7da2378a0Cc5; @@ -34,7 +42,7 @@ abstract contract UpgradeMainnetForkBaseTest is Test { bytes[] calldatas; function setUp() public virtual { - vm.createSelectFork(vm.envString('RPC_MAINNET'), 19127187); + vm.createSelectFork(vm.envString('RPC_MAINNET'), 21473045); // Get votes vm.prank(NOUNDERS); @@ -64,32 +72,6 @@ abstract contract UpgradeMainnetForkBaseTest is Test { proposalId = NOUNS_DAO_PROXY_MAINNET.propose(targets_, values_, signatures_, calldatas_, 'my proposal'); } - function propose( - address target, - uint256 value, - string memory signature, - bytes memory data, - uint32 clientId - ) internal returns (uint256 proposalId) { - vm.prank(proposerAddr); - address[] memory targets_ = new address[](1); - targets_[0] = target; - uint256[] memory values_ = new uint256[](1); - values_[0] = value; - string[] memory signatures_ = new string[](1); - signatures_[0] = signature; - bytes[] memory calldatas_ = new bytes[](1); - calldatas_[0] = data; - proposalId = NOUNS_DAO_PROXY_MAINNET.propose( - targets_, - values_, - signatures_, - calldatas_, - 'my proposal', - clientId - ); - } - function voteAndExecuteProposal(uint256 proposalId) internal { NounsDAOTypes.ProposalCondensedV2 memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); @@ -108,269 +90,136 @@ abstract contract UpgradeMainnetForkBaseTest is Test { } } -contract DAOUpgradeMainnetForkTest is UpgradeMainnetForkBaseTest { - function setUp() public virtual override { - super.setUp(); - - // Deploy the latest DAO logic - vm.setEnv('DEPLOYER_PRIVATE_KEY', '0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'); - newLogic = address(new NounsDAOLogicV4()); - - // Propose the upgrade - vm.setEnv('PROPOSER_KEY', '0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); - vm.setEnv('DAO_V3_IMPL', Strings.toHexString(uint160(newLogic), 20)); - vm.setEnv('PROPOSAL_DESCRIPTION_FILE', 'test/foundry/Upgrade/proposal-description.txt'); - uint256 proposalId = new ProposeDAOUpgradeMainnet().run(); - - // Execute the upgrade - voteAndExecuteProposal(proposalId); - } - - function test_daoUpgradeWorked() public { - assertTrue(CURRENT_DAO_IMPL != NOUNS_DAO_PROXY_MAINNET.implementation()); - assertEq(newLogic, NOUNS_DAO_PROXY_MAINNET.implementation()); - } - - function test_givenRecentBitPacking_creationBlockAndProposalIdValuesAreLegit() public { - NounsDAOTypes.ProposalCondensedV3 memory prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(493); - - assertEq(prop.id, 493); - assertEq(prop.creationBlock, 19093670); - assertEq(getProposalDataForRewards(493).creationTimestamp, 0); - - prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(474); - - assertEq(prop.id, 474); - assertEq(prop.creationBlock, 18836862); - assertEq(getProposalDataForRewards(474).creationTimestamp, 0); - } - - function test_creationTimestampAndBlock_setOnNewProposals() public { - assertTrue(block.timestamp > 0); - assertTrue(block.number > 0); - uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', ''); - - NounsDAOTypes.ProposalCondensedV3 memory prop = NOUNS_DAO_PROXY_MAINNET.proposalsV3(proposalId); - - assertEq(getProposalDataForRewards(proposalId).creationTimestamp, block.timestamp); - assertEq(prop.creationBlock, block.number); - } - - function test_adminFunctions_workUsingTheNewFallbackDesign() public { - uint256 currentForkPeriod = NOUNS_DAO_PROXY_MAINNET.forkPeriod(); - uint256 expectedForkPeriod = currentForkPeriod + 1; - - uint256 proposalId = propose( - address(NOUNS_DAO_PROXY_MAINNET), - 0, - '_setForkPeriod(uint256)', - abi.encode(expectedForkPeriod) - ); - voteAndExecuteProposal(proposalId); - - assertEq(expectedForkPeriod, NOUNS_DAO_PROXY_MAINNET.forkPeriod()); - - uint256 currentVotingDelay = NOUNS_DAO_PROXY_MAINNET.votingDelay(); - uint256 expectedVotingDelay = currentVotingDelay - 1; - - proposalId = propose( - address(NOUNS_DAO_PROXY_MAINNET), - 0, - '_setVotingDelay(uint256)', - abi.encode(expectedVotingDelay) - ); - voteAndExecuteProposal(proposalId); - - assertEq(expectedVotingDelay, NOUNS_DAO_PROXY_MAINNET.votingDelay()); - } - - function test_voteSnapshotBlockSwitchProposalId_zeroOutWorks() public { - assertNotEq(NOUNS_DAO_PROXY_MAINNET.voteSnapshotBlockSwitchProposalId(), 0); - - uint256 proposalId = propose( - address(NOUNS_DAO_PROXY_MAINNET), - 0, - '_zeroOutVoteSnapshotBlockSwitchProposalId()', - '' - ); - voteAndExecuteProposal(proposalId); - - assertEq(NOUNS_DAO_PROXY_MAINNET.voteSnapshotBlockSwitchProposalId(), 0); - } - - function test_clientId_savedOnProposals() public { - uint32 expectedClientId = 42; - uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', '', expectedClientId); - - NounsDAOTypes.ProposalForRewards memory propsData = getProposalDataForRewards(proposalId); - assertEq(expectedClientId, propsData.clientId); - } - - function getProposalDataForRewards( - uint256 proposalId - ) internal view returns (NounsDAOTypes.ProposalForRewards memory) { - return - NOUNS_DAO_PROXY_MAINNET.proposalDataForRewards(proposalId, proposalId, 0, false, false, new uint32[](0))[0]; - } - - function test_clientId_savedOnVotes() public { - uint256 proposalId = propose(address(NOUNS_DAO_PROXY_MAINNET), 0, '', ''); - NounsDAOTypes.ProposalCondensedV2 memory propInfo = NOUNS_DAO_PROXY_MAINNET.proposals(proposalId); - vm.roll(propInfo.startBlock + 1); - - uint32 clientId1 = 42; - uint32 clientId2 = 142; - - vm.prank(proposerAddr, origin); - NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1, clientId1); - vm.prank(WHALE, origin); - NOUNS_DAO_PROXY_MAINNET.castRefundableVote(proposalId, 1, clientId2); - - uint32[] memory clientIds = new uint32[](2); - clientIds[0] = clientId1; - clientIds[1] = clientId2; - - NounsDAOTypes.ProposalForRewards[] memory propsData = NOUNS_DAO_PROXY_MAINNET.proposalDataForRewards( - proposalId, - proposalId, - 0, - false, - false, - clientIds - ); - NounsDAOTypes.ClientVoteData[] memory voteData = propsData[0].voteData; - - assertEq(voteData[0].txs, 1); - assertEq(voteData[0].votes, nouns.getCurrentVotes(proposerAddr)); - assertEq(voteData[1].txs, 1); - assertEq(voteData[1].votes, nouns.getCurrentVotes(WHALE)); - } - - function test_nounsCandidatesUsingProposalsV3GetterWorks() public { - NounsDAOData d = NounsDAOData(NOUNS_DAO_DATA_PROXY); - address[] memory targets = new address[](1); - targets[0] = address(0); - uint256[] memory values = new uint256[](1); - values[0] = 0; - string[] memory signatures = new string[](1); - signatures[0] = ''; - bytes[] memory calldatas = new bytes[](1); - calldatas[0] = bytes(''); - vm.expectRevert(NounsDAOData.ProposalToUpdateMustBeUpdatable.selector); - d.createProposalCandidate{ value: 0.1 ether }(targets, values, signatures, calldatas, 'desc', 'slug', 400); - } -} - contract AuctionHouseUpgradeMainnetForkTest is UpgradeMainnetForkBaseTest { - uint256 v1NounId; - uint256 v1Amount; - uint256 v1StartTime; - uint256 v1EndTime; - address v1Bidder; - bool v1Settled; - address v1NounsAddress; - address v1WethAddress; - address v1Owner; - uint256 v1Duration; - uint8 v1MinBidIncrementPercentage; - uint256 v1ReservePrice; - uint256 v1TimeBuffer; + address v2NounsAddress; + address v2WethAddress; + address v2Owner; + uint256 v2Duration; + uint8 v2MinBidIncrementPercentage; + uint256 v2ReservePrice; + uint256 v2TimeBuffer; + INounsAuctionHouseV2.AuctionV2View auctionV2State; + ChainalysisSanctionsListMock sanctionsOracle; + + address user1 = makeAddr('user1'); + address user2 = makeAddr('user2'); function setUp() public override { super.setUp(); - // Save AH V1 state before the upgrade - NounsAuctionHouse ahv1 = NounsAuctionHouse(AUCTION_HOUSE_PROXY_MAINNET); - (v1NounId, v1Amount, v1StartTime, v1EndTime, v1Bidder, v1Settled) = ahv1.auction(); - v1NounsAddress = address(ahv1.nouns()); - v1WethAddress = address(ahv1.weth()); - v1Owner = ahv1.owner(); - v1Duration = ahv1.duration(); - v1MinBidIncrementPercentage = ahv1.minBidIncrementPercentage(); - v1ReservePrice = ahv1.reservePrice(); - v1TimeBuffer = ahv1.timeBuffer(); + vm.deal(user1, 100 ether); + vm.deal(user2, 100 ether); - // Propose and execute the upgrade proposal + // Save AH V2 state before the upgrade + INounsAuctionHouseV2 ahv2 = INounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); + auctionV2State = ahv2.auction(); - NounsAuctionHouseV2 newLogic = new NounsAuctionHouseV2(ahv1.nouns(), ahv1.weth(), ahv1.duration()); - NounsAuctionHousePreV2Migration migratorLogic = new NounsAuctionHousePreV2Migration(); + v2NounsAddress = address(ahv2.nouns()); + v2WethAddress = address(ahv2.weth()); + v2Owner = IOwner(address(ahv2)).owner(); + v2Duration = ahv2.duration(); + v2MinBidIncrementPercentage = ahv2.minBidIncrementPercentage(); + v2ReservePrice = ahv2.reservePrice(); + v2TimeBuffer = ahv2.timeBuffer(); - uint256 txCount = 3; + NounsAuctionHouseV3 ahv3 = new NounsAuctionHouseV3(ahv2.nouns(), ahv2.weth(), ahv2.duration()); + sanctionsOracle = new ChainalysisSanctionsListMock(); + + // Propose upgrade + uint256 txCount = 2; address[] memory targets = new address[](txCount); uint256[] memory values = new uint256[](txCount); string[] memory signatures = new string[](txCount); bytes[] memory calldatas = new bytes[](txCount); - // proxyAdmin.upgrade(proxy, address(migratorLogic)); + // proxyAdmin.upgrade(proxy, address(newLogic)); targets[0] = AUCTION_HOUSE_PROXY_ADMIN_MAINNET; signatures[0] = 'upgrade(address,address)'; - calldatas[0] = abi.encode(AUCTION_HOUSE_PROXY_MAINNET, address(migratorLogic)); - - // // migrator.migrate(); + calldatas[0] = abi.encode(AUCTION_HOUSE_PROXY_MAINNET, address(ahv3)); + // auctionHouse.setSanctionsOracle(sanctionsOracle); targets[1] = AUCTION_HOUSE_PROXY_MAINNET; - signatures[1] = 'migrate()'; - - // proxyAdmin.upgrade(proxy, address(newLogic)); - targets[2] = AUCTION_HOUSE_PROXY_ADMIN_MAINNET; - signatures[2] = 'upgrade(address,address)'; - calldatas[2] = abi.encode(AUCTION_HOUSE_PROXY_MAINNET, address(newLogic)); - + signatures[1] = 'setSanctionsOracle(address)'; + calldatas[1] = abi.encode(address(sanctionsOracle)); vm.prank(proposerAddr); uint256 proposalId = NOUNS_DAO_PROXY_MAINNET.propose( targets, values, signatures, calldatas, - 'Upgrading to AuctionHouseV2' + 'Upgrading to AuctionHouseV3' ); - voteAndExecuteProposal(proposalId); } - function test_auctionState_survivesUpgrade() public { - NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); - NounsAuctionHouseV2.AuctionV2View memory auctionV2State = auctionV2.auction(); - - assertEq(auctionV2State.nounId, v1NounId); - assertEq(auctionV2State.amount, v1Amount); - assertEq(auctionV2State.startTime, v1StartTime); - assertEq(auctionV2State.endTime, v1EndTime); - assertEq(auctionV2State.bidder, v1Bidder); - assertEq(auctionV2State.settled, false); - - assertEq(address(auctionV2.nouns()), v1NounsAddress); - assertEq(address(auctionV2.weth()), v1WethAddress); - assertEq(auctionV2.timeBuffer(), v1TimeBuffer); - assertEq(auctionV2.reservePrice(), v1ReservePrice); - assertEq(auctionV2.minBidIncrementPercentage(), v1MinBidIncrementPercentage); - assertEq(auctionV2.duration(), v1Duration); - assertEq(auctionV2.paused(), false); - assertEq(auctionV2.owner(), v1Owner); - } - - function test_bidAndSettleInV2_worksAndCapturesSettlementHistory() public { - NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); + INounsAuctionHouseV2 auctionV3 = INounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); + INounsAuctionHouseV2.AuctionV2View memory auctionV3State = auctionV3.auction(); + assertEq(auctionV3State.nounId, auctionV2State.nounId); + assertEq(auctionV3State.amount, auctionV2State.amount); + assertEq(auctionV3State.startTime, auctionV2State.startTime); + assertEq(auctionV3State.endTime, auctionV2State.endTime); + assertEq(auctionV3State.bidder, auctionV2State.bidder); + assertEq(auctionV3State.settled, false); + assertEq(address(auctionV3.nouns()), v2NounsAddress); + assertEq(address(auctionV3.weth()), v2WethAddress); + assertEq(auctionV3.timeBuffer(), v2TimeBuffer); + assertEq(auctionV3.reservePrice(), v2ReservePrice); + assertEq(auctionV3.minBidIncrementPercentage(), v2MinBidIncrementPercentage); + assertEq(auctionV3.duration(), v2Duration); + assertEq(IPausible(address(auctionV3)).paused(), false); + assertEq(IOwner(address(auctionV3)).owner(), v2Owner); + } + + function test_bidAndSettleInV3_worksAndCapturesSettlementHistory() public { + INounsAuctionHouseV2 auctionV2 = INounsAuctionHouseV2(AUCTION_HOUSE_PROXY_MAINNET); auctionV2.settleCurrentAndCreateNewAuction(); uint32 clientId = 42; uint96 nounId = auctionV2.auction().nounId; - auctionV2.createBid{ value: 0.042 ether }(nounId, clientId); vm.warp(block.timestamp + auctionV2.auction().endTime); uint32 settlementTime = uint32(block.timestamp); auctionV2.settleCurrentAndCreateNewAuction(); - - NounsAuctionHouseV2.Settlement[] memory settlements = auctionV2.getSettlementsFromIdtoTimestamp( + INounsAuctionHouseV2.Settlement[] memory settlements = auctionV2.getSettlementsFromIdtoTimestamp( nounId, block.timestamp, true ); - assertEq(settlements.length, 1); - NounsAuctionHouseV2.Settlement memory s = settlements[0]; + INounsAuctionHouseV2.Settlement memory s = settlements[0]; assertEq(s.nounId, nounId); assertEq(s.winner, address(this)); assertEq(s.amount, 0.042 ether); assertEq(s.clientId, clientId); assertEq(s.blockTimestamp, settlementTime); } + + function test_auctionHouseV3_rejectsBidFromSanctionedAddress() public { + INounsAuctionHouseV3 auction = INounsAuctionHouseV3(AUCTION_HOUSE_PROXY_MAINNET); + auction.settleCurrentAndCreateNewAuction(); + uint96 nounId = auction.auction().nounId; + + sanctionsOracle.setSanctioned(user1, true); + + vm.expectRevert('Sanctioned bidder'); + vm.prank(user1); + auction.createBid{ value: 0.042 ether }(nounId, 0); + } + + function test_auctionHouseV3_acceptsBidFromNonSanctionedAddress() public { + INounsAuctionHouseV3 auction = INounsAuctionHouseV3(AUCTION_HOUSE_PROXY_MAINNET); + auction.settleCurrentAndCreateNewAuction(); + uint96 nounId = auction.auction().nounId; + + sanctionsOracle.setSanctioned(user1, false); + + vm.prank(user1); + auction.createBid{ value: 0.042 ether }(nounId, 0); + } +} + +interface IOwner { + function owner() external view returns (address); +} + +interface IPausible { + function paused() external view returns (bool); } From 37bd6535f059c3a0843d5e454bd2d145d16bf70c Mon Sep 17 00:00:00 2001 From: eladmallel Date: Tue, 24 Dec 2024 10:33:39 -0500 Subject: [PATCH 3/7] ah: update tests to use V3 --- .../contracts/NounsAuctionHouseV3.sol | 10 +- .../NounsAuctionHouseGasSnapshot.t.sol | 110 ----------------- .../test/foundry/NounsAuctionHouseV2.t.sol | 115 +----------------- .../foundry/Upgrade/UpgradeMainnetFork.t.sol | 14 +-- .../foundry/helpers/AuctionHouseUpgrader.sol | 40 ------ .../helpers/ChainalysisSanctionsListMock.sol | 16 +++ .../test/foundry/helpers/DeployUtils.sol | 20 ++- .../test/foundry/helpers/DeployUtilsV3.sol | 25 +++- .../foundry/rewards/ProposalRewards.t.sol | 7 -- .../test/foundry/rewards/Rewards.t.sol | 7 -- 10 files changed, 58 insertions(+), 306 deletions(-) delete mode 100644 packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol delete mode 100644 packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol create mode 100644 packages/nouns-contracts/test/foundry/helpers/ChainalysisSanctionsListMock.sol diff --git a/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol b/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol index c14b6a8db6..03810d51b4 100644 --- a/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol +++ b/packages/nouns-contracts/contracts/NounsAuctionHouseV3.sol @@ -87,7 +87,8 @@ contract NounsAuctionHouseV3 is function initialize( uint192 _reservePrice, uint56 _timeBuffer, - uint8 _minBidIncrementPercentage + uint8 _minBidIncrementPercentage, + IChainalysisSanctionsList _sanctionsOracle ) external initializer { __Pausable_init(); __ReentrancyGuard_init(); @@ -98,6 +99,9 @@ contract NounsAuctionHouseV3 is reservePrice = _reservePrice; timeBuffer = _timeBuffer; minBidIncrementPercentage = _minBidIncrementPercentage; + sanctionsOracle = _sanctionsOracle; + + emit SanctionsOracleSet(address(_sanctionsOracle)); } /** @@ -247,7 +251,7 @@ contract NounsAuctionHouseV3 is * @notice Set the sanctions oracle address. * @dev Only callable by the owner. */ - function setSanctionsOracle(address newSanctionsOracle) external onlyOwner { + function setSanctionsOracle(address newSanctionsOracle) public onlyOwner { sanctionsOracle = IChainalysisSanctionsList(newSanctionsOracle); emit SanctionsOracleSet(newSanctionsOracle); @@ -334,7 +338,7 @@ contract NounsAuctionHouseV3 is } return success; } - + /** * @notice Revert if `sanctionsOracle` is set and `account` is sanctioned. */ diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol deleted file mode 100644 index a16f300791..0000000000 --- a/packages/nouns-contracts/test/foundry/NounsAuctionHouseGasSnapshot.t.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.15; - -import { INounsAuctionHouse } from '../../contracts/interfaces/INounsAuctionHouse.sol'; -import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; -import { INounsToken } from '../../contracts/interfaces/INounsToken.sol'; -import { DeployUtils } from './helpers/DeployUtils.sol'; -import { AuctionHouseUpgrader } from './helpers/AuctionHouseUpgrader.sol'; -import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol'; -import { NounsAuctionHouseProxyAdmin } from '../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; - -abstract contract NounsAuctionHouseBaseTest is DeployUtils { - INounsAuctionHouse auctionHouse; - INounsToken nouns; - address noundersDAO = makeAddr('noundersDAO'); - address owner = makeAddr('owner'); - NounsAuctionHouseProxy auctionHouseProxy; - NounsAuctionHouseProxyAdmin proxyAdmin; - uint256[] nounIds; - - function setUp() public virtual { - ( - NounsAuctionHouseProxy auctionHouseProxy_, - NounsAuctionHouseProxyAdmin proxyAdmin_ - ) = _deployAuctionHouseV1AndToken(owner, noundersDAO, address(0)); - auctionHouseProxy = auctionHouseProxy_; - proxyAdmin = proxyAdmin_; - - auctionHouse = INounsAuctionHouse(address(auctionHouseProxy_)); - - vm.prank(owner); - auctionHouse.unpause(); - } -} - -contract NounsAuctionHouse_GasSnapshot is NounsAuctionHouseBaseTest { - function test_createOneBid() public { - auctionHouse.createBid{ value: 1 ether }(1); - } - - function test_createTwoBids() public { - auctionHouse.createBid{ value: 1 ether }(1); - auctionHouse.createBid{ value: 1.1 ether }(1); - } - - function test_settleCurrentAndCreateNewAuction() public { - vm.warp(block.timestamp + 1.1 days); - - auctionHouse.settleCurrentAndCreateNewAuction(); - } -} - -contract NounsAuctionHouseV2_GasSnapshot is NounsAuctionHouse_GasSnapshot { - function setUp() public virtual override { - super.setUp(); - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionHouseProxy); - } -} - -contract NounsAuctionHouseV2WarmedUp_GasSnapshot is NounsAuctionHouseV2_GasSnapshot { - function setUp() public override { - super.setUp(); - INounsAuctionHouseV2(address(auctionHouse)).warmUpSettlementState(1, 4); - } -} - -contract NounsAuctionHouseV2_HistoricPrices_GasSnapshot is NounsAuctionHouseBaseTest { - INounsAuctionHouseV2 auctionHouseV2; - - function setUp() public virtual override { - super.setUp(); - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionHouseProxy); - auctionHouseV2 = INounsAuctionHouseV2(address(auctionHouse)); - - for (uint256 i = 1; i <= 200; ++i) { - address bidder = makeAddr(vm.toString(i)); - bidAndWinCurrentAuction(bidder, i * 1e18); - } - } - - function bidAndWinCurrentAuction(address bidder, uint256 bid) internal returns (uint256) { - uint128 nounId = auctionHouseV2.auction().nounId; - uint40 endTime = auctionHouseV2.auction().endTime; - vm.deal(bidder, bid); - vm.prank(bidder); - auctionHouseV2.createBid{ value: bid }(nounId); - vm.warp(endTime); - auctionHouseV2.settleCurrentAndCreateNewAuction(); - return block.timestamp; - } - - function test_getSettlements_90() public { - INounsAuctionHouseV2.Settlement[] memory prices = auctionHouseV2.getSettlements(90, false); - assertEq(prices.length, 90); - } - - function test_getPrices_90() public { - uint256[] memory prices = auctionHouseV2.getPrices(90); - assertEq(prices.length, 90); - } - - function test_getSettlements_range_100() public { - INounsAuctionHouseV2.Settlement[] memory settlements = auctionHouseV2.getSettlements(0, 100, false); - assertEq(settlements.length, 100); - } - - function test_warmUp() public { - auctionHouseV2.warmUpSettlementState(0, 1000); - } -} diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol index 9eff37bd1a..10dd192b22 100644 --- a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.15; import 'forge-std/Test.sol'; import { DeployUtils } from './helpers/DeployUtils.sol'; -import { AuctionHouseUpgrader } from './helpers/AuctionHouseUpgrader.sol'; import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; import { NounsAuctionHouse } from '../../contracts/NounsAuctionHouse.sol'; @@ -22,13 +21,7 @@ contract NounsAuctionHouseV2TestBase is Test, DeployUtils { function setUp() public virtual { vm.warp(timestamp); - (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( - owner, - noundersDAO, - minter - ); - - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + (NounsAuctionHouseProxy auctionProxy, ) = _deployAuctionHouseAndToken(owner, noundersDAO, minter); auction = NounsAuctionHouseV2(address(auctionProxy)); @@ -165,12 +158,8 @@ contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { } function test_settleAuction_revertsWhenAuctionHasntBegunYet() public { - (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( - owner, - noundersDAO, - minter - ); - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); + (NounsAuctionHouseProxy auctionProxy, ) = _deployAuctionHouseAndToken(owner, noundersDAO, minter); + auction = NounsAuctionHouseV2(address(auctionProxy)); vm.expectRevert("Auction hasn't begun"); @@ -188,104 +177,6 @@ contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { auction.settleCurrentAndCreateNewAuction(); } - function test_V2Migration_works() public { - (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( - owner, - noundersDAO, - minter - ); - NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auctionProxy)); - vm.prank(owner); - auctionV1.unpause(); - vm.roll(block.number + 1); - (uint256 nounId, , uint256 startTime, uint256 endTime, , ) = auctionV1.auction(); - - address payable bidder = payable(address(0x142)); - uint256 amount = 142 ether; - vm.deal(bidder, amount); - vm.prank(bidder); - auctionV1.createBid{ value: amount }(nounId); - - address nounsBefore = address(auctionV1.nouns()); - address wethBefore = address(auctionV1.weth()); - - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); - - NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(address(auctionProxy)); - - IAH.AuctionV2View memory auctionV2State = auctionV2.auction(); - - assertEq(auctionV2State.nounId, nounId); - assertEq(auctionV2State.amount, amount); - assertEq(auctionV2State.startTime, startTime); - assertEq(auctionV2State.endTime, endTime); - assertEq(auctionV2State.bidder, bidder); - assertEq(auctionV2State.settled, false); - - assertEq(address(auctionV2.nouns()), nounsBefore); - assertEq(address(auctionV2.weth()), wethBefore); - assertEq(auctionV2.timeBuffer(), AUCTION_TIME_BUFFER); - assertEq(auctionV2.reservePrice(), AUCTION_RESERVE_PRICE); - assertEq(auctionV2.minBidIncrementPercentage(), AUCTION_MIN_BID_INCREMENT_PRCT); - assertEq(auctionV2.duration(), AUCTION_DURATION); - assertEq(auctionV2.paused(), false); - assertEq(auctionV2.owner(), owner); - } - - function test_V2Migration_copiesPausedWhenTrue() public { - (NounsAuctionHouseProxy auctionProxy, NounsAuctionHouseProxyAdmin proxyAdmin) = _deployAuctionHouseV1AndToken( - owner, - noundersDAO, - minter - ); - NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auctionProxy)); - vm.prank(owner); - auctionV1.unpause(); - vm.roll(block.number + 1); - (uint256 nounId, , , , , ) = auctionV1.auction(); - - address payable bidder = payable(address(0x142)); - uint256 amount = 142 ether; - vm.deal(bidder, amount); - vm.prank(bidder); - auctionV1.createBid{ value: amount }(nounId); - - vm.prank(owner); - auctionV1.pause(); - - AuctionHouseUpgrader.upgradeAuctionHouse(owner, proxyAdmin, auctionProxy); - - NounsAuctionHouseV2 auctionV2 = NounsAuctionHouseV2(address(auctionProxy)); - assertEq(auctionV2.paused(), true); - } - - function test_auctionGetter_compatibleWithV1() public { - address bidder = address(0x4242); - vm.deal(bidder, 1.1 ether); - vm.prank(bidder); - auction.createBid{ value: 1.1 ether }(1); - - NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(auction)); - - IAH.AuctionV2View memory auctionV2 = auction.auction(); - - ( - uint256 nounIdV1, - uint256 amountV1, - uint256 startTimeV1, - uint256 endTimeV1, - address payable bidderV1, - bool settledV1 - ) = auctionV1.auction(); - - assertEq(auctionV2.nounId, nounIdV1); - assertEq(auctionV2.amount, amountV1); - assertEq(auctionV2.startTime, startTimeV1); - assertEq(auctionV2.endTime, endTimeV1); - assertEq(auctionV2.bidder, bidderV1); - assertEq(auctionV2.settled, settledV1); - } - function test_setMinBidIncrementPercentage_givenNonOwnerSender_reverts() public { vm.expectRevert('Ownable: caller is not the owner'); auction.setMinBidIncrementPercentage(42); diff --git a/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol index 8d57476342..b66c736c58 100644 --- a/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol +++ b/packages/nouns-contracts/test/foundry/Upgrade/UpgradeMainnetFork.t.sol @@ -8,19 +8,7 @@ import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces. import { NounsAuctionHouseV3 } from '../../../contracts/NounsAuctionHouseV3.sol'; import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; import { INounsAuctionHouseV3 } from '../../../contracts/interfaces/INounsAuctionHouseV3.sol'; -import { IChainalysisSanctionsList } from '../../../contracts/external/chainalysis/IChainalysisSanctionsList.sol'; - -contract ChainalysisSanctionsListMock is IChainalysisSanctionsList { - mapping(address => bool) public sanctioned; - - function isSanctioned(address addr) external view returns (bool) { - return sanctioned[addr]; - } - - function setSanctioned(address addr, bool value) public { - sanctioned[addr] = value; - } -} +import { ChainalysisSanctionsListMock } from '../helpers/ChainalysisSanctionsListMock.sol'; abstract contract UpgradeMainnetForkBaseTest is Test { address public constant NOUNDERS = 0x2573C60a6D127755aA2DC85e342F7da2378a0Cc5; diff --git a/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol b/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol deleted file mode 100644 index 6c70290b5c..0000000000 --- a/packages/nouns-contracts/test/foundry/helpers/AuctionHouseUpgrader.sol +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; -import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; -import { NounsAuctionHousePreV2Migration } from '../../../contracts/NounsAuctionHousePreV2Migration.sol'; -import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; -import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; -import 'forge-std/Vm.sol'; - -library AuctionHouseUpgrader { - Vm private constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code'))))); - - function upgradeAuctionHouse( - address owner, - NounsAuctionHouseProxyAdmin proxyAdmin, - NounsAuctionHouseProxy proxy - ) internal { - NounsAuctionHouse auctionV1 = NounsAuctionHouse(address(proxy)); - - NounsAuctionHouseV2 newLogic = new NounsAuctionHouseV2( - auctionV1.nouns(), - auctionV1.weth(), - auctionV1.duration() - ); - NounsAuctionHousePreV2Migration migratorLogic = new NounsAuctionHousePreV2Migration(); - - vm.startPrank(owner); - - // not using upgradeAndCall because the call must come from the auction house owner - // which is owner, not the proxy admin - - proxyAdmin.upgrade(proxy, address(migratorLogic)); - NounsAuctionHousePreV2Migration migrator = NounsAuctionHousePreV2Migration(address(proxy)); - migrator.migrate(); - proxyAdmin.upgrade(proxy, address(newLogic)); - - vm.stopPrank(); - } -} diff --git a/packages/nouns-contracts/test/foundry/helpers/ChainalysisSanctionsListMock.sol b/packages/nouns-contracts/test/foundry/helpers/ChainalysisSanctionsListMock.sol new file mode 100644 index 0000000000..e93e80a414 --- /dev/null +++ b/packages/nouns-contracts/test/foundry/helpers/ChainalysisSanctionsListMock.sol @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { IChainalysisSanctionsList } from '../../../contracts/external/chainalysis/IChainalysisSanctionsList.sol'; + +contract ChainalysisSanctionsListMock is IChainalysisSanctionsList { + mapping(address => bool) public sanctioned; + + function isSanctioned(address addr) external view returns (bool) { + return sanctioned[addr]; + } + + function setSanctioned(address addr, bool value) public { + sanctioned[addr] = value; + } +} diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol index b13c75b75f..ba353e766f 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtils.sol @@ -16,8 +16,9 @@ import { NounsToken } from '../../../contracts/NounsToken.sol'; import { Inflator } from '../../../contracts/Inflator.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; -import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; +import { NounsAuctionHouseV3 } from '../../../contracts/NounsAuctionHouseV3.sol'; import { WETH } from '../../../contracts/test/WETH.sol'; +import { ChainalysisSanctionsListMock } from './ChainalysisSanctionsListMock.sol'; abstract contract DeployUtils is Test, DescriptorHelpers { uint256 constant TIMELOCK_DELAY = 2 days; @@ -30,28 +31,25 @@ abstract contract DeployUtils is Test, DescriptorHelpers { uint8 constant AUCTION_MIN_BID_INCREMENT_PRCT = 2; uint256 constant AUCTION_DURATION = 24 hours; - function _deployAuctionHouseV1AndToken( + function _deployAuctionHouseAndToken( address owner, address noundersDAO, address minter ) internal returns (NounsAuctionHouseProxy, NounsAuctionHouseProxyAdmin) { - NounsAuctionHouse logic = new NounsAuctionHouse(); NounsToken token = deployToken(noundersDAO, minter); - WETH weth = new WETH(); + NounsAuctionHouseV3 logic = new NounsAuctionHouseV3(token, address(new WETH()), AUCTION_DURATION); NounsAuctionHouseProxyAdmin admin = new NounsAuctionHouseProxyAdmin(); admin.transferOwnership(owner); bytes memory data = abi.encodeWithSelector( - NounsAuctionHouse.initialize.selector, - address(token), - address(weth), - AUCTION_TIME_BUFFER, + NounsAuctionHouseV3.initialize.selector, AUCTION_RESERVE_PRICE, + AUCTION_TIME_BUFFER, AUCTION_MIN_BID_INCREMENT_PRCT, - AUCTION_DURATION + new ChainalysisSanctionsListMock() ); NounsAuctionHouseProxy proxy = new NounsAuctionHouseProxy(address(logic), address(admin), data); - NounsAuctionHouse auction = NounsAuctionHouse(address(proxy)); + NounsAuctionHouseV3 auction = NounsAuctionHouseV3(address(proxy)); auction.transferOwnership(owner); token.setMinter(address(proxy)); @@ -117,4 +115,4 @@ abstract contract DeployUtils is Test, DescriptorHelpers { bytes32 slot = bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1); return address(uint160(uint256(vm.load(proxy, slot)))); } -} \ No newline at end of file +} diff --git a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol index d292131734..10941bab1e 100644 --- a/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol +++ b/packages/nouns-contracts/test/foundry/helpers/DeployUtilsV3.sol @@ -9,7 +9,7 @@ import { NounsDAOProxyV3 } from '../../../contracts/governance/NounsDAOProxyV3.s import { NounsDAOForkEscrow } from '../../../contracts/governance/fork/NounsDAOForkEscrow.sol'; import { NounsDAOExecutorV2 } from '../../../contracts/governance/NounsDAOExecutorV2.sol'; import { ERC1967Proxy } from '@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol'; -import { NounsAuctionHouse } from '../../../contracts/NounsAuctionHouse.sol'; +import { NounsAuctionHouseV3 } from '../../../contracts/NounsAuctionHouseV3.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; @@ -21,6 +21,9 @@ import { NounsAuctionHouseFork } from '../../../contracts/governance/fork/newdao import { NounsDAOLogicV1Fork } from '../../../contracts/governance/fork/newdao/governance/NounsDAOLogicV1Fork.sol'; import { NounsDAOTypes } from '../../../contracts/governance/NounsDAOInterfaces.sol'; import { INounsDAOLogic } from '../../../contracts/interfaces/INounsDAOLogic.sol'; +import { INounsToken } from '../../../contracts/interfaces/INounsToken.sol'; +import { WETH } from '../../../contracts/test/WETH.sol'; +import { ChainalysisSanctionsListMock } from './ChainalysisSanctionsListMock.sol'; abstract contract DeployUtilsV3 is DeployUtils { NounsAuctionHouseProxyAdmin auctionHouseProxyAdmin; @@ -88,8 +91,14 @@ abstract contract DeployUtilsV3 is DeployUtils { t.timelock.initialize(address(1), TIMELOCK_DELAY); auctionHouseProxyAdmin = new NounsAuctionHouseProxyAdmin(); + address predictedTokenAddress = computeCreateAddress(address(this), vm.getNonce(address(this)) + 9); + NounsAuctionHouseV3 auctionHouseImpl = new NounsAuctionHouseV3( + INounsToken(predictedTokenAddress), + address(new WETH()), + auctionDuration + ); NounsAuctionHouseProxy auctionProxy = new NounsAuctionHouseProxy( - address(new NounsAuctionHouse()), + address(auctionHouseImpl), address(auctionHouseProxyAdmin), '' ); @@ -103,6 +112,9 @@ abstract contract DeployUtilsV3 is DeployUtils { new ProxyRegistryMock() ); t.nounsToken.transferOwnership(address(t.timelock)); + + require(predictedTokenAddress == address(t.nounsToken), 'Token address mismatch'); + address daoLogicImplementation = address(new NounsDAOLogicV4()); uint256 nonce = vm.getNonce(address(this)); @@ -149,8 +161,15 @@ abstract contract DeployUtilsV3 is DeployUtils { address(new NounsDAOForkEscrow(address(dao), address(t.nounsToken))); + ChainalysisSanctionsListMock sanctionsOracle = new ChainalysisSanctionsListMock(); + vm.prank(address(t.timelock)); - NounsAuctionHouse(address(auctionProxy)).initialize(t.nounsToken, makeAddr('weth'), 2, 0, 1, auctionDuration); + NounsAuctionHouseV3(address(auctionProxy)).initialize({ + _reservePrice: 0, + _timeBuffer: 2, + _minBidIncrementPercentage: 1, + _sanctionsOracle: sanctionsOracle + }); vm.prank(address(t.timelock)); t.timelock.setPendingAdmin(address(dao)); diff --git a/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol b/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol index 4fec95ba5f..f7651d161d 100644 --- a/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol +++ b/packages/nouns-contracts/test/foundry/rewards/ProposalRewards.t.sol @@ -5,7 +5,6 @@ import { NounsDAOLogicBaseTest } from '../NounsDAOLogic/NounsDAOLogicBaseTest.so import { ERC20Mock } from '../helpers/ERC20Mock.sol'; import { Rewards } from '../../../contracts/client-incentives/Rewards.sol'; import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; -import { AuctionHouseUpgrader } from '../helpers/AuctionHouseUpgrader.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { RewardsDeployer } from '../../../script/Rewards/RewardsDeployer.sol'; @@ -81,12 +80,6 @@ abstract contract BaseProposalRewardsTest is NounsDAOLogicBaseTest { auctionHouse = INounsAuctionHouseV2(minter); vm.prank(address(dao.timelock())); auctionHouse.unpause(); - - AuctionHouseUpgrader.upgradeAuctionHouse( - address(dao.timelock()), - auctionHouseProxyAdmin, - NounsAuctionHouseProxy(payable(address(auctionHouse))) - ); } function proposeVoteAndEndVotingPeriod(uint32 clientId) internal returns (uint32) { diff --git a/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol b/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol index 6784fdb023..532c560a60 100644 --- a/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol +++ b/packages/nouns-contracts/test/foundry/rewards/Rewards.t.sol @@ -5,7 +5,6 @@ import { NounsDAOLogicBaseTest } from '../NounsDAOLogic/NounsDAOLogicBaseTest.so import { Rewards } from '../../../contracts/client-incentives/Rewards.sol'; import { NounsToken } from '../../../contracts/NounsToken.sol'; import { INounsAuctionHouseV2 } from '../../../contracts/interfaces/INounsAuctionHouseV2.sol'; -import { AuctionHouseUpgrader } from '../helpers/AuctionHouseUpgrader.sol'; import { NounsAuctionHouseProxy } from '../../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { ERC20Mock } from '../helpers/ERC20Mock.sol'; import { RewardsDeployer } from '../../../script/Rewards/RewardsDeployer.sol'; @@ -68,12 +67,6 @@ abstract contract RewardsBaseTest is NounsDAOLogicBaseTest { _mintTo(voter3); } - AuctionHouseUpgrader.upgradeAuctionHouse( - address(dao.timelock()), - auctionHouseProxyAdmin, - NounsAuctionHouseProxy(payable(address(auctionHouse))) - ); - rewards.registerClient('some client', 'some client description'); vm.prank(client1Wallet); CLIENT_ID = rewards.registerClient('client1', 'client1 description'); From 772118ee5cb38fde5413f975c6a144723b631fba Mon Sep 17 00:00:00 2001 From: eladmallel Date: Tue, 24 Dec 2024 10:44:05 -0500 Subject: [PATCH 4/7] ah: add sanctions unit test --- .../test/foundry/NounsAuctionHouseV2.t.sol | 41 ++++++++++++++----- .../foundry/helpers/BidderWithGasGriefing.sol | 4 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol index 10dd192b22..6649808933 100644 --- a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol +++ b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol @@ -6,24 +6,25 @@ import { DeployUtils } from './helpers/DeployUtils.sol'; import { NounsAuctionHouseProxy } from '../../contracts/proxies/NounsAuctionHouseProxy.sol'; import { NounsAuctionHouseProxyAdmin } from '../../contracts/proxies/NounsAuctionHouseProxyAdmin.sol'; import { NounsAuctionHouse } from '../../contracts/NounsAuctionHouse.sol'; -import { INounsAuctionHouseV2 as IAH } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; -import { NounsAuctionHouseV2 } from '../../contracts/NounsAuctionHouseV2.sol'; +import { INounsAuctionHouseV3 as IAH } from '../../contracts/interfaces/INounsAuctionHouseV3.sol'; +import { NounsAuctionHouseV3 } from '../../contracts/NounsAuctionHouseV3.sol'; import { BidderWithGasGriefing } from './helpers/BidderWithGasGriefing.sol'; +import { ChainalysisSanctionsListMock } from './helpers/ChainalysisSanctionsListMock.sol'; -contract NounsAuctionHouseV2TestBase is Test, DeployUtils { +contract NounsAuctionHouseV3TestBase is Test, DeployUtils { address owner = address(0x1111); address noundersDAO = address(0x2222); address minter = address(0x3333); uint256[] nounIds; uint32 timestamp = 1702289583; - NounsAuctionHouseV2 auction; + NounsAuctionHouseV3 auction; function setUp() public virtual { vm.warp(timestamp); (NounsAuctionHouseProxy auctionProxy, ) = _deployAuctionHouseAndToken(owner, noundersDAO, minter); - auction = NounsAuctionHouseV2(address(auctionProxy)); + auction = NounsAuctionHouseV3(address(auctionProxy)); vm.prank(owner); auction.unpause(); @@ -56,7 +57,7 @@ contract NounsAuctionHouseV2TestBase is Test, DeployUtils { } } -contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { +contract NounsAuctionHouseV3Test is NounsAuctionHouseV3TestBase { function test_createBid_revertsGivenWrongNounId() public { uint128 nounId = auction.auction().nounId; @@ -160,7 +161,7 @@ contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { function test_settleAuction_revertsWhenAuctionHasntBegunYet() public { (NounsAuctionHouseProxy auctionProxy, ) = _deployAuctionHouseAndToken(owner, noundersDAO, minter); - auction = NounsAuctionHouseV2(address(auctionProxy)); + auction = NounsAuctionHouseV3(address(auctionProxy)); vm.expectRevert("Auction hasn't begun"); auction.settleAuction(); @@ -198,7 +199,27 @@ contract NounsAuctionHouseV2Test is NounsAuctionHouseV2TestBase { } } -abstract contract NoracleBaseTest is NounsAuctionHouseV2TestBase { +contract AuctionHouseSanctionsTest is NounsAuctionHouseV3TestBase { + address sanctionedBidder = makeAddr('sanctioned bidder'); + ChainalysisSanctionsListMock sanctionsMock; + + function setUp() public override { + super.setUp(); + sanctionsMock = ChainalysisSanctionsListMock(address(auction.sanctionsOracle())); + sanctionsMock.setSanctioned(sanctionedBidder, true); + vm.deal(sanctionedBidder, 1 ether); + } + + function test_createBid_revertsGivenSanctionedBidder() public { + uint128 nounId = auction.auction().nounId; + + vm.expectRevert('Sanctioned bidder'); + vm.prank(sanctionedBidder); + auction.createBid{ value: 1 ether }(nounId); + } +} + +abstract contract NoracleBaseTest is NounsAuctionHouseV3TestBase { uint256[] expectedPrices; IAH.Settlement[] expectedSettlements; address bidder = makeAddr('bidder'); @@ -798,7 +819,7 @@ contract NoracleTest_NoActiveAuction is NoracleBaseTest { } } -contract NounsAuctionHouseV2_setPricesTest is NoracleBaseTest { +contract NounsAuctionHouseV3_setPricesTest is NoracleBaseTest { function test_setPrices_revertsForNonOwner() public { IAH.SettlementNoClientId[] memory settlements = new IAH.SettlementNoClientId[](1); settlements[0] = IAH.SettlementNoClientId({ @@ -848,7 +869,7 @@ contract NounsAuctionHouseV2_setPricesTest is NoracleBaseTest { } } -contract NounsAuctionHouseV2_OwnerFunctionsTest is NounsAuctionHouseV2TestBase { +contract NounsAuctionHouseV3_OwnerFunctionsTest is NounsAuctionHouseV3TestBase { function test_setTimeBuffer_revertsForNonOwner() public { vm.expectRevert('Ownable: caller is not the owner'); auction.setTimeBuffer(1 days); diff --git a/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol b/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol index 50a59e1bca..80ebb2463e 100644 --- a/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol +++ b/packages/nouns-contracts/test/foundry/helpers/BidderWithGasGriefing.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.6; -import { NounsAuctionHouseV2 } from '../../../contracts/NounsAuctionHouseV2.sol'; +import { NounsAuctionHouseV3 } from '../../../contracts/NounsAuctionHouseV3.sol'; contract BidderWithGasGriefing { - function bid(NounsAuctionHouseV2 auctionHouse, uint256 nounId) public payable { + function bid(NounsAuctionHouseV3 auctionHouse, uint256 nounId) public payable { auctionHouse.createBid{ value: msg.value }(nounId); } From 614d02ebfc93d59fcbaf1d141c4ab7c4a6c9f6e0 Mon Sep 17 00:00:00 2001 From: eladmallel Date: Tue, 24 Dec 2024 10:44:42 -0500 Subject: [PATCH 5/7] ah: rename test file to v3 --- .../{NounsAuctionHouseV2.t.sol => NounsAuctionHouseV3.t.sol} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/nouns-contracts/test/foundry/{NounsAuctionHouseV2.t.sol => NounsAuctionHouseV3.t.sol} (100%) diff --git a/packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol b/packages/nouns-contracts/test/foundry/NounsAuctionHouseV3.t.sol similarity index 100% rename from packages/nouns-contracts/test/foundry/NounsAuctionHouseV2.t.sol rename to packages/nouns-contracts/test/foundry/NounsAuctionHouseV3.t.sol From 63626a855a980550d7507813de45adf2637a8b97 Mon Sep 17 00:00:00 2001 From: eladmallel Date: Tue, 24 Dec 2024 10:56:59 -0500 Subject: [PATCH 6/7] ah: remove V2 --- .../contracts/NounsAuctionHouseV2.sol | 555 ------------------ .../DeployAuctionHouseV2Base.s.sol | 28 - .../DeployAuctionHouseV2Mainnet.s.sol | 10 - .../DeployAuctionHouseV2Sepolia.s.sol | 10 - 4 files changed, 603 deletions(-) delete mode 100644 packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol delete mode 100644 packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol delete mode 100644 packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol delete mode 100644 packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol diff --git a/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol b/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol deleted file mode 100644 index 1ceacec99b..0000000000 --- a/packages/nouns-contracts/contracts/NounsAuctionHouseV2.sol +++ /dev/null @@ -1,555 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 - -/// @title The Nouns DAO auction house - -/********************************* - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░██░░░████░░██░░░████░░░ * - * ░░██████░░░████████░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░██░░██░░░████░░██░░░████░░░ * - * ░░░░░░█████████░░█████████░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - * ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ * - *********************************/ - -// LICENSE -// NounsAuctionHouse.sol is a modified version of Zora's AuctionHouse.sol: -// https://github.com/ourzora/auction-house/blob/54a12ec1a6cf562e49f0a4917990474b11350a2d/contracts/AuctionHouse.sol -// -// AuctionHouse.sol source code Copyright Zora licensed under the GPL-3.0 license. -// With modifications by Nounders DAO. - -pragma solidity ^0.8.19; - -import { PausableUpgradeable } from '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; -import { ReentrancyGuardUpgradeable } from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol'; -import { OwnableUpgradeable } from '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol'; -import { IERC20 } from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; -import { INounsAuctionHouseV2 } from './interfaces/INounsAuctionHouseV2.sol'; -import { INounsToken } from './interfaces/INounsToken.sol'; -import { IWETH } from './interfaces/IWETH.sol'; - -/** - * @dev The contract inherits from PausableUpgradeable & ReentrancyGuardUpgradeable most of all the keep the same - * storage layout as the NounsAuctionHouse contract - */ -contract NounsAuctionHouseV2 is - INounsAuctionHouseV2, - PausableUpgradeable, - ReentrancyGuardUpgradeable, - OwnableUpgradeable -{ - /// @notice A hard-coded cap on time buffer to prevent accidental auction disabling if set with a very high value. - uint56 public constant MAX_TIME_BUFFER = 1 days; - - /// @notice The Nouns ERC721 token contract - INounsToken public immutable nouns; - - /// @notice The address of the WETH contract - address public immutable weth; - - /// @notice The duration of a single auction - uint256 public immutable duration; - - /// @notice The minimum price accepted in an auction - uint192 public reservePrice; - - /// @notice The minimum amount of time left in an auction after a new bid is created - uint56 public timeBuffer; - - /// @notice The minimum percentage difference between the last bid amount and the current bid - uint8 public minBidIncrementPercentage; - - /// @notice The active auction - INounsAuctionHouseV2.AuctionV2 public auctionStorage; - - /// @notice The Nouns price feed state - mapping(uint256 => SettlementState) settlementHistory; - - constructor(INounsToken _nouns, address _weth, uint256 _duration) initializer { - nouns = _nouns; - weth = _weth; - duration = _duration; - } - - /** - * @notice Initialize the auction house and base contracts, - * populate configuration values, and pause the contract. - * @dev This function can only be called once. - */ - function initialize( - uint192 _reservePrice, - uint56 _timeBuffer, - uint8 _minBidIncrementPercentage - ) external initializer { - __Pausable_init(); - __ReentrancyGuard_init(); - __Ownable_init(); - - _pause(); - - reservePrice = _reservePrice; - timeBuffer = _timeBuffer; - minBidIncrementPercentage = _minBidIncrementPercentage; - } - - /** - * @notice Settle the current auction, mint a new Noun, and put it up for auction. - */ - function settleCurrentAndCreateNewAuction() external override whenNotPaused { - _settleAuction(); - _createAuction(); - } - - /** - * @notice Settle the current auction. - * @dev This function can only be called when the contract is paused. - */ - function settleAuction() external override whenPaused { - _settleAuction(); - } - - /** - * @notice Create a bid for a Noun, with a given amount. - * @dev This contract only accepts payment in ETH. - */ - function createBid(uint256 nounId) external payable override { - createBid(nounId, 0); - } - - /** - * @notice Create a bid for a Noun, with a given amount. - * @param nounId id of the Noun to bid on - * @param clientId the client which facilitate this action - * @dev This contract only accepts payment in ETH. - */ - function createBid(uint256 nounId, uint32 clientId) public payable override { - INounsAuctionHouseV2.AuctionV2 memory _auction = auctionStorage; - - (uint192 _reservePrice, uint56 _timeBuffer, uint8 _minBidIncrementPercentage) = ( - reservePrice, - timeBuffer, - minBidIncrementPercentage - ); - - require(_auction.nounId == nounId, 'Noun not up for auction'); - require(block.timestamp < _auction.endTime, 'Auction expired'); - require(msg.value >= _reservePrice, 'Must send at least reservePrice'); - require( - msg.value >= _auction.amount + ((_auction.amount * _minBidIncrementPercentage) / 100), - 'Must send more than last bid by minBidIncrementPercentage amount' - ); - - auctionStorage.clientId = clientId; - auctionStorage.amount = uint128(msg.value); - auctionStorage.bidder = payable(msg.sender); - - // Extend the auction if the bid was received within `timeBuffer` of the auction end time - bool extended = _auction.endTime - block.timestamp < _timeBuffer; - - emit AuctionBid(_auction.nounId, msg.sender, msg.value, extended); - if (clientId > 0) emit AuctionBidWithClientId(_auction.nounId, msg.value, clientId); - - if (extended) { - auctionStorage.endTime = _auction.endTime = uint40(block.timestamp + _timeBuffer); - emit AuctionExtended(_auction.nounId, _auction.endTime); - } - - address payable lastBidder = _auction.bidder; - - // Refund the last bidder, if applicable - if (lastBidder != address(0)) { - _safeTransferETHWithFallback(lastBidder, _auction.amount); - } - } - - /** - * @notice Get the current auction. - */ - function auction() external view returns (AuctionV2View memory) { - return - AuctionV2View({ - nounId: auctionStorage.nounId, - amount: auctionStorage.amount, - startTime: auctionStorage.startTime, - endTime: auctionStorage.endTime, - bidder: auctionStorage.bidder, - settled: auctionStorage.settled - }); - } - - /** - * @notice Pause the Nouns auction house. - * @dev This function can only be called by the owner when the - * contract is unpaused. While no new auctions can be started when paused, - * anyone can settle an ongoing auction. - */ - function pause() external override onlyOwner { - _pause(); - } - - /** - * @notice Unpause the Nouns auction house. - * @dev This function can only be called by the owner when the - * contract is paused. If required, this function will start a new auction. - */ - function unpause() external override onlyOwner { - _unpause(); - - if (auctionStorage.startTime == 0 || auctionStorage.settled) { - _createAuction(); - } - } - - /** - * @notice Set the auction time buffer. - * @dev Only callable by the owner. - */ - function setTimeBuffer(uint56 _timeBuffer) external override onlyOwner { - require(_timeBuffer <= MAX_TIME_BUFFER, 'timeBuffer too large'); - - timeBuffer = _timeBuffer; - - emit AuctionTimeBufferUpdated(_timeBuffer); - } - - /** - * @notice Set the auction reserve price. - * @dev Only callable by the owner. - */ - function setReservePrice(uint192 _reservePrice) external override onlyOwner { - reservePrice = _reservePrice; - - emit AuctionReservePriceUpdated(_reservePrice); - } - - /** - * @notice Set the auction minimum bid increment percentage. - * @dev Only callable by the owner. - */ - function setMinBidIncrementPercentage(uint8 _minBidIncrementPercentage) external override onlyOwner { - require(_minBidIncrementPercentage > 0, 'must be greater than zero'); - - minBidIncrementPercentage = _minBidIncrementPercentage; - - emit AuctionMinBidIncrementPercentageUpdated(_minBidIncrementPercentage); - } - - /** - * @notice Create an auction. - * @dev Store the auction details in the `auction` state variable and emit an AuctionCreated event. - * If the mint reverts, the minter was updated without pausing this contract first. To remedy this, - * catch the revert and pause this contract. - */ - function _createAuction() internal { - try nouns.mint() returns (uint256 nounId) { - uint40 startTime = uint40(block.timestamp); - uint40 endTime = startTime + uint40(duration); - - auctionStorage = AuctionV2({ - nounId: uint96(nounId), - clientId: 0, - amount: 0, - startTime: startTime, - endTime: endTime, - bidder: payable(0), - settled: false - }); - - emit AuctionCreated(nounId, startTime, endTime); - } catch Error(string memory) { - _pause(); - } - } - - /** - * @notice Settle an auction, finalizing the bid and paying out to the owner. - * @dev If there are no bids, the Noun is burned. - */ - function _settleAuction() internal { - INounsAuctionHouseV2.AuctionV2 memory _auction = auctionStorage; - - require(_auction.startTime != 0, "Auction hasn't begun"); - require(!_auction.settled, 'Auction has already been settled'); - require(block.timestamp >= _auction.endTime, "Auction hasn't completed"); - - auctionStorage.settled = true; - - if (_auction.bidder == address(0)) { - nouns.burn(_auction.nounId); - } else { - nouns.transferFrom(address(this), _auction.bidder, _auction.nounId); - } - - if (_auction.amount > 0) { - _safeTransferETHWithFallback(owner(), _auction.amount); - } - - SettlementState storage settlementState = settlementHistory[_auction.nounId]; - settlementState.blockTimestamp = uint32(block.timestamp); - settlementState.amount = ethPriceToUint64(_auction.amount); - settlementState.winner = _auction.bidder; - if (_auction.clientId > 0) settlementState.clientId = _auction.clientId; - - emit AuctionSettled(_auction.nounId, _auction.bidder, _auction.amount); - if (_auction.clientId > 0) emit AuctionSettledWithClientId(_auction.nounId, _auction.clientId); - } - - /** - * @notice Transfer ETH. If the ETH transfer fails, wrap the ETH and try send it as WETH. - */ - function _safeTransferETHWithFallback(address to, uint256 amount) internal { - if (!_safeTransferETH(to, amount)) { - IWETH(weth).deposit{ value: amount }(); - IERC20(weth).transfer(to, amount); - } - } - - /** - * @notice Transfer ETH and return the success status. - * @dev This function only forwards 30,000 gas to the callee. - */ - function _safeTransferETH(address to, uint256 value) internal returns (bool) { - bool success; - assembly { - success := call(30000, to, value, 0, 0, 0, 0) - } - return success; - } - - /** - * @notice Set historic prices; only callable by the owner, which in Nouns is the treasury (timelock) contract. - * @dev This function lowers auction price accuracy from 18 decimals to 10 decimals, as part of the price history - * bit packing, to save gas. - * @param settlements The list of historic prices to set. - */ - function setPrices(SettlementNoClientId[] memory settlements) external onlyOwner { - for (uint256 i = 0; i < settlements.length; ++i) { - SettlementState storage settlementState = settlementHistory[settlements[i].nounId]; - settlementState.blockTimestamp = settlements[i].blockTimestamp; - settlementState.amount = ethPriceToUint64(settlements[i].amount); - settlementState.winner = settlements[i].winner; - } - } - - /** - * @notice Warm up the settlement state for a range of Noun IDs. - * @dev Helps lower the gas cost of auction settlement when storing settlement data - * thanks to the state slot being non-zero. - * @dev Only writes to slots where blockTimestamp is zero, meaning it will not overwrite existing data. - * @dev Skips Nounder reward nouns. - * @param startId the first Noun ID to warm up. - * @param endId end Noun ID (up to, but not including). - */ - function warmUpSettlementState(uint256 startId, uint256 endId) external { - for (uint256 i = startId; i < endId; ++i) { - // Skipping Nounder rewards, no need to warm up those slots since they are never used. - if (i <= 1820 && i % 10 == 0) continue; - - SettlementState storage settlementState = settlementHistory[i]; - if (settlementState.blockTimestamp == 0) { - settlementState.blockTimestamp = 1; - settlementState.slotWarmedUp = true; - } - } - } - - /** - * @notice Get past auction settlements. - * @dev Returns up to `auctionCount` settlements in reverse order, meaning settlements[0] will be the most recent auction price. - * Includes auctions with no bids (blockTimestamp will be > 1) - * @param auctionCount The number of price observations to get. - * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data - * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, - * the Noun ID of that auction, the winning bid amount, and the winner's address. - */ - function getSettlements( - uint256 auctionCount, - bool skipEmptyValues - ) external view returns (Settlement[] memory settlements) { - uint256 latestNounId = auctionStorage.nounId; - if (!auctionStorage.settled && latestNounId > 0) { - latestNounId -= 1; - } - - settlements = new Settlement[](auctionCount); - uint256 actualCount = 0; - - SettlementState memory settlementState; - for (uint256 id = latestNounId; actualCount < auctionCount; --id) { - settlementState = settlementHistory[id]; - - if (skipEmptyValues && settlementState.blockTimestamp <= 1) { - if (id == 0) break; - continue; - } - - settlements[actualCount] = Settlement({ - blockTimestamp: settlementState.blockTimestamp, - amount: uint64PriceToUint256(settlementState.amount), - winner: settlementState.winner, - nounId: id, - clientId: settlementState.clientId - }); - ++actualCount; - - if (id == 0) break; - } - - if (auctionCount > actualCount) { - // this assembly trims the observations array, getting rid of unused cells - assembly { - mstore(settlements, actualCount) - } - } - } - - /** - * @notice Get past auction prices. - * @dev Returns prices in reverse order, meaning prices[0] will be the most recent auction price. - * Skips auctions where there was no winner, i.e. no bids. - * Skips nounder rewards noun ids. - * Reverts if getting a empty data for an auction that happened, e.g. historic data not filled - * Reverts if there's not enough auction data, i.e. reached noun id 0 - * @param auctionCount The number of price observations to get. - * @return prices An array of uint256 prices. - */ - function getPrices(uint256 auctionCount) external view returns (uint256[] memory prices) { - uint256 latestNounId = auctionStorage.nounId; - if (!auctionStorage.settled && latestNounId > 0) { - latestNounId -= 1; - } - - prices = new uint256[](auctionCount); - uint256 actualCount = 0; - - SettlementState memory settlementState; - for (uint256 id = latestNounId; id > 0 && actualCount < auctionCount; --id) { - if (id <= 1820 && id % 10 == 0) continue; // Skip Nounder reward nouns - - settlementState = settlementHistory[id]; - require(settlementState.blockTimestamp > 1, 'Missing data'); - if (settlementState.winner == address(0)) continue; // Skip auctions with no bids - - prices[actualCount] = uint64PriceToUint256(settlementState.amount); - ++actualCount; - } - - require(auctionCount == actualCount, 'Not enough history'); - } - - /** - * @notice Get all past auction settlements starting at `startId` and settled before or at `endTimestamp`. - * @param startId the first Noun ID to get prices for. - * @param endTimestamp the latest timestamp for auctions - * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data - * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, - * the Noun ID of that auction, the winning bid amount, and the winner's address. - */ - function getSettlementsFromIdtoTimestamp( - uint256 startId, - uint256 endTimestamp, - bool skipEmptyValues - ) public view returns (Settlement[] memory settlements) { - uint256 maxId = auctionStorage.nounId; - require(startId <= maxId, 'startId too large'); - settlements = new Settlement[](maxId - startId + 1); - uint256 actualCount = 0; - SettlementState memory settlementState; - for (uint256 id = startId; id <= maxId; ++id) { - settlementState = settlementHistory[id]; - - if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; - - // don't include the currently auctioned noun if it hasn't settled - if ((id == maxId) && (settlementState.blockTimestamp <= 1)) continue; - - if (settlementState.blockTimestamp > endTimestamp) break; - - settlements[actualCount] = Settlement({ - blockTimestamp: settlementState.blockTimestamp, - amount: uint64PriceToUint256(settlementState.amount), - winner: settlementState.winner, - nounId: id, - clientId: settlementState.clientId - }); - ++actualCount; - } - - if (settlements.length > actualCount) { - // this assembly trims the settlements array, getting rid of unused cells - assembly { - mstore(settlements, actualCount) - } - } - } - - /** - * @notice Get a range of past auction settlements. - * @dev Returns prices in chronological order, as opposed to `getSettlements(count)` which returns prices in reverse order. - * Includes auctions with no bids (blockTimestamp will be > 1) - * @param startId the first Noun ID to get prices for. - * @param endId end Noun ID (up to, but not including). - * @param skipEmptyValues if true, skips nounder reward ids and ids with missing data - * @return settlements An array of type `Settlement`, where each Settlement includes a timestamp, - * the Noun ID of that auction, the winning bid amount, and the winner's address. - */ - function getSettlements( - uint256 startId, - uint256 endId, - bool skipEmptyValues - ) external view returns (Settlement[] memory settlements) { - settlements = new Settlement[](endId - startId); - uint256 actualCount = 0; - - SettlementState memory settlementState; - for (uint256 id = startId; id < endId; ++id) { - settlementState = settlementHistory[id]; - - if (skipEmptyValues && settlementState.blockTimestamp <= 1) continue; - - settlements[actualCount] = Settlement({ - blockTimestamp: settlementState.blockTimestamp, - amount: uint64PriceToUint256(settlementState.amount), - winner: settlementState.winner, - nounId: id, - clientId: settlementState.clientId - }); - ++actualCount; - } - - if (settlements.length > actualCount) { - // this assembly trims the settlements array, getting rid of unused cells - assembly { - mstore(settlements, actualCount) - } - } - } - - /*** - * @notice Get the client ID that facilitated the winning bid for a Noun. Returns 0 if there is no settlement data - * for the Noun in question, or if the winning bid was not facilitated by a registered client. - */ - function biddingClient(uint256 nounId) external view returns (uint32) { - return settlementHistory[nounId].clientId; - } - - /** - * @dev Convert an ETH price of 256 bits with 18 decimals, to 64 bits with 10 decimals. - * Max supported value is 1844674407.3709551615 ETH. - * - */ - function ethPriceToUint64(uint256 ethPrice) internal pure returns (uint64) { - return uint64(ethPrice / 1e8); - } - - /** - * @dev Convert a 64 bit 10 decimal price to a 256 bit 18 decimal price. - */ - function uint64PriceToUint256(uint64 price) internal pure returns (uint256) { - return uint256(price) * 1e8; - } -} diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol deleted file mode 100644 index ee639462ee..0000000000 --- a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Base.s.sol +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import 'forge-std/Script.sol'; -import { NounsAuctionHouse } from '../../contracts/NounsAuctionHouse.sol'; -import { NounsAuctionHouseV2 } from '../../contracts/NounsAuctionHouseV2.sol'; -import { NounsAuctionHousePreV2Migration } from '../../contracts/NounsAuctionHousePreV2Migration.sol'; -import { OptimizedScript } from '../OptimizedScript.s.sol'; - -abstract contract DeployAuctionHouseV2Base is OptimizedScript { - NounsAuctionHouse public immutable auctionV1; - - constructor(address _auctionHouseProxy) { - auctionV1 = NounsAuctionHouse(payable(_auctionHouseProxy)); - } - - function run() public returns (NounsAuctionHouseV2 newLogic, NounsAuctionHousePreV2Migration migratorLogic) { - requireDefaultProfile(); - uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); - - vm.startBroadcast(deployerKey); - - newLogic = new NounsAuctionHouseV2(auctionV1.nouns(), auctionV1.weth(), auctionV1.duration()); - migratorLogic = new NounsAuctionHousePreV2Migration(); - - vm.stopBroadcast(); - } -} diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol deleted file mode 100644 index 329bca88c0..0000000000 --- a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Mainnet.s.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import { DeployAuctionHouseV2Base } from './DeployAuctionHouseV2Base.s.sol'; - -contract DeployAuctionHouseV2Mainnet is DeployAuctionHouseV2Base { - address constant AUCTION_HOUSE_PROXY_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; - - constructor() DeployAuctionHouseV2Base(AUCTION_HOUSE_PROXY_MAINNET) {} -} \ No newline at end of file diff --git a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol b/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol deleted file mode 100644 index 2f8423b110..0000000000 --- a/packages/nouns-contracts/script/AuctionHouseV2/DeployAuctionHouseV2Sepolia.s.sol +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0 -pragma solidity ^0.8.19; - -import { DeployAuctionHouseV2Base } from './DeployAuctionHouseV2Base.s.sol'; - -contract DeployAuctionHouseV2Sepolia is DeployAuctionHouseV2Base { - address constant AUCTION_HOUSE_SEPOLIA = 0xf459b7573a9c2B37eF21F2f7a1a96339E343CdD8; - - constructor() DeployAuctionHouseV2Base(AUCTION_HOUSE_SEPOLIA) {} -} \ No newline at end of file From b10f4c04b928868b73dd3dda1f7ef6d36f1cfe4f Mon Sep 17 00:00:00 2001 From: davidbrai Date: Thu, 2 Jan 2025 11:16:21 +0100 Subject: [PATCH 7/7] add deploy scripts --- .../1/run-latest.json | 55 +++++++++++++++++++ .../11155111/run-latest.json | 55 +++++++++++++++++++ .../DeployAuctionHouseV3Base.s.sol | 26 +++++++++ .../DeployAuctionHouseV3Mainnet.s.sol | 10 ++++ .../DeployAuctionHouseV3Sepolia.s.sol | 10 ++++ 5 files changed, 156 insertions(+) create mode 100644 packages/nouns-contracts/broadcast/DeployAuctionHouseV3Mainnet.s.sol/1/run-latest.json create mode 100644 packages/nouns-contracts/broadcast/DeployAuctionHouseV3Sepolia.s.sol/11155111/run-latest.json create mode 100644 packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Base.s.sol create mode 100644 packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Mainnet.s.sol create mode 100644 packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Sepolia.s.sol diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Mainnet.s.sol/1/run-latest.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Mainnet.s.sol/1/run-latest.json new file mode 100644 index 0000000000..fb13712d69 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Mainnet.s.sol/1/run-latest.json @@ -0,0 +1,55 @@ +{ + "transactions": [ + { + "hash": "0x69dfba89aa482ca717d9e0f2ed664c78249a31d7acfc0514f8a581e59aa9ad21", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV3", + "contractAddress": "0x1d835808ddca38fbe14e560d8e25b3d256810af0", + "function": null, + "arguments": [ + "0x9C8fF314C9Bc7F6e59A9d9225Fb22946427eDC03", + "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "86400" + ], + "transaction": { + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "gas": "0x35cdbd", + "value": "0x0", + "input": "0x60e060405234801562000010575f80fd5b506040516200314938038062003149833981016040819052620000339162000120565b5f54610100900460ff16806200004b57505f5460ff16155b620000b35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b5f54610100900460ff16158015620000d4575f805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c08290528015620000fe575f805461ff00191690555b5050505062000165565b6001600160a01b03811681146200011d575f80fd5b50565b5f805f6060848603121562000133575f80fd5b8351620001408162000108565b6020850151909350620001538162000108565b80925050604084015190509250925092565b60805160a05160c051612f8f620001ba5f395f81816102460152611d7e01525f818161030501528181612482015261251301525f818161028701528181611cc10152818161210801526121a80152612f8f5ff3fe6080604052600436106101db575f3560e01c806391492956116100fd578063b296024d11610092578063db2e1eed11610062578063db2e1eed14610799578063ec91f2a4146107d0578063f25efffc146107f6578063f2fde38b1461080a575f80fd5b8063b296024d1461070a578063b3df4df91461073c578063bc88b0031461075b578063c0555d981461077a575f80fd5b8063a94dd8a0116100cd578063a94dd8a01461069a578063abbfb786146106b9578063af64dd30146106cc578063b1296a94146106eb575f80fd5b80639149295614610565578063945c37cb146105915780639ddd898214610667578063a4d0a17e14610686575f80fd5b80635c975abb116101735780637d9f6db5116101435780637d9f6db5146103d85780638456cb591461050657806385317a291461051a5780638da5cb5b14610548575f80fd5b80635c975abb14610346578063659dd2b4146103685780636dd83b5d1461037b578063715018a6146103c4575f80fd5b806336ebdb38116101ae57806336ebdb38146102c15780633f4ba83a146102e05780633fc8cef3146102f45780635112fabf14610327575f80fd5b806309b85709146101df5780630ba4e9ea146102145780630fb5a6b4146102355780632de45f1814610276575b5f80fd5b3480156101ea575f80fd5b506101fe6101f936600461289f565b610829565b60405161020b91906128d5565b60405180910390f35b34801561021f575f80fd5b5061023361022e36600461296f565b610a75565b005b348015610240575f80fd5b506102687f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161020b565b348015610281575f80fd5b506102a97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161020b565b3480156102cc575f80fd5b506102336102db36600461299f565b610b53565b3480156102eb575f80fd5b50610233610c1f565b3480156102ff575f80fd5b506102a97f000000000000000000000000000000000000000000000000000000000000000081565b348015610332575f80fd5b506102336103413660046129b8565b610c7f565b348015610351575f80fd5b5060335460ff16604051901515815260200161020b565b6102336103763660046129d8565b610cfa565b348015610386575f80fd5b506103af6103953660046129d8565b5f90815260cc602052604090206001015463ffffffff1690565b60405163ffffffff909116815260200161020b565b3480156103cf575f80fd5b50610233610d07565b3480156103e3575f80fd5b506104936040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b60405161020b919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b348015610511575f80fd5b50610233610d3a565b348015610525575f80fd5b506105306201518081565b60405166ffffffffffffff909116815260200161020b565b348015610553575f80fd5b506097546001600160a01b03166102a9565b348015610570575f80fd5b5061058461057f3660046129d8565b610d6c565b60405161020b91906129ef565b34801561059c575f80fd5b5060ca5460cb54610604916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e00161020b565b348015610672575f80fd5b50610233610681366004612a46565b610f7f565b348015610691575f80fd5b50610233610ff7565b3480156106a5575f80fd5b506102336106b4366004612ad9565b611048565b6102336106c7366004612bc8565b611181565b3480156106d7575f80fd5b506101fe6106e6366004612bf2565b6115d0565b3480156106f6575f80fd5b506101fe61070536600461289f565b6117d2565b348015610715575f80fd5b5060c95461072a90600160f81b900460ff1681565b60405160ff909116815260200161020b565b348015610747575f80fd5b5060cd546102a9906001600160a01b031681565b348015610766575f80fd5b50610233610775366004612c36565b61198a565b348015610785575f80fd5b50610233610794366004612c89565b611aa8565b3480156107a4575f80fd5b5060c9546107b8906001600160c01b031681565b6040516001600160c01b03909116815260200161020b565b3480156107db575f80fd5b5060c95461053090600160c01b900466ffffffffffffff1681565b348015610801575f80fd5b50610233611b20565b348015610815575f80fd5b50610233610824366004612a46565b611b76565b60ca546060906001600160601b0316808511156108815760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61088b8582612cb6565b610896906001612cc9565b6001600160401b038111156108ad576108ad612a61565b60405190808252806020026020018201604052801561090457816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816108cb5790505b5091505f610910612865565b865b838111610a5d575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff161515608082015291508580156109a157506001825f015163ffffffff1611155b610a4d5783811480156109be57506001825f015163ffffffff1611155b610a4d57815163ffffffff168710610a5d576040518060a00160405280835f015163ffffffff1681526020016109f78460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a3557610a35612cdc565b602002602001018190525082610a4a90612cf0565b92505b610a5681612cf0565b9050610912565b508184511115610a6b578184525b5050509392505050565b6097546001600160a01b03163314610a9f5760405162461bcd60e51b815260040161087890612d08565b6201518066ffffffffffffff82161115610af25760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b6044820152606401610878565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b7d5760405162461bcd60e51b815260040161087890612d08565b5f8160ff1611610bcf5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f000000000000006044820152606401610878565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b48565b6097546001600160a01b03163314610c495760405162461bcd60e51b815260040161087890612d08565b610c51611c2c565b60cb5464ffffffffff161580610c70575060cb54600160f01b900460ff165b15610c7d57610c7d611cbf565b565b815b81811015610cf55761071c8111158015610ca35750610ca1600a82612d51565b155b610ced575f81815260cc602052604081208054909163ffffffff9091169003610ceb57805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c81565b505050565b610d04815f611181565b50565b6097546001600160a01b03163314610d315760405162461bcd60e51b815260040161087890612d08565b610c7d5f611e79565b6097546001600160a01b03163314610d645760405162461bcd60e51b815260040161087890612d08565b610c7d611eca565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d9557505f81115b15610da857610da5600182612cb6565b90505b826001600160401b03811115610dc057610dc0612a61565b604051908082528060200260200182016040528015610de9578160200160208202803683370190505b5091505f610df5612865565b825b5f81118015610e0557508583105b15610f325761071c8111158015610e245750610e22600a82612d51565b155b610f22575f81815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ed95760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b6044820152606401610878565b60408201516001600160a01b031615610f2257610ef98260200151611c0e565b858481518110610f0b57610f0b612cdc565b6020908102919091010152610f1f83612cf0565b92505b610f2b81612d64565b9050610df7565b50818514610f775760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b6044820152606401610878565b505050919050565b6097546001600160a01b03163314610fa95760405162461bcd60e51b815260040161087890612d08565b60cd80546001600160a01b0319166001600160a01b0383169081179091556040519081527fa917c3b8ce8404f93eeba37a73e16eefcc65cf43ec166ab2a230571577b0695f90602001610b48565b60335460ff166110405760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610878565b610c7d611f45565b6097546001600160a01b031633146110725760405162461bcd60e51b815260040161087890612d08565b5f5b815181101561117d575f60cc5f84848151811061109357611093612cdc565b60200260200101516060015181526020019081526020015f2090508282815181106110c0576110c0612cdc565b602090810291909101015151815463ffffffff191663ffffffff9091161781558251611109908490849081106110f8576110f8612cdc565b6020026020010151602001516123a8565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061114557611145612cdc565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b03909116179055600101611074565b5050565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c9546001600160c01b03811691600160c01b820466ffffffffffffff1691600160f81b900416611239336123b7565b83516001600160601b031686146112925760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e0000000000000000006044820152606401610878565b836080015164ffffffffff1642106112de5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b6044820152606401610878565b826001600160c01b03163410156113375760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c6561737420726573657276655072696365006044820152606401610878565b60648160ff16856040015161134c9190612d79565b6113569190612da4565b84604001516113659190612dc9565b6001600160801b03163410156113e5576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e746064820152608401610878565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b0217905560808401515f9066ffffffffffffff84169061147290429064ffffffffff16612cb6565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561151957845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b801561159b5761153266ffffffffffffff841642612cc9565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115c6576115c68187604001516001600160801b0316612472565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff161580156115f957505f81115b1561160c57611609600182612cb6565b90505b836001600160401b0381111561162457611624612a61565b60405190808252806020026020018201604052801561167b57816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816116425790505b5091505f611687612865565b825b868310156117bc575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561171957506001825f015163ffffffff1611155b156117295780156117bc576117ac565b6040518060a00160405280835f015163ffffffff1681526020016117508460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525085848151811061178e5761178e612cdc565b6020026020010181905250826117a390612cf0565b925080156117bc575b6117b581612d64565b9050611689565b50818611156117c9578184525b50505092915050565b60606117de8484612cb6565b6001600160401b038111156117f5576117f5612a61565b60405190808252806020026020018201604052801561184c57816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816118135790505b5090505f611858612865565b855b85811015611973575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff161515608082015291508480156118ea57506001825f015163ffffffff1611155b61196b576040518060a00160405280835f015163ffffffff1681526020016119158460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061195357611953612cdc565b60200260200101819052508261196890612cf0565b92505b60010161185a565b508183511115611981578183525b50509392505050565b5f54610100900460ff16806119a157505f5460ff16155b6119bd5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156119dd575f805461ffff19166101011790555b6119e5612581565b6119ed6125f7565b6119f5612652565b6119fd611eca565b60c980546001600160c01b0387166001600160f81b031990911617600160c01b66ffffffffffffff871602176001600160f81b0316600160f81b60ff86160217905560cd80546001600160a01b0319166001600160a01b0384169081179091556040519081527fa917c3b8ce8404f93eeba37a73e16eefcc65cf43ec166ab2a230571577b0695f9060200160405180910390a18015611aa1575f805461ff00191690555b5050505050565b6097546001600160a01b03163314611ad25760405162461bcd60e51b815260040161087890612d08565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b48565b60335460ff1615611b665760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610878565b611b6e611f45565b610c7d611cbf565b6097546001600160a01b03163314611ba05760405162461bcd60e51b815260040161087890612d08565b6001600160a01b038116611c055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610878565b610d0481611e79565b5f611c266001600160401b0383166305f5e100612e3e565b92915050565b60335460ff16611c755760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610878565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303815f875af1925050508015611d3a575060408051601f3d908101601f19168201909252611d3791810190612e55565b60015b611d7757611d46612e6c565b806308c379a003611d6d5750611d5a612e85565b80611d655750611d6f565b610d04611eca565b505b3d5f803e3d5ffd5b425f611da37f000000000000000000000000000000000000000000000000000000000000000083612f0d565b6040805160e0810182526001600160601b0386168082525f602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60335460ff1615611f105760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610878565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611ca23390565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c08301525f036120155760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b6044820152606401610878565b8060c00151156120675760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c65646044820152606401610878565b806080015164ffffffffff164210156120c25760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c6574656400000000000000006044820152606401610878565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b031661216c578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c68906024015f604051808303815f87803b158015612151575f80fd5b505af1158015612163573d5f803e3d5ffd5b50505050612202565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd906064015f604051808303815f87803b1580156121eb575f80fd5b505af11580156121fd573d5f803e3d5ffd5b505050505b60408101516001600160801b03161561223d5761223d61222a6097546001600160a01b031690565b82604001516001600160801b0316612472565b80516001600160601b03165f90815260cc602052604090819020805463ffffffff19164263ffffffff1617815590820151612280906001600160801b03166123a8565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff91821617919091178255602083015116156122ef57602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff161561117d57816020015163ffffffff16825f01516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b5f611c266305f5e10083612f2b565b60cd546001600160a01b0316801561117d5760405163df592f7d60e01b81526001600160a01b03838116600483015282169063df592f7d90602401602060405180830381865afa15801561240d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124319190612f3e565b1561117d5760405162461bcd60e51b815260206004820152601160248201527029b0b731ba34b7b732b2103134b23232b960791b6044820152606401610878565b61247c82826126b5565b61117d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156124d9575f80fd5b505af11580156124eb573d5f803e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303815f875af115801561255d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf59190612f3e565b5f54610100900460ff168061259857505f5460ff16155b6125b45760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156125d4575f805461ffff19166101011790555b6125dc6126c9565b6125e461272e565b8015610d04575f805461ff001916905550565b5f54610100900460ff168061260e57505f5460ff16155b61262a5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff1615801561264a575f805461ffff19166101011790555b6125e461279e565b5f54610100900460ff168061266957505f5460ff16155b6126855760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156126a5575f805461ffff19166101011790555b6126ad6126c9565b6125e4612809565b5f805f805f808688617530f1949350505050565b5f54610100900460ff16806126e057505f5460ff16155b6126fc5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156125e4575f805461ffff19166101011790558015610d04575f805461ff001916905550565b5f54610100900460ff168061274557505f5460ff16155b6127615760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff16158015612781575f805461ffff19166101011790555b6033805460ff191690558015610d04575f805461ff001916905550565b5f54610100900460ff16806127b557505f5460ff16155b6127d15760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156127f1575f805461ffff19166101011790555b60016065558015610d04575f805461ff001916905550565b5f54610100900460ff168061282057505f5460ff16155b61283c5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff1615801561285c575f805461ffff19166101011790555b6125e433611e79565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b8015158114610d04575f80fd5b5f805f606084860312156128b1575f80fd5b833592506020840135915060408401356128ca81612892565b809150509250925092565b602080825282518282018190525f919060409081850190868401855b82811015612947578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a090930192908501906001016128f1565b5091979650505050505050565b803566ffffffffffffff8116811461296a575f80fd5b919050565b5f6020828403121561297f575f80fd5b61298882612954565b9392505050565b803560ff8116811461296a575f80fd5b5f602082840312156129af575f80fd5b6129888261298f565b5f80604083850312156129c9575f80fd5b50508035926020909101359150565b5f602082840312156129e8575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b81811015612a2657835183529284019291840191600101612a0a565b50909695505050505050565b6001600160a01b0381168114610d04575f80fd5b5f60208284031215612a56575f80fd5b813561298881612a32565b634e487b7160e01b5f52604160045260245ffd5b608081018181106001600160401b0382111715612a9457612a94612a61565b60405250565b601f8201601f191681016001600160401b0381118282101715612abf57612abf612a61565b6040525050565b803563ffffffff8116811461296a575f80fd5b5f6020808385031215612aea575f80fd5b82356001600160401b0380821115612b00575f80fd5b818501915085601f830112612b13575f80fd5b813581811115612b2557612b25612a61565b60409150604051612b3b858360051b0182612a9a565b81815260079190911b830184019084810188831115612b58575f80fd5b938501935b82851015612bbc576080858a031215612b74575f80fd5b8351612b7f81612a75565b612b8886612ac6565b8152868601358782015284860135612b9f81612a32565b818601526060868101359082015281526080909401938501612b5d565b50979650505050505050565b5f8060408385031215612bd9575f80fd5b82359150612be960208401612ac6565b90509250929050565b5f8060408385031215612c03575f80fd5b823591506020830135612c1581612892565b809150509250929050565b80356001600160c01b038116811461296a575f80fd5b5f805f8060808587031215612c49575f80fd5b612c5285612c20565b9350612c6060208601612954565b9250612c6e6040860161298f565b91506060850135612c7e81612a32565b939692955090935050565b5f60208284031215612c99575f80fd5b61298882612c20565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611c2657611c26612ca2565b80820180821115611c2657611c26612ca2565b634e487b7160e01b5f52603260045260245ffd5b5f60018201612d0157612d01612ca2565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601260045260245ffd5b5f82612d5f57612d5f612d3d565b500690565b5f81612d7257612d72612ca2565b505f190190565b6001600160801b03818116838216028082169190828114612d9c57612d9c612ca2565b505092915050565b5f6001600160801b0380841680612dbd57612dbd612d3d565b92169190910492915050565b6001600160801b03818116838216019080821115612de957612de9612ca2565b5092915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b8082028115828204841417611c2657611c26612ca2565b5f60208284031215612e65575f80fd5b5051919050565b5f60033d1115612e825760045f803e505f5160e01c5b90565b5f60443d1015612e925790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612ec157505050505090565b8285019150815181811115612ed95750505050505090565b843d8701016020828501011115612ef35750505050505090565b612f0260208286010187612a9a565b509095945050505050565b64ffffffffff818116838216019080821115612de957612de9612ca2565b5f82612f3957612f39612d3d565b500490565b5f60208284031215612f4e575f80fd5b81516129888161289256fea2646970667358221220520af9cfe6871ff8ed662d510f244af183be25914e1dd7e48ab9208e1466c29364736f6c634300081700330000000000000000000000009c8ff314c9bc7f6e59a9d9225fb22946427edc03000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000000000000000000000000000000000000000015180", + "nonce": "0x22", + "chainId": "0x1" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x14886fe", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x69dfba89aa482ca717d9e0f2ed664c78249a31d7acfc0514f8a581e59aa9ad21", + "transactionIndex": "0xbb", + "blockHash": "0x404836f8ffe9e03bee21ba9f0d58f5cb7432daba6ee01f672af9fac018216be7", + "blockNumber": "0x1489d6f", + "gasUsed": "0x29632f", + "effectiveGasPrice": "0x2e808e2bb", + "from": "0x918895f466eb3cd5fb181626f8e1b2fd8a9d5192", + "to": null, + "contractAddress": "0x1d835808ddca38fbe14e560d8e25b3d256810af0" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV3", + "value": "0x1D835808ddCa38fbE14e560D8e25b3D256810aF0" + } + }, + "timestamp": 1735812830, + "chain": 1, + "commit": "63626a85" +} \ No newline at end of file diff --git a/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Sepolia.s.sol/11155111/run-latest.json b/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Sepolia.s.sol/11155111/run-latest.json new file mode 100644 index 0000000000..02f53b7f68 --- /dev/null +++ b/packages/nouns-contracts/broadcast/DeployAuctionHouseV3Sepolia.s.sol/11155111/run-latest.json @@ -0,0 +1,55 @@ +{ + "transactions": [ + { + "hash": "0x295e3d1b4e149738cd178f1a3cec04be09478b1648aaff3e6f65bac16dcf8a79", + "transactionType": "CREATE", + "contractName": "NounsAuctionHouseV3", + "contractAddress": "0xfba84808d0168e91f94d91bd8ef1496c4f8dfcdf", + "function": null, + "arguments": [ + "0x054183Db3bE7E1AE513DBb0F26288084a2337531", + "0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14", + "120" + ], + "transaction": { + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "gas": "0x35cd9d", + "value": "0x0", + "input": "0x60e060405234801562000010575f80fd5b506040516200314938038062003149833981016040819052620000339162000120565b5f54610100900460ff16806200004b57505f5460ff16155b620000b35760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b606482015260840160405180910390fd5b5f54610100900460ff16158015620000d4575f805461ffff19166101011790555b6001600160a01b03808516608052831660a05260c08290528015620000fe575f805461ff00191690555b5050505062000165565b6001600160a01b03811681146200011d575f80fd5b50565b5f805f6060848603121562000133575f80fd5b8351620001408162000108565b6020850151909350620001538162000108565b80925050604084015190509250925092565b60805160a05160c051612f8f620001ba5f395f81816102460152611d7e01525f818161030501528181612482015261251301525f818161028701528181611cc10152818161210801526121a80152612f8f5ff3fe6080604052600436106101db575f3560e01c806391492956116100fd578063b296024d11610092578063db2e1eed11610062578063db2e1eed14610799578063ec91f2a4146107d0578063f25efffc146107f6578063f2fde38b1461080a575f80fd5b8063b296024d1461070a578063b3df4df91461073c578063bc88b0031461075b578063c0555d981461077a575f80fd5b8063a94dd8a0116100cd578063a94dd8a01461069a578063abbfb786146106b9578063af64dd30146106cc578063b1296a94146106eb575f80fd5b80639149295614610565578063945c37cb146105915780639ddd898214610667578063a4d0a17e14610686575f80fd5b80635c975abb116101735780637d9f6db5116101435780637d9f6db5146103d85780638456cb591461050657806385317a291461051a5780638da5cb5b14610548575f80fd5b80635c975abb14610346578063659dd2b4146103685780636dd83b5d1461037b578063715018a6146103c4575f80fd5b806336ebdb38116101ae57806336ebdb38146102c15780633f4ba83a146102e05780633fc8cef3146102f45780635112fabf14610327575f80fd5b806309b85709146101df5780630ba4e9ea146102145780630fb5a6b4146102355780632de45f1814610276575b5f80fd5b3480156101ea575f80fd5b506101fe6101f936600461289f565b610829565b60405161020b91906128d5565b60405180910390f35b34801561021f575f80fd5b5061023361022e36600461296f565b610a75565b005b348015610240575f80fd5b506102687f000000000000000000000000000000000000000000000000000000000000000081565b60405190815260200161020b565b348015610281575f80fd5b506102a97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200161020b565b3480156102cc575f80fd5b506102336102db36600461299f565b610b53565b3480156102eb575f80fd5b50610233610c1f565b3480156102ff575f80fd5b506102a97f000000000000000000000000000000000000000000000000000000000000000081565b348015610332575f80fd5b506102336103413660046129b8565b610c7f565b348015610351575f80fd5b5060335460ff16604051901515815260200161020b565b6102336103763660046129d8565b610cfa565b348015610386575f80fd5b506103af6103953660046129d8565b5f90815260cc602052604090206001015463ffffffff1690565b60405163ffffffff909116815260200161020b565b3480156103cf575f80fd5b50610233610d07565b3480156103e3575f80fd5b506104936040805160c0810182525f80825260208201819052918101829052606081018290526080810182905260a0810191909152506040805160c08101825260ca546001600160601b0381168252600160801b90046001600160801b0316602082015260cb5464ffffffffff80821693830193909352600160281b81049092166060820152600160501b82046001600160a01b03166080820152600160f01b90910460ff16151560a082015290565b60405161020b919081516001600160601b031681526020808301516001600160801b03169082015260408083015164ffffffffff90811691830191909152606080840151909116908201526080808301516001600160a01b03169082015260a09182015115159181019190915260c00190565b348015610511575f80fd5b50610233610d3a565b348015610525575f80fd5b506105306201518081565b60405166ffffffffffffff909116815260200161020b565b348015610553575f80fd5b506097546001600160a01b03166102a9565b348015610570575f80fd5b5061058461057f3660046129d8565b610d6c565b60405161020b91906129ef565b34801561059c575f80fd5b5060ca5460cb54610604916001600160601b03811691600160601b820463ffffffff1691600160801b90046001600160801b03169064ffffffffff80821691600160281b810490911690600160501b81046001600160a01b031690600160f01b900460ff1687565b604080516001600160601b03909816885263ffffffff90961660208801526001600160801b039094169486019490945264ffffffffff91821660608601521660808401526001600160a01b0390911660a0830152151560c082015260e00161020b565b348015610672575f80fd5b50610233610681366004612a46565b610f7f565b348015610691575f80fd5b50610233610ff7565b3480156106a5575f80fd5b506102336106b4366004612ad9565b611048565b6102336106c7366004612bc8565b611181565b3480156106d7575f80fd5b506101fe6106e6366004612bf2565b6115d0565b3480156106f6575f80fd5b506101fe61070536600461289f565b6117d2565b348015610715575f80fd5b5060c95461072a90600160f81b900460ff1681565b60405160ff909116815260200161020b565b348015610747575f80fd5b5060cd546102a9906001600160a01b031681565b348015610766575f80fd5b50610233610775366004612c36565b61198a565b348015610785575f80fd5b50610233610794366004612c89565b611aa8565b3480156107a4575f80fd5b5060c9546107b8906001600160c01b031681565b6040516001600160c01b03909116815260200161020b565b3480156107db575f80fd5b5060c95461053090600160c01b900466ffffffffffffff1681565b348015610801575f80fd5b50610233611b20565b348015610815575f80fd5b50610233610824366004612a46565b611b76565b60ca546060906001600160601b0316808511156108815760405162461bcd60e51b81526020600482015260116024820152707374617274496420746f6f206c6172676560781b60448201526064015b60405180910390fd5b61088b8582612cb6565b610896906001612cc9565b6001600160401b038111156108ad576108ad612a61565b60405190808252806020026020018201604052801561090457816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816108cb5790505b5091505f610910612865565b865b838111610a5d575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff161515608082015291508580156109a157506001825f015163ffffffff1611155b610a4d5783811480156109be57506001825f015163ffffffff1611155b610a4d57815163ffffffff168710610a5d576040518060a00160405280835f015163ffffffff1681526020016109f78460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff16815250858481518110610a3557610a35612cdc565b602002602001018190525082610a4a90612cf0565b92505b610a5681612cf0565b9050610912565b508184511115610a6b578184525b5050509392505050565b6097546001600160a01b03163314610a9f5760405162461bcd60e51b815260040161087890612d08565b6201518066ffffffffffffff82161115610af25760405162461bcd60e51b815260206004820152601460248201527374696d6542756666657220746f6f206c6172676560601b6044820152606401610878565b60c9805466ffffffffffffff60c01b1916600160c01b66ffffffffffffff8416908102919091179091556040519081527f1b55d9f7002bda4490f467e326f22a4a847629c0f2d1ed421607d318d25b410d906020015b60405180910390a150565b6097546001600160a01b03163314610b7d5760405162461bcd60e51b815260040161087890612d08565b5f8160ff1611610bcf5760405162461bcd60e51b815260206004820152601960248201527f6d7573742062652067726561746572207468616e207a65726f000000000000006044820152606401610878565b60c980546001600160f81b0316600160f81b60ff8416908102919091179091556040519081527fec5ccd96cc77b6219e9d44143df916af68fc169339ea7de5008ff15eae13450d90602001610b48565b6097546001600160a01b03163314610c495760405162461bcd60e51b815260040161087890612d08565b610c51611c2c565b60cb5464ffffffffff161580610c70575060cb54600160f01b900460ff165b15610c7d57610c7d611cbf565b565b815b81811015610cf55761071c8111158015610ca35750610ca1600a82612d51565b155b610ced575f81815260cc602052604081208054909163ffffffff9091169003610ceb57805463ffffffff1916600190811782558101805464ff000000001916600160201b1790555b505b600101610c81565b505050565b610d04815f611181565b50565b6097546001600160a01b03163314610d315760405162461bcd60e51b815260040161087890612d08565b610c7d5f611e79565b6097546001600160a01b03163314610d645760405162461bcd60e51b815260040161087890612d08565b610c7d611eca565b60ca5460cb546060916001600160601b031690600160f01b900460ff16158015610d9557505f81115b15610da857610da5600182612cb6565b90505b826001600160401b03811115610dc057610dc0612a61565b604051908082528060200260200182016040528015610de9578160200160208202803683370190505b5091505f610df5612865565b825b5f81118015610e0557508583105b15610f325761071c8111158015610e245750610e22600a82612d51565b155b610f22575f81815260cc6020908152604091829020825160a081018452815463ffffffff808216808452600160201b8084046001600160401b031696850196909652600160601b9092046001600160a01b03169583019590955260019283015494851660608301529290930460ff161515608084015291935011610ed95760405162461bcd60e51b815260206004820152600c60248201526b4d697373696e67206461746160a01b6044820152606401610878565b60408201516001600160a01b031615610f2257610ef98260200151611c0e565b858481518110610f0b57610f0b612cdc565b6020908102919091010152610f1f83612cf0565b92505b610f2b81612d64565b9050610df7565b50818514610f775760405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f75676820686973746f727960701b6044820152606401610878565b505050919050565b6097546001600160a01b03163314610fa95760405162461bcd60e51b815260040161087890612d08565b60cd80546001600160a01b0319166001600160a01b0383169081179091556040519081527fa917c3b8ce8404f93eeba37a73e16eefcc65cf43ec166ab2a230571577b0695f90602001610b48565b60335460ff166110405760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610878565b610c7d611f45565b6097546001600160a01b031633146110725760405162461bcd60e51b815260040161087890612d08565b5f5b815181101561117d575f60cc5f84848151811061109357611093612cdc565b60200260200101516060015181526020019081526020015f2090508282815181106110c0576110c0612cdc565b602090810291909101015151815463ffffffff191663ffffffff9091161781558251611109908490849081106110f8576110f8612cdc565b6020026020010151602001516123a8565b81546001600160401b0391909116600160201b026bffffffffffffffff0000000019909116178155825183908390811061114557611145612cdc565b60209081029190910101516040015181546001600160a01b03909116600160601b026001600160601b03909116179055600101611074565b5050565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff8082166060840152600160281b8204166080830152600160501b81046001600160a01b031660a0830152600160f01b900460ff908116151560c083015260c9546001600160c01b03811691600160c01b820466ffffffffffffff1691600160f81b900416611239336123b7565b83516001600160601b031686146112925760405162461bcd60e51b815260206004820152601760248201527f4e6f756e206e6f7420757020666f722061756374696f6e0000000000000000006044820152606401610878565b836080015164ffffffffff1642106112de5760405162461bcd60e51b815260206004820152600f60248201526e105d58dd1a5bdb88195e1c1a5c9959608a1b6044820152606401610878565b826001600160c01b03163410156113375760405162461bcd60e51b815260206004820152601f60248201527f4d7573742073656e64206174206c6561737420726573657276655072696365006044820152606401610878565b60648160ff16856040015161134c9190612d79565b6113569190612da4565b84604001516113659190612dc9565b6001600160801b03163410156113e5576040805162461bcd60e51b81526020600482015260248101919091527f4d7573742073656e64206d6f7265207468616e206c617374206269642062792060448201527f6d696e426964496e6372656d656e7450657263656e7461676520616d6f756e746064820152608401610878565b60ca80546001600160601b0316600160601b63ffffffff8816026001600160801b0390811691909117600160801b349092169190910217905560cb80547fffff0000000000000000000000000000000000000000ffffffffffffffffffff1633600160501b0217905560808401515f9066ffffffffffffff84169061147290429064ffffffffff16612cb6565b865160408051338152346020820152939092109183018290529092506001600160601b0316907f1159164c56f277e6fc99c11731bd380e0347deb969b75523398734c252706ea39060600160405180910390a263ffffffff86161561151957845160405134815263ffffffff8816916001600160601b0316907f38e150a71033b4c9a3eeb9ebe568476f075a558e47171f3b5d715aa0cf6cd1b59060200160405180910390a35b801561159b5761153266ffffffffffffff841642612cc9565b64ffffffffff166080860181905260cb805469ffffffffff00000000001916600160281b830217905585516040519182526001600160601b0316907f6e912a3a9105bdd2af817ba5adc14e6c127c1035b5b648faa29ca0d58ab8ff4e9060200160405180910390a25b60a08501516001600160a01b038116156115c6576115c68187604001516001600160801b0316612472565b5050505050505050565b60ca5460cb546060916001600160601b031690600160f01b900460ff161580156115f957505f81115b1561160c57611609600182612cb6565b90505b836001600160401b0381111561162457611624612a61565b60405190808252806020026020018201604052801561167b57816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816116425790505b5091505f611687612865565b825b868310156117bc575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff1615156080820152915085801561171957506001825f015163ffffffff1611155b156117295780156117bc576117ac565b6040518060a00160405280835f015163ffffffff1681526020016117508460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525085848151811061178e5761178e612cdc565b6020026020010181905250826117a390612cf0565b925080156117bc575b6117b581612d64565b9050611689565b50818611156117c9578184525b50505092915050565b60606117de8484612cb6565b6001600160401b038111156117f5576117f5612a61565b60405190808252806020026020018201604052801561184c57816020015b6040805160a0810182525f808252602080830182905292820181905260608201819052608082015282525f199092019101816118135790505b5090505f611858612865565b855b85811015611973575f81815260cc6020908152604091829020825160a081018452815463ffffffff8082168352600160201b8083046001600160401b031695840195909552600160601b9091046001600160a01b0316948201949094526001909101549283166060820152910460ff161515608082015291508480156118ea57506001825f015163ffffffff1611155b61196b576040518060a00160405280835f015163ffffffff1681526020016119158460200151611c0e565b815260200183604001516001600160a01b03168152602001828152602001836060015163ffffffff1681525084848151811061195357611953612cdc565b60200260200101819052508261196890612cf0565b92505b60010161185a565b508183511115611981578183525b50509392505050565b5f54610100900460ff16806119a157505f5460ff16155b6119bd5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156119dd575f805461ffff19166101011790555b6119e5612581565b6119ed6125f7565b6119f5612652565b6119fd611eca565b60c980546001600160c01b0387166001600160f81b031990911617600160c01b66ffffffffffffff871602176001600160f81b0316600160f81b60ff86160217905560cd80546001600160a01b0319166001600160a01b0384169081179091556040519081527fa917c3b8ce8404f93eeba37a73e16eefcc65cf43ec166ab2a230571577b0695f9060200160405180910390a18015611aa1575f805461ff00191690555b5050505050565b6097546001600160a01b03163314611ad25760405162461bcd60e51b815260040161087890612d08565b60c980546001600160c01b0319166001600160c01b0383169081179091556040519081527f6ab2e127d7fdf53b8f304e59d3aab5bfe97979f52a85479691a6fab27a28a6b290602001610b48565b60335460ff1615611b665760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610878565b611b6e611f45565b610c7d611cbf565b6097546001600160a01b03163314611ba05760405162461bcd60e51b815260040161087890612d08565b6001600160a01b038116611c055760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610878565b610d0481611e79565b5f611c266001600160401b0383166305f5e100612e3e565b92915050565b60335460ff16611c755760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606401610878565b6033805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b6040516001600160a01b03909116815260200160405180910390a1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631249c58b6040518163ffffffff1660e01b81526004016020604051808303815f875af1925050508015611d3a575060408051601f3d908101601f19168201909252611d3791810190612e55565b60015b611d7757611d46612e6c565b806308c379a003611d6d5750611d5a612e85565b80611d655750611d6f565b610d04611eca565b505b3d5f803e3d5ffd5b425f611da37f000000000000000000000000000000000000000000000000000000000000000083612f0d565b6040805160e0810182526001600160601b0386168082525f602080840182905283850182905264ffffffffff888116606086018190529087166080860181905260a0860184905260c09095019290925260ca9290925560cb805469ffffffffffffffffffff19168217600160281b8502177fff000000000000000000000000000000000000000000ffffffffffffffffffff16905583519081529081019190915291925084917fd6eddd1118d71820909c1197aa966dbc15ed6f508554252169cc3d5ccac756ca910160405180910390a2505050565b609780546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a35050565b60335460ff1615611f105760405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606401610878565b6033805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a258611ca23390565b6040805160e08101825260ca546001600160601b0381168252600160601b810463ffffffff166020830152600160801b90046001600160801b03169181019190915260cb5464ffffffffff80821660608401819052600160281b83049091166080840152600160501b82046001600160a01b031660a0840152600160f01b90910460ff16151560c08301525f036120155760405162461bcd60e51b815260206004820152601460248201527320bab1ba34b7b7103430b9b713ba103132b3bab760611b6044820152606401610878565b8060c00151156120675760405162461bcd60e51b815260206004820181905260248201527f41756374696f6e2068617320616c7265616479206265656e20736574746c65646044820152606401610878565b806080015164ffffffffff164210156120c25760405162461bcd60e51b815260206004820152601860248201527f41756374696f6e206861736e277420636f6d706c6574656400000000000000006044820152606401610878565b60cb805460ff60f01b1916600160f01b17905560a08101516001600160a01b031661216c578051604051630852cd8d60e31b81526001600160601b0390911660048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906342966c68906024015f604051808303815f87803b158015612151575f80fd5b505af1158015612163573d5f803e3d5ffd5b50505050612202565b60a081015181516040516323b872dd60e01b81523060048201526001600160a01b0392831660248201526001600160601b0390911660448201527f0000000000000000000000000000000000000000000000000000000000000000909116906323b872dd906064015f604051808303815f87803b1580156121eb575f80fd5b505af11580156121fd573d5f803e3d5ffd5b505050505b60408101516001600160801b03161561223d5761223d61222a6097546001600160a01b031690565b82604001516001600160801b0316612472565b80516001600160601b03165f90815260cc602052604090819020805463ffffffff19164263ffffffff1617815590820151612280906001600160801b03166123a8565b815460a08401516001600160a01b0316600160601b026001600160601b036001600160401b0393909316600160201b029290921663ffffffff91821617919091178255602083015116156122ef57602082015160018201805463ffffffff191663ffffffff9092169190911790555b815160a083015160408085015181516001600160a01b0390931683526001600160801b031660208301526001600160601b03909216917fc9f72b276a388619c6d185d146697036241880c36654b1a3ffdad07c24038d99910160405180910390a2602082015163ffffffff161561117d57816020015163ffffffff16825f01516001600160601b03167ff445afb110f5e782fc78bf23e7066d3c5a95f7b57bd25fb718a29ad0287db2b960405160405180910390a35050565b5f611c266305f5e10083612f2b565b60cd546001600160a01b0316801561117d5760405163df592f7d60e01b81526001600160a01b03838116600483015282169063df592f7d90602401602060405180830381865afa15801561240d573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906124319190612f3e565b1561117d5760405162461bcd60e51b815260206004820152601160248201527029b0b731ba34b7b732b2103134b23232b960791b6044820152606401610878565b61247c82826126b5565b61117d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156124d9575f80fd5b505af11580156124eb573d5f803e3d5ffd5b505060405163a9059cbb60e01b81526001600160a01b038681166004830152602482018690527f000000000000000000000000000000000000000000000000000000000000000016935063a9059cbb925060440190506020604051808303815f875af115801561255d573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610cf59190612f3e565b5f54610100900460ff168061259857505f5460ff16155b6125b45760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156125d4575f805461ffff19166101011790555b6125dc6126c9565b6125e461272e565b8015610d04575f805461ff001916905550565b5f54610100900460ff168061260e57505f5460ff16155b61262a5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff1615801561264a575f805461ffff19166101011790555b6125e461279e565b5f54610100900460ff168061266957505f5460ff16155b6126855760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156126a5575f805461ffff19166101011790555b6126ad6126c9565b6125e4612809565b5f805f805f808688617530f1949350505050565b5f54610100900460ff16806126e057505f5460ff16155b6126fc5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156125e4575f805461ffff19166101011790558015610d04575f805461ff001916905550565b5f54610100900460ff168061274557505f5460ff16155b6127615760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff16158015612781575f805461ffff19166101011790555b6033805460ff191690558015610d04575f805461ff001916905550565b5f54610100900460ff16806127b557505f5460ff16155b6127d15760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff161580156127f1575f805461ffff19166101011790555b60016065558015610d04575f805461ff001916905550565b5f54610100900460ff168061282057505f5460ff16155b61283c5760405162461bcd60e51b815260040161087890612df0565b5f54610100900460ff1615801561285c575f805461ffff19166101011790555b6125e433611e79565b6040805160a0810182525f8082526020820181905291810182905260608101829052608081019190915290565b8015158114610d04575f80fd5b5f805f606084860312156128b1575f80fd5b833592506020840135915060408401356128ca81612892565b809150509250925092565b602080825282518282018190525f919060409081850190868401855b82811015612947578151805163ffffffff90811686528782015188870152868201516001600160a01b03168787015260608083015190870152608091820151169085015260a090930192908501906001016128f1565b5091979650505050505050565b803566ffffffffffffff8116811461296a575f80fd5b919050565b5f6020828403121561297f575f80fd5b61298882612954565b9392505050565b803560ff8116811461296a575f80fd5b5f602082840312156129af575f80fd5b6129888261298f565b5f80604083850312156129c9575f80fd5b50508035926020909101359150565b5f602082840312156129e8575f80fd5b5035919050565b602080825282518282018190525f9190848201906040850190845b81811015612a2657835183529284019291840191600101612a0a565b50909695505050505050565b6001600160a01b0381168114610d04575f80fd5b5f60208284031215612a56575f80fd5b813561298881612a32565b634e487b7160e01b5f52604160045260245ffd5b608081018181106001600160401b0382111715612a9457612a94612a61565b60405250565b601f8201601f191681016001600160401b0381118282101715612abf57612abf612a61565b6040525050565b803563ffffffff8116811461296a575f80fd5b5f6020808385031215612aea575f80fd5b82356001600160401b0380821115612b00575f80fd5b818501915085601f830112612b13575f80fd5b813581811115612b2557612b25612a61565b60409150604051612b3b858360051b0182612a9a565b81815260079190911b830184019084810188831115612b58575f80fd5b938501935b82851015612bbc576080858a031215612b74575f80fd5b8351612b7f81612a75565b612b8886612ac6565b8152868601358782015284860135612b9f81612a32565b818601526060868101359082015281526080909401938501612b5d565b50979650505050505050565b5f8060408385031215612bd9575f80fd5b82359150612be960208401612ac6565b90509250929050565b5f8060408385031215612c03575f80fd5b823591506020830135612c1581612892565b809150509250929050565b80356001600160c01b038116811461296a575f80fd5b5f805f8060808587031215612c49575f80fd5b612c5285612c20565b9350612c6060208601612954565b9250612c6e6040860161298f565b91506060850135612c7e81612a32565b939692955090935050565b5f60208284031215612c99575f80fd5b61298882612c20565b634e487b7160e01b5f52601160045260245ffd5b81810381811115611c2657611c26612ca2565b80820180821115611c2657611c26612ca2565b634e487b7160e01b5f52603260045260245ffd5b5f60018201612d0157612d01612ca2565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b634e487b7160e01b5f52601260045260245ffd5b5f82612d5f57612d5f612d3d565b500690565b5f81612d7257612d72612ca2565b505f190190565b6001600160801b03818116838216028082169190828114612d9c57612d9c612ca2565b505092915050565b5f6001600160801b0380841680612dbd57612dbd612d3d565b92169190910492915050565b6001600160801b03818116838216019080821115612de957612de9612ca2565b5092915050565b6020808252602e908201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160408201526d191e481a5b9a5d1a585b1a5e995960921b606082015260800190565b8082028115828204841417611c2657611c26612ca2565b5f60208284031215612e65575f80fd5b5051919050565b5f60033d1115612e825760045f803e505f5160e01c5b90565b5f60443d1015612e925790565b6040516003193d81016004833e81513d6001600160401b038160248401118184111715612ec157505050505090565b8285019150815181811115612ed95750505050505090565b843d8701016020828501011115612ef35750505050505090565b612f0260208286010187612a9a565b509095945050505050565b64ffffffffff818116838216019080821115612de957612de9612ca2565b5f82612f3957612f39612d3d565b500490565b5f60208284031215612f4e575f80fd5b81516129888161289256fea2646970667358221220520af9cfe6871ff8ed662d510f244af183be25914e1dd7e48ab9208e1466c29364736f6c63430008170033000000000000000000000000054183db3be7e1ae513dbb0f26288084a2337531000000000000000000000000fff9976782d46cc05630d1f6ebab18b2324d6b140000000000000000000000000000000000000000000000000000000000000078", + "nonce": "0x350", + "chainId": "0xaa36a7" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x10d02de", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0x295e3d1b4e149738cd178f1a3cec04be09478b1648aaff3e6f65bac16dcf8a79", + "transactionIndex": "0x74", + "blockHash": "0x70b19907f0057d24ccc007d60d4deedc4ca8ca6a46037a1e7f01bc85a391dc78", + "blockNumber": "0x70ff26", + "gasUsed": "0x296317", + "effectiveGasPrice": "0x8481ac682", + "from": "0xad36c32f3c28a9214adcf50a09998de1d3b0ee06", + "to": null, + "contractAddress": "0xfba84808d0168e91f94d91bd8ef1496c4f8dfcdf" + } + ], + "libraries": [], + "pending": [], + "returns": { + "newLogic": { + "internal_type": "contract NounsAuctionHouseV3", + "value": "0xFbA84808d0168e91F94d91Bd8eF1496c4f8DFCDf" + } + }, + "timestamp": 1735812429, + "chain": 11155111, + "commit": "63626a85" +} \ No newline at end of file diff --git a/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Base.s.sol b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Base.s.sol new file mode 100644 index 0000000000..5872d6c389 --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Base.s.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import 'forge-std/Script.sol'; +import { INounsAuctionHouseV2 } from '../../contracts/interfaces/INounsAuctionHouseV2.sol'; +import { NounsAuctionHouseV3 } from '../../contracts/NounsAuctionHouseV3.sol'; +import { OptimizedScript } from '../OptimizedScript.s.sol'; + +abstract contract DeployAuctionHouseV3Base is OptimizedScript { + INounsAuctionHouseV2 public immutable auctionV2; + + constructor(address _auctionHouseProxy) { + auctionV2 = INounsAuctionHouseV2(payable(_auctionHouseProxy)); + } + + function run() public returns (NounsAuctionHouseV3 newLogic) { + requireDefaultProfile(); + uint256 deployerKey = vm.envUint('DEPLOYER_PRIVATE_KEY'); + + vm.startBroadcast(deployerKey); + + newLogic = new NounsAuctionHouseV3(auctionV2.nouns(), auctionV2.weth(), auctionV2.duration()); + + vm.stopBroadcast(); + } +} diff --git a/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Mainnet.s.sol b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Mainnet.s.sol new file mode 100644 index 0000000000..98634ac869 --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Mainnet.s.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployAuctionHouseV3Base } from './DeployAuctionHouseV3Base.s.sol'; + +contract DeployAuctionHouseV3Mainnet is DeployAuctionHouseV3Base { + address constant AUCTION_HOUSE_PROXY_MAINNET = 0x830BD73E4184ceF73443C15111a1DF14e495C706; + + constructor() DeployAuctionHouseV3Base(AUCTION_HOUSE_PROXY_MAINNET) {} +} diff --git a/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Sepolia.s.sol b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Sepolia.s.sol new file mode 100644 index 0000000000..005edaaa62 --- /dev/null +++ b/packages/nouns-contracts/script/AuctionHouseV3/DeployAuctionHouseV3Sepolia.s.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0 +pragma solidity ^0.8.19; + +import { DeployAuctionHouseV3Base } from './DeployAuctionHouseV3Base.s.sol'; + +contract DeployAuctionHouseV3Sepolia is DeployAuctionHouseV3Base { + address constant AUCTION_HOUSE_SEPOLIA = 0xf459b7573a9c2B37eF21F2f7a1a96339E343CdD8; + + constructor() DeployAuctionHouseV3Base(AUCTION_HOUSE_SEPOLIA) {} +}