nasirovpe/solidity-auction-v2

GitHub: nasirovpe/solidity-auction-v2

Stars: 1 | Forks: 0

# AuctionV2 Secure Ethereum auction smart contract with reserve pricing, second-price bidding, pull-payment withdrawals, and Hardhat test coverage. ## Description **AuctionV2** is an on-chain auction for a single item (identified by an IPFS metadata hash). Bidders compete during a fixed time window. The contract enforces a **reserve price** and **minimum bid increment**, applies **second-price-style binding bids**, and settles funds through **pull payments** so refunds and proceeds are claimed explicitly rather than pushed in nested calls. The repository includes a Hardhat toolchain, OpenZeppelin **ReentrancyGuard**, and an automated test suite (**13 tests**, all passing). ## Features - **Reserve price** — The first bid must meet or exceed the configured minimum sale price. - **Bid increment** — Each subsequent bid must be at least the current highest bid plus the increment. - **Second-price-style logic** — The winner’s binding amount follows reserve and increment rules (see [Contract overview](#contract-overview)). - **Pull-payment withdrawals** — Outbid bidders, the winner’s excess, and the owner’s proceeds are withdrawn via dedicated functions. - **`call` instead of `transfer`** — ETH sends use low-level `call` with explicit failure handling (compatible with smart contract wallets and post-merge gas semantics). - **Owner cannot bid** — The deployer is blocked from `placeBid` to avoid self-dealing. - **Reentrancy protection** — Critical state-changing paths use OpenZeppelin `ReentrancyGuard`. - **Auction lifecycle** — Running, ended, and canceled states with owner cancel only before the first bid and before `endTime`. - **Hardhat tests** — Full scenario coverage including bidding, settlement, and access control. ## Tech stack | Layer | Technology | |--------|------------| | Language | Solidity `^0.8.20` | | Framework | [Hardhat](https://hardhat.org/) `^2.26` | | Libraries | [OpenZeppelin Contracts](https://docs.openzeppelin.com/contracts/) `^5.0` (`ReentrancyGuard`) | | Testing | Hardhat + Ethers v6 + Chai matchers + `@nomicfoundation/hardhat-network-helpers` | | Module system | ESM (`"type": "module"` in `package.json`; Hardhat config is `hardhat.config.cjs`) | ## Contract overview **Primary contract:** `contracts/AuctionV2.sol` ### Constructor parameters | Parameter | Description | |-----------|-------------| | `_ipfsHash` | Metadata URI (e.g. `ipfs://...`) for the auctioned item | | `_durationSeconds` | Length of the auction from deployment block timestamp; must be > 0 | | `_reservePrice` | Minimum selling price in wei; first bid must be ≥ this value | | `_bidIncrement` | Minimum raise above the current highest bid in wei | ### Main functions | Function | Purpose | |----------|---------| | `placeBid()` | Submit a payable bid while the auction is running and within `[startTime, endTime]` | | `endAuction()` | Anyone may finalize after `endTime`; credits the winner’s excess to `pendingWithdrawals` | | `cancelAuction()` | Owner-only; only if no bids and before `endTime` | | `withdraw()` | Pull refunds (outbid bidders) or winner excess after `endAuction` | | `withdrawOwnerProceeds()` | Owner pulls `highestBindingBid` once after the auction has ended | | `isOpenForBids()` | View helper for whether bidding is currently allowed | ### Binding bid behavior (summary) - **First bid:** If it meets `reservePrice`, `highestBindingBid` is set to `reservePrice`. - **Later bids:** The previous high bidder’s full bid is credited to `pendingWithdrawals`; `highestBindingBid` is updated using second-price-style rules (capped by the new bid and prior bid + increment). - **After end:** The winner pays the binding amount to the owner via `withdrawOwnerProceeds`; any amount above the binding bid is withdrawn by the winner via `withdraw`. An earlier **`Auction.sol`** contract remains in the repo for reference; **AuctionV2** is the version covered by tests and recommended for use. ## Installation git clone cd auction-smart-contract npm install Copy environment variables when you add deployment or network scripts (never commit secrets): # .env — example only; file is gitignored # PRIVATE_KEY=... # RPC_URL=... ## Compile npm run compile # or npx hardhat compile Compiled artifacts are written to `artifacts/` and `cache/` (both ignored by Git). ## Test npm test # or npx hardhat test Expected result: **13 passing** tests in `test/AuctionV2.test.js`. ## Deployment parameters (example) There is no bundled deploy script; deploy with Hardhat/ethers using the same values as the test fixture: import hre from "hardhat"; const { ethers } = hre; const ipfsHash = "ipfs://auction-metadata"; const durationSeconds = 3600; // 1 hour const reservePrice = ethers.parseEther("0.05"); const bidIncrement = ethers.parseEther("0.01"); const AuctionV2 = await ethers.getContractFactory("AuctionV2"); const auction = await AuctionV2.deploy( ipfsHash, durationSeconds, reservePrice, bidIncrement ); await auction.waitForDeployment(); console.log("AuctionV2 deployed to:", await auction.getAddress()); Adjust `durationSeconds`, `reservePrice`, and `bidIncrement` for your sale. The deployer becomes `owner` and cannot call `placeBid`. ## Security notes - **Not audited.** This code is suitable for learning and integration tests; obtain a professional audit before mainnet use with real value. - **Reentrancy** — `placeBid`, `cancelAuction`, `withdraw`, and `withdrawOwnerProceeds` use `nonReentrant`. Follow checks-effects-interactions when extending the contract. - **Pull payments** — Reduces reentrancy risk from pushing ETH during bid updates; users must call `withdraw` to receive funds. - **Owner trust** — The owner can cancel only before any bid; after bids, cancellation is disabled. Proceeds are limited to `highestBindingBid` after a successful sale. - **Time dependency** — Bidding and `endAuction` rely on `block.timestamp`; miners/validators have limited leeway—design durations accordingly. - **No upgradeability** — The contract is not proxied; incorrect constructor parameters are immutable. - **Secrets** — Keep private keys and RPC URLs in `.env` (listed in `.gitignore`). ## Folder structure . ├── contracts/ │ ├── AuctionV2.sol # Main auction contract (tested) │ └── Auction.sol # Earlier version (reference) ├── test/ │ └── AuctionV2.test.js # Hardhat test suite ├── hardhat.config.cjs # Solidity 0.8.20, optimizer, Hardhat plugins ├── package.json ├── package-lock.json ├── .gitignore # node_modules, artifacts, cache, .env, coverage, etc. └── README.md Generated and local-only paths (not committed): `node_modules/`, `artifacts/`, `cache/`, `coverage/`, `coverage.json`. ## License This project’s smart contracts are released under the **MIT License**, as indicated by the SPDX identifier in the source files (`// SPDX-License-Identifier: MIT`). Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files, to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, subject to the condition that the above copyright notice and this permission notice are included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.