Skip to content

ThirteenYearAuction Contract#

Overview#

The ThirteenYearAuction is an innovative long-term NFT auction system that creates scarcity through time-based bidding cycles. The contract manages periodic auctions with rest intervals, encouraging strategic bidding and long-term engagement with the Eden platform.

Key Features#

  • Long-Term Auctions: 13-year total duration (configurable)
  • Periodic Cycles: Active auction periods with rest intervals
  • Reserve Pricing: Minimum bid requirements
  • Automatic Settlement: Self-executing auction resolution
  • Revenue Distribution: Automated payout to designated address
  • Emergency Controls: Pause/resume functionality for safety
  • Gas Efficient: Optimized for minimal transaction costs

Architecture#

graph TB
    subgraph "ThirteenYearAuction System"
        A[Auction Start] --> B[Accept Bids]
        B --> C{Auction Period Over?}
        C -->|No| B
        C -->|Yes| D[Auction Settlement]
        D --> E[NFT Transfer]
        E --> F[Payment Transfer]
        F --> G[Rest Period]
        G --> H{Max Auctions Reached?}
        H -->|No| I[Start Next Auction]
        H -->|Yes| J[Contract Complete]
        I --> A
    end

    subgraph "External Systems"
        K[NFT Minting]
        L[Payment Processing]
        M[Frontend Interface]
    end

    A --> K
    F --> L
    B --> M
    D --> M

Auction Mechanics#

Timing Structure#

  • Auction Duration: 1 hour (3600 seconds) - configurable
  • Rest Duration: 30 minutes (1800 seconds) - configurable
  • Rest Interval: Every 3 auctions - configurable
  • Total Auctions: 10 maximum - configurable
  • Time Span: 13+ years at full schedule

Bidding Rules#

  1. Minimum Bid: Must meet reserve price
  2. Outbid Amount: Must exceed previous bid by minimum increment
  3. Last Minute Extension: Bidding extends auction if within time limit
  4. Automatic Refunds: Previous bidders automatically refunded

Contract Functions#

Auction Management#

startAuction(string metadataURI)#

  • Purpose: Begin a new auction period
  • Access: Owner only
  • Parameters: metadataURI: IPFS metadata for auction NFT
  • Requirements: Must not be in active auction or rest period
  • Events: Emits AuctionStarted(auctionId, metadataURI, endTime)

bid()#

  • Purpose: Place bid on active auction
  • Access: Public (payable)
  • Requirements:
  • Auction must be active
  • Bid must exceed current highest bid
  • Bid must meet minimum increment
  • Events: Emits BidPlaced(auctionId, bidder, amount)

settleAuction()#

  • Purpose: Finalize completed auction
  • Access: Public (anyone can settle)
  • Requirements: Auction period must be ended
  • Actions:
  • Mints NFT to winning bidder
  • Transfers payment to payout address
  • Initiates rest period if needed
  • Events: Emits AuctionSettled(auctionId, winner, amount)

Administrative Functions#

pauseAuctions()#

  • Purpose: Emergency pause all auction activity
  • Access: Owner only
  • Effect: Prevents new auctions and bid placement

resumeAuctions()#

  • Purpose: Resume auction activity after pause
  • Access: Owner only
  • Effect: Allows normal auction operations

updatePayoutAddress(address newPayout)#

  • Purpose: Change recipient of auction proceeds
  • Access: Owner only
  • Parameters: newPayout: New address to receive payments

View Functions#

getCurrentAuction()#

  • Purpose: Get details of active auction
  • Returns: Auction struct with all details
  • Access: Public view

getAuctionHistory(uint256 auctionId)#

  • Purpose: Get historical auction data
  • Parameters: auctionId: ID of past auction
  • Returns: Complete auction information

isAuctionActive()#

  • Purpose: Check if auction is currently accepting bids
  • Returns: Boolean indicating auction status

timeUntilNextAuction()#

  • Purpose: Calculate time remaining until next auction
  • Returns: Seconds until next auction can start

Events#

event AuctionStarted(
    uint256 indexed auctionId, 
    string metadataURI, 
    uint256 endTime
);

event BidPlaced(
    uint256 indexed auctionId, 
    address indexed bidder, 
    uint256 amount
);

event AuctionSettled(
    uint256 indexed auctionId, 
    address indexed winner, 
    uint256 amount
);

event RestPeriodStarted(uint256 indexed auctionId, uint256 restEndTime);
event PayoutAddressUpdated(address indexed newPayout);
event AuctionsPaused();
event AuctionsResumed();

Auction Lifecycle#

sequenceDiagram
    participant Owner as Contract Owner
    participant AC as AuctionContract
    participant Bidder1 as Bidder 1
    participant Bidder2 as Bidder 2
    participant Winner as Winning Bidder

    Owner->>AC: startAuction(metadataURI)
    AC->>AC: Create auction, set end time
    AC-->>Bidder1: AuctionStarted event

    Bidder1->>AC: bid() + 0.1 ETH
    AC->>AC: Record bid, refund none
    AC-->>Bidder1: BidPlaced event

    Bidder2->>AC: bid() + 0.2 ETH
    AC->>AC: Record new highest bid
    AC->>Bidder1: Refund 0.1 ETH
    AC-->>Bidder2: BidPlaced event

    Note over AC: Auction period ends

    Winner->>AC: settleAuction()
    AC->>AC: Mint NFT to Bidder2
    AC->>Owner: Transfer 0.2 ETH to payout
    AC-->>Winner: AuctionSettled event

    alt Rest Period Needed
        AC->>AC: Start rest period
        AC-->>Owner: RestPeriodStarted event
    end

Economic Model#

Revenue Distribution#

// Example auction economics
const auctionProceeds = winningBid; // e.g., 0.5 ETH
const platformFee = auctionProceeds * 0.025; // 2.5%
const artistPayout = auctionProceeds - platformFee;

// Automated distribution on settlement
contract.transfer(payoutAddress, artistPayout);

Bidding Strategy#

The long-term nature encourages strategic approaches:

  1. Early Bidding: Secure position early in cycle
  2. Sniping: Last-minute bidding for advantage
  3. Rest Period Planning: Prepare for upcoming auctions
  4. Long-term Commitment: Engagement over years

Security Features#

  • Reentrancy Protection: All payable functions protected
  • Overflow Protection: Safe math for all calculations
  • Access Control: Owner-only administrative functions
  • Emergency Pause: Immediate auction halt capability
  • Refund Safety: Automatic and secure bid refunds
  • Time Validation: Strict timing enforcement

Gas Optimization#

  • Efficient Storage: Packed auction data structures
  • Minimal State Changes: Optimized state updates
  • Batch Settlement: Single transaction settlement
  • Event-Based Indexing: Off-chain data access

Configuration#

The contract supports flexible configuration:

struct AuctionConfig {
    uint256 auctionDuration;    // 3600 seconds (1 hour)
    uint256 restDuration;       // 1800 seconds (30 min)
    uint256 restInterval;       // Every 3 auctions
    uint256 maxAuctions;        // 10 total auctions
    uint256 reservePrice;       // Minimum bid
    uint256 minBidIncrement;    // Minimum overbid amount
}

Usage Examples#

Starting an Auction#

import { ethers } from 'ethers';
import ThirteenYearAuctionABI from './ThirteenYearAuction.json';

const auctionContract = new ethers.Contract(
  CONTRACT_ADDRESS,
  ThirteenYearAuctionABI,
  ownerSigner
);

// Start new auction
const tx = await auctionContract.startAuction(
  "ipfs://QmYourAuctionMetadata"
);
await tx.wait();
console.log("Auction started!");

Placing Bids#

// Get current auction info
const currentAuction = await auctionContract.getCurrentAuction();
console.log("Current highest bid:", ethers.formatEther(currentAuction.highestBid));

// Place bid (must exceed current highest)
const bidAmount = ethers.parseEther("0.1");
const tx = await auctionContract
  .connect(bidderSigner)
  .bid({ value: bidAmount });

await tx.wait();
console.log("Bid placed successfully!");

Monitoring Auctions#

// Check auction status
const isActive = await auctionContract.isAuctionActive();
if (isActive) {
  const timeLeft = await auctionContract.timeUntilNextAuction();
  console.log("Auction ends in:", timeLeft, "seconds");
} else {
  const timeToNext = await auctionContract.timeUntilNextAuction();
  console.log("Next auction in:", timeToNext, "seconds");
}

// Listen for auction events
auctionContract.on("BidPlaced", (auctionId, bidder, amount) => {
  console.log(`New bid: ${ethers.formatEther(amount)} ETH from ${bidder}`);
});

auctionContract.on("AuctionSettled", (auctionId, winner, amount) => {
  console.log(`Auction ${auctionId} won by ${winner} for ${ethers.formatEther(amount)} ETH`);
});

Settlement#

// Anyone can settle completed auctions
const currentAuction = await auctionContract.getCurrentAuction();
const now = Math.floor(Date.now() / 1000);

if (now > currentAuction.endTime && currentAuction.settled === false) {
  const tx = await auctionContract.settleAuction();
  await tx.wait();
  console.log("Auction settled!");
}

Testing#

Comprehensive test suite covers:

describe("ThirteenYearAuction", function() {
  it("Should accept valid bids during auction", async function() {
    await auction.startAuction("ipfs://test");
    const bidAmount = ethers.parseEther("0.1");

    await expect(
      auction.connect(bidder).bid({ value: bidAmount })
    ).to.emit(auction, "BidPlaced");
  });

  it("Should automatically refund outbid bidders", async function() {
    await auction.startAuction("ipfs://test");

    const bid1 = ethers.parseEther("0.1");
    const bid2 = ethers.parseEther("0.2");

    await auction.connect(bidder1).bid({ value: bid1 });

    const balanceBefore = await bidder1.getBalance();
    await auction.connect(bidder2).bid({ value: bid2 });
    const balanceAfter = await bidder1.getBalance();

    expect(balanceAfter - balanceBefore).to.equal(bid1);
  });
});


Contract Status: Production Ready
Last Updated: September 1, 2025