Skip to content

WorkTimer/solidity_task_3

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NFT拍卖系统 (NFT Auction System)

这是一个基于Solidity的NFT拍卖系统,支持多代币出价、动态手续费和可升级的智能合约架构。系统使用Chainlink预言机获取实时价格数据,确保拍卖的公平性和透明度。

项目特性

  • 🎯 多代币支持: 支持ETH和ERC20代币出价
  • 🔄 动态手续费: 根据拍卖金额自动调整手续费率
  • 📈 实时价格: 集成Chainlink预言机获取准确的价格数据
  • 🔧 可升级架构: 使用UUPS代理模式支持合约升级
  • 🛡️ 安全机制: 重入攻击保护、权限控制等安全特性
  • 🎨 NFT支持: 内置SimpleNFT合约用于测试

合约架构

核心合约

1. AuctionFactory (拍卖工厂合约)

功能: 创建和管理NFT拍卖的工厂合约

主要函数:

  • createAuction(address nftContract, uint256 tokenId, uint256 duration, uint256 startingPriceUsd): 创建新的NFT拍卖
  • getAllAuctions(): 获取所有拍卖合约地址
  • getAuctionByNFT(address nftContract, uint256 tokenId): 根据NFT获取拍卖地址
  • getEthUsdPrice(uint256 amount): 获取ETH的美元价格
  • getTokenUsdPrice(address token, uint256 amount): 获取ERC20代币的美元价格
  • setFeeRecipient(address newFeeRecipient): 设置手续费接收者
  • setEthUsdFeed(address _ethUsdFeed): 设置ETH/USD预言机地址
  • setTokenUsdFeed(address token, address feed): 设置ERC20/USD预言机地址
  • upgradeImplementation(address newImplementation, uint16 newVersion): 升级拍卖实现合约

2. SingleAuction (单场拍卖合约)

功能: 管理单个NFT的拍卖过程

主要函数:

  • placeBidwithETH(): 使用ETH出价
  • placeBidbyToken(address token, uint256 amount): 使用ERC20代币出价
  • endAuction(): 结束拍卖
  • cancelAuction(): 取消拍卖
  • getAuctionInfo(): 获取完整拍卖信息
  • calculateDynamicFee(uint256 bidAmountUsd, uint256 bidAmount, uint256 tokenPriceUsd): 计算动态手续费

动态手续费规则:

  • 0-1000美元: 5%手续费
  • 1000-10000美元: 3%手续费
  • 10000美元以上: 1%手续费
  • 最低手续费: 1美元

3. SimpleNFT (简单NFT合约)

功能: ERC721 NFT合约,用于测试和演示

主要函数:

  • mintNFT(address to, string calldata uri): 铸造单个NFT
  • batchMintNFT(address to, string[] calldata uris): 批量铸造NFT
  • maxSupply(): 获取最大供应量
  • currentSupply(): 获取当前供应量
  • remainingSupply(): 获取剩余可铸造数量

接口合约

4. IAuctionFactory (拍卖工厂接口)

定义了拍卖工厂合约必须实现的所有函数和事件。

5. ISingleAuction (单场拍卖接口)

定义了单场拍卖合约必须实现的所有函数、事件和数据结构。

工具合约

6. AuctionConstants (拍卖常量库)

功能: 定义拍卖系统的常量参数

常量定义:

  • MIN_BID_INCREMENT_USD: 最小加价限制 (1美元)
  • MIN_AUCTION_DURATION: 最小拍卖时长 (5分钟)
  • MAX_AUCTION_DURATION: 最大拍卖时长 (7天)
  • MIN_STARTING_PRICE_USD: 最小起始价格 (1美元)
  • MAX_AUCTION_FEE: 最大手续费 (10%)

版本合约

7. AuctionFactoryV2 (拍卖工厂V2)

继承自AuctionFactory,添加版本信息功能。

8. SingleAuctionV2 (单场拍卖V2)

继承自SingleAuction,添加版本信息功能。

模拟合约

9. MockAggregatorV3 (模拟预言机)

功能: 模拟Chainlink价格预言机,用于测试

主要函数:

  • setPrice(int256 price): 设置价格
  • latestRoundData(): 获取最新价格数据

10. MockERC20 (模拟ERC20代币)

功能: 模拟ERC20代币,用于测试

主要函数:

  • mint(address to, uint256 amount): 铸造代币

系统架构流程图

整体系统架构

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   SimpleNFT     │    │ AuctionFactory  │    │  Chainlink      │
│   (ERC721)      │    │   (Factory)     │    │  Oracle Feeds   │
└─────────┬───────┘    └─────────┬───────┘    └─────────┬───────┘
          │                      │                      │
          │ 1. 转移NFT            │                      │
          ├─────────────────────►│                      │
          │                      │                      │
          │                      │ 2. 创建代理合约        │
          │                      ├─────────────────────►│
          │                      │                      │
          │                      │ 3. 获取价格数据        │
          │                      │◄─────────────────────┤
          │                      │                      │
          │                      │ 4. 转移NFT到拍卖合约   │
          │◄─────────────────────┤                      │
          │                      │                      │
          │                      │                      │
┌─────────▼───────┐              │                      │
│  SingleAuction  │◄─────────────┤                      │
│   (Proxy)       │              │                      │
└─────────┬───────┘              │                      │
          │                      │                      │
          │ 5. 拍卖过程           │                      │
          │                      │                      │
          │ 6. 出价 (ETH/Token)   │                      │
          │                      │                      │
          │ 7. 结束拍卖           │                      │
          │                      │                      │
          │ 8. 转移NFT给获胜者     │                      │
          ├─────────────────────►│                      │
          │                      │                      │
          │ 9. 分配资金           │                      │
          │                      │                      │
          │ 10. 支付手续费         │                      │
          │                      │                      │

拍卖状态流转图

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   创建拍卖   │───►│   拍卖进行中  │───►│   拍卖结束   │───►│   拍卖完成   │
│ (Created)   │    │  (Active)   │    │  (Ended)    │    │ (Completed) │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
       │                   │                   │                   │
       │                   │                   │                   │
       ▼                   ▼                   ▼                   ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   取消拍卖   │    │   出价过程   │    │   成功拍卖   │    │   失败拍卖   │
│ (Cancelled) │    │  (Bidding)  │    │ (Successful)│    │  (Failed)   │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘

资金流转图

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   出价者     │    │ 拍卖合约     │    │   卖家      │
│  (Bidder)   │    │ (Auction)   │    │  (Seller)   │
└─────────────┘    └─────────────┘    └─────────────┘
       │                   │                   │
       │ 1. 出价资金        │                   │
       ├──────────────────►│                   │
       │                   │                   │
       │                   │ 2. 拍卖成功        │
       │                   ├──────────────────►│
       │                   │ 3. 支付手续费       │
       │                   ├──────────────────►│
       │                   │                   │
       │                   │ 4. 退还失败出价     │
       │◄──────────────────┤                   │
       │                   │                   │
       │                   │ 5. 转移NFT         │
       │◄──────────────────┤                   │

合约交互时序图

用户    工厂合约    NFT合约    拍卖合约      预言机
 │            │           │           │         │
 │ 1.创建拍卖  │           │           │         │
 ├───────────►│           │           │         │
 │            │ 2.验证NFT │           │         │
 │            ├──────────►│           │         │
 │            │ 3.转移NFT │           │         │
 │            │◄──────────┤           │         │
 │            │ 4.创建代理 │           │         │
 │            ├───────────┐           │         │
 │            │           │ 5.初始化   │         │
 │            │           ├──────────►│         │
 │            │ 6.获取价格 │           │         │
 │            ├───────────┐           ├────────►│
 │            │           │           │◄────────┤
 │            │ 7.转移NFT │           │         │
 │            ├──────────►│           │         │
 │            │           │ 8.开始拍卖 │         │
 │            │           ├──────────►│         │
 │            │           │           │         │
 │ 9.出价     │            │           │         │
 ├───────────►│           │           │         │
 │            │           │ 10.处理出价 │         │
 │            │           ├───────────►│         │
 │            │           │ 11.获取价格 │         │
 │            │           ├───────────┐├────────►│
 │            │           │            │◄────────┤
 │            │           │ 12.更新出价 │         │
 │            │           ├───────────►│         │
 │            │           │            │         │
 │ 13.结束拍卖 │           │            │         │
 ├───────────►│           │            │         │
 │            │           │ 14.结束拍卖 │         │
 │            │           ├───────────►│         │
 │            │           │ 15.转移NFT │         │
 │            │           ├───────────►│         │
 │            │           │ 16.分配资金 │         │
 │            │           ├───────────►│         │

详细使用流程

1. 系统初始化流程

# 步骤1: 编译合约
npx hardhat compile

# 步骤2: 运行测试验证
npx hardhat test

# 步骤3: 启动本地网络
npx hardhat node

# 步骤4: 部署合约系统
npx hardhat ignition deploy ./ignition/modules/CompleteAuctionSystem.js

2. 合约部署顺序

  1. 部署基础合约

    • SimpleNFT (NFT合约)
    • MockAggregatorV3 (预言机模拟)
    • MockERC20 (代币模拟)
  2. 部署核心合约

    • SingleAuction (拍卖实现合约)
    • AuctionFactory (工厂合约)
  3. 配置系统参数

    • 设置预言机地址
    • 设置手续费接收者
    • 配置代币价格源

3. 创建拍卖流程

// 步骤1: 准备NFT
SimpleNFT nft = SimpleNFT(nftAddress);
uint256 tokenId = nft.mintNFT(sellerAddress, "https://example.com/metadata");

// 步骤2: 创建拍卖
AuctionFactory factory = AuctionFactory(factoryAddress);
address auctionAddress = factory.createAuction(
    nftAddress,     // NFT合约地址
    tokenId,        // NFT token ID
    3600,           // 拍卖时长(1小时)
    startingPrice   // 起始价格(美元)
);

// 步骤3: 获取拍卖合约实例
SingleAuction auction = SingleAuction(auctionAddress);

4. 参与拍卖流程

使用ETH出价

// 步骤1: 检查拍卖状态
(bool isActive, uint256 timeRemaining) = auction.getAuctionInfo();

// 步骤2: 计算出价金额
uint256 bidAmount = 1 ether; // 1 ETH

// 步骤3: 提交出价
auction.placeBidwithETH{value: bidAmount}();

使用ERC20代币出价

// 步骤1: 授权代币转账
IERC20 token = IERC20(tokenAddress);
token.approve(auctionAddress, bidAmount);

// 步骤2: 提交代币出价
auction.placeBidbyToken(tokenAddress, bidAmount);

5. 拍卖结束流程

// 步骤1: 检查拍卖是否结束
(bool isActive, uint256 timeRemaining) = auction.getAuctionInfo();

// 步骤2: 结束拍卖 (可由卖家、管理员或时间到期自动触发)
auction.endAuction();

// 步骤3: 处理结果
// - 如果拍卖成功: NFT转移给最高出价者,资金分配给卖家和平台
// - 如果拍卖失败: NFT退还卖家,资金退还出价者

合约交互详细流程

创建拍卖的完整流程

1. 用户调用 AuctionFactory.createAuction()
   ├── 验证NFT所有权
   ├── 验证拍卖参数
   ├── 转移NFT到工厂合约
   ├── 创建SingleAuction代理合约
   ├── 初始化拍卖参数
   ├── 转移NFT到拍卖合约
   └── 记录拍卖信息

2. 拍卖合约初始化
   ├── 设置拍卖参数
   ├── 设置权限控制
   ├── 设置重入保护
   └── 发出AuctionCreated事件

出价流程

1. 用户调用出价函数
   ├── 验证拍卖状态
   ├── 验证出价金额
   ├── 获取价格数据 (通过Chainlink)
   ├── 计算美元价值
   ├── 退还之前出价者资金
   ├── 更新最高出价信息
   └── 发出BidPlaced事件

结束拍卖流程

1. 触发结束拍卖
   ├── 验证权限 (卖家/管理员/时间到期)
   ├── 标记拍卖结束
   ├── 处理拍卖结果
   │   ├── 成功: 转移NFT + 分配资金
   │   └── 失败: 退还NFT + 退还资金
   └── 发出AuctionEnded事件

实际使用示例

完整的拍卖示例

// 1. 部署和配置
const factory = await AuctionFactory.deploy();
await factory.setEthUsdFeed(ethFeedAddress);
await factory.setFeeRecipient(feeRecipientAddress);

// 2. 创建NFT
const nft = await SimpleNFT.deploy("MyNFT", "MNFT", 1000);
const tokenId = await nft.mintNFT(sellerAddress, "https://example.com/1");

// 3. 创建拍卖
const tx = await factory.createAuction(
    nftAddress,
    tokenId,
    3600, // 1小时
    ethers.parseEther("100") // 100美元起始价
);
const receipt = await tx.wait();
const auctionAddress = receipt.logs[0].args.auctionContract;

// 4. 参与拍卖
const auction = SingleAuction.attach(auctionAddress);
await auction.placeBidwithETH({value: ethers.parseEther("1")});

// 5. 结束拍卖
await auction.endAuction();

多代币出价示例

// 使用USDC出价
await usdc.approve(auctionAddress, ethers.parseUnits("1000", 6));
await auction.placeBidbyToken(usdcAddress, ethers.parseUnits("1000", 6));

// 使用ETH出价
await auction.placeBidwithETH({value: ethers.parseEther("0.5")});

最佳实践指南

1. 部署最佳实践

// 推荐的部署顺序
async function deployAuctionSystem() {
    // 1. 部署基础合约
    const nft = await SimpleNFT.deploy("MyNFT", "MNFT", 1000);
    const mockEthFeed = await MockAggregatorV3.deploy();
    const mockUsdcFeed = await MockAggregatorV3.deploy();
    const usdc = await MockERC20.deploy("USDC", "USDC", 6, 1000000);
    
    // 2. 设置价格
    await mockEthFeed.setPrice(2000); // $2000/ETH
    await mockUsdcFeed.setPrice(1);   // $1/USDC
    
    // 3. 部署核心合约
    const auctionImpl = await SingleAuction.deploy();
    const factoryImpl = await AuctionFactory.deploy();
    
    // 4. 创建代理合约
    const factory = await createProxy(factoryImpl, [
        auctionImpl.address,
        feeRecipientAddress
    ]);
    
    // 5. 配置系统
    await factory.setEthUsdFeed(mockEthFeed.address);
    await factory.setTokenUsdFeed(usdc.address, mockUsdcFeed.address);
    
    return { factory, nft, usdc, mockEthFeed, mockUsdcFeed };
}

2. 拍卖管理最佳实践

// 监控拍卖状态
async function monitorAuction(auctionAddress) {
    const auction = SingleAuction.attach(auctionAddress);
    
    // 获取拍卖信息
    const info = await auction.getAuctionInfo();
    console.log(`拍卖状态: ${info.isActive ? '进行中' : '已结束'}`);
    console.log(`剩余时间: ${info.timeRemaining}秒`);
    console.log(`当前最高出价: ${ethers.formatEther(info.auctionData.highestBidUsd)}美元`);
    
    // 检查是否需要结束拍卖
    if (info.isActive && info.timeRemaining === 0) {
        await auction.endAuction();
        console.log('拍卖已自动结束');
    }
}

3. 错误处理最佳实践

// 安全的出价函数
async function safePlaceBid(auctionAddress, bidAmount, tokenAddress = null) {
    try {
        const auction = SingleAuction.attach(auctionAddress);
        
        // 检查拍卖状态
        const info = await auction.getAuctionInfo();
        if (!info.isActive) {
            throw new Error('拍卖未进行中');
        }
        
        if (tokenAddress) {
            // ERC20代币出价
            const token = IERC20.attach(tokenAddress);
            await token.approve(auctionAddress, bidAmount);
            await auction.placeBidbyToken(tokenAddress, bidAmount);
        } else {
            // ETH出价
            await auction.placeBidwithETH({value: bidAmount});
        }
        
        console.log('出价成功');
    } catch (error) {
        console.error('出价失败:', error.message);
        // 处理常见错误
        if (error.message.includes('Bid must be higher')) {
            console.log('出价必须高于当前最高出价');
        } else if (error.message.includes('Auction has ended')) {
            console.log('拍卖已结束');
        }
    }
}

4. 批量操作示例

// 批量创建拍卖
async function batchCreateAuctions(factory, nft, tokenIds, duration, startingPrice) {
    const auctions = [];
    
    for (const tokenId of tokenIds) {
        try {
            const tx = await factory.createAuction(
                nft.address,
                tokenId,
                duration,
                startingPrice
            );
            const receipt = await tx.wait();
            const auctionAddress = receipt.logs[0].args.auctionContract;
            auctions.push(auctionAddress);
            console.log(`拍卖 ${tokenId} 创建成功: ${auctionAddress}`);
        } catch (error) {
            console.error(`拍卖 ${tokenId} 创建失败:`, error.message);
        }
    }
    
    return auctions;
}

常见问题解答

Q1: 如何设置合适的手续费?

A: 系统使用动态手续费机制,根据拍卖金额自动调整:

  • 0-1000美元: 5%
  • 1000-10000美元: 3%
  • 10000美元以上: 1%
  • 最低手续费: 1美元

Q2: 拍卖失败时资金如何处理?

A: 如果拍卖失败(没有达到起始价格),系统会:

  • 将NFT退还卖家
  • 将出价资金退还给最高出价者

Q3: 如何升级合约?

A: 使用UUPS代理模式,只有合约所有者可以升级:

await factory.upgradeImplementation(newImplAddress, newVersion);

Q4: 支持哪些代币出价?

A: 支持任何ERC20代币,但需要先配置对应的价格预言机:

await factory.setTokenUsdFeed(tokenAddress, priceFeedAddress);

Q5: 如何监控拍卖状态?

A: 可以通过事件监听或定期查询:

// 监听出价事件
auction.on("BidPlaced", (bidder, amount, token, priceUsd) => {
    console.log(`新出价: ${ethers.formatEther(amount)} from ${bidder}`);
});

配置文件说明

config/deployed_addresses_sepolia.json

这个配置文件包含了在Sepolia测试网上已部署的所有合约地址:

{
  "auctionFactory": "0xaEcb00Da8656C18a16415085b49da518B0984CBB",     // 拍卖工厂代理合约
  "simpleNFT": "0x3DB1Ef472Fd65DE888aCeBABB0A78931f6644E4f",           // 简单NFT合约
  "singleAuction": "0x3386618aE692Cfd51d94d9b456DE198406160541",      // 单场拍卖实现合约
  "usdc": "0x8e3A570e170fba92E50BA83510c60F897F283C40",               // USDC代币合约
  "usdt": "0x7381fe1C126B2B62Fa3E766F0ED079d91Def9188",               // USDT代币合约
  "weth": "0x34a56f192001Ba8Ea16eb55B54B683Aa9F325C84",               // Wrapped ETH合约
  "wbtc": "0x2Fc62A208B330F4673F828B7B54e661ec539E4e9",               // Wrapped BTC合约
  "ethUsdFeed": "0x694AA1769357215DE4FAC081bf1f309aDC325306",         // ETH/USD价格源
  "usdcUsdFeed": "0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E",        // USDC/USD价格源
  "usdtUsdFeed": "0x1a81afB8146aeFfCFc5E50e8479e826E7D55b910",        // USDT/USD价格源
  "btcUsdFeed": "0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43",         // BTC/USD价格源
  "auctionFactoryImpl": "0x470f867661F61a76CcC7926F20c091600d61C906"  // 拍卖工厂实现合约
}

配置说明

  • 核心合约: 包含拍卖工厂、NFT合约和拍卖实现合约
  • 代币合约: 支持USDC、USDT、WETH、WBTC四种代币出价
  • 价格预言机: 使用Chainlink官方价格源获取实时价格数据
  • 代理模式: 使用UUPS代理模式,支持合约升级

已部署合约地址

Sepolia测试网部署

项目已在Sepolia测试网上部署,以下是合约地址和Etherscan链接:

核心合约

合约名称 地址 Etherscan链接
AuctionFactory (代理) 0xaEcb00Da8656C18a16415085b49da518B0984CBB 查看合约
AuctionFactory (实现) 0x470f867661F61a76CcC7926F20c091600d61C906 查看合约
SingleAuction (实现) 0x3386618aE692Cfd51d94d9b456DE198406160541 查看合约
SimpleNFT 0x3DB1Ef472Fd65DE888aCeBABB0A78931f6644E4f 查看合约

代币合约

代币名称 地址 Etherscan链接
USDC 0x8e3A570e170fba92E50BA83510c60F897F283C40 查看合约
USDT 0x7381fe1C126B2B62Fa3E766F0ED079d91Def9188 查看合约
WETH 0x34a56f192001Ba8Ea16eb55B54B683Aa9F325C84 查看合约
WBTC 0x2Fc62A208B330F4673F828B7B54e661ec539E4e9 查看合约

价格预言机

价格源 地址 Etherscan链接
ETH/USD 0x694AA1769357215DE4FAC081bf1f309aDC325306 查看合约
USDC/USD 0xA2F78ab2355fe2f984D808B5CeE7FD0A93D5270E 查看合约
USDT/USD 0x1a81afB8146aeFfCFc5E50e8479e826E7D55b910 查看合约
BTC/USD 0x1b44F3514812d835EB1BDB0acB33d3fA3351Ee43 查看合约

使用已部署合约

// 连接到已部署的合约
const factory = await ethers.getContractAt("AuctionFactory", "0xaEcb00Da8656C18a16415085b49da518B0984CBB");
const nft = await ethers.getContractAt("SimpleNFT", "0x3DB1Ef472Fd65DE888aCeBABB0A78931f6644E4f");

// 创建拍卖
const tx = await factory.createAuction(
    nft.target,
    tokenId,
    3600, // 1小时
    ethers.parseEther("100") // $100起始价
);

快速开始指南

5分钟快速体验

# 1. 克隆项目
git clone <repository-url>
cd solidity_task_3

# 2. 安装依赖
npm install

# 3. 编译合约
npx hardhat compile

# 4. 运行测试
npx hardhat test

# 5. 启动本地网络
npx hardhat node

# 6. 部署合约 (新终端)
npx hardhat ignition deploy ./ignition/modules/CompleteAuctionSystem.js

使用Sepolia测试网

# 配置环境变量
export SEPOLIA_RPC_URL="your_sepolia_rpc_url"
export PRIVATE_KEY="your_private_key"

# 部署到Sepolia
npx hardhat ignition deploy ./ignition/modules/SepoliaDeployment.js --network sepolia

在Sepolia测试网上测试

// 连接到Sepolia测试网
const provider = new ethers.JsonRpcProvider("https://sepolia.infura.io/v3/YOUR_PROJECT_ID");
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// 连接到已部署的合约
const factory = new ethers.Contract(
    "0xaEcb00Da8656C18a16415085b49da518B0984CBB",
    AuctionFactoryABI,
    wallet
);

const nft = new ethers.Contract(
    "0x3DB1Ef472Fd65DE888aCeBABB0A78931f6644E4f",
    SimpleNFTABI,
    wallet
);

// 创建测试NFT
const mintTx = await nft.mintNFT(wallet.address, "https://example.com/metadata/1");
await mintTx.wait();

// 创建拍卖
const createTx = await factory.createAuction(
    nft.target,
    0, // tokenId
    3600, // 1小时
    ethers.parseEther("100") // $100起始价
);
const receipt = await createTx.wait();
console.log("拍卖创建成功!");

获取测试代币

在Sepolia测试网上,你可以通过以下方式获取测试代币:

  1. ETH: 从 Sepolia Faucet 获取
  2. USDC/USDT: 使用已部署的MockERC20合约铸造
  3. WETH/WBTC: 使用已部署的MockERC20合约铸造
// 铸造测试代币
const usdc = new ethers.Contract(usdcAddress, MockERC20ABI, wallet);
await usdc.mint(wallet.address, ethers.parseUnits("1000", 6)); // 铸造1000 USDC

快速测试脚本

// quick-test.js
const { ethers } = require("hardhat");

async function quickTest() {
    // 获取签名者
    const [owner, seller, bidder1, bidder2] = await ethers.getSigners();
    
    // 部署合约
    const factory = await ethers.getContractAt("AuctionFactory", "0x...");
    const nft = await ethers.getContractAt("SimpleNFT", "0x...");
    
    // 创建NFT
    await nft.mintNFT(seller.address, "https://example.com/1");
    
    // 创建拍卖
    const tx = await factory.createAuction(
        nft.target,
        0, // tokenId
        300, // 5分钟
        ethers.parseEther("100") // $100起始价
    );
    
    console.log("拍卖创建成功!");
}

quickTest().catch(console.error);

API参考

AuctionFactory 合约

函数名 参数 返回值 描述
createAuction (address, uint256, uint256, uint256) address 创建新拍卖
getAllAuctions () address[] 获取所有拍卖地址
getAuctionByNFT (address, uint256) address 根据NFT获取拍卖
getEthUsdPrice (uint256) uint256 获取ETH美元价格
getTokenUsdPrice (address, uint256) uint256 获取代币美元价格
setFeeRecipient (address) void 设置手续费接收者
setEthUsdFeed (address) void 设置ETH价格源
setTokenUsdFeed (address, address) void 设置代币价格源

SingleAuction 合约

函数名 参数 返回值 描述
placeBidwithETH () void 使用ETH出价
placeBidbyToken (address, uint256) void 使用代币出价
endAuction () void 结束拍卖
cancelAuction () void 取消拍卖
getAuctionInfo () (AuctionInfo, uint256, address, address, uint256, bool, uint256) 获取拍卖信息
calculateDynamicFee (uint256, uint256, uint256) uint256 计算动态手续费

事件列表

事件名 参数 描述
AuctionCreated (address, address, uint256, address, uint256, uint256, uint256) 拍卖创建
BidPlaced (address, uint256, address, uint256) 出价事件
AuctionEnded (address, uint256, address, uint256) 拍卖结束
AuctionCancelled () 拍卖取消

安全特性

  • 重入攻击保护: 使用ReentrancyGuard防止重入攻击
  • 权限控制: 使用Ownable模式控制关键函数访问
  • 输入验证: 对所有输入参数进行严格验证
  • 溢出保护: 使用SafeMath防止数值溢出
  • 升级安全: 使用UUPS代理模式确保升级安全

测试

项目包含完整的测试套件,覆盖所有核心功能:

# 运行所有测试
npx hardhat test

# 运行特定测试
npx hardhat test test/AuctionFactory.test.js
npx hardhat test test/SingleAuction.test.js
npx hardhat test test/SimpleNFT.test.js

# 运行升级测试
npx hardhat test test/UUPSUpgrade.test.js

# 生成测试覆盖率报告
npx hardhat coverage

技术栈

  • Solidity: ^0.8.20
  • OpenZeppelin: 安全合约库
  • Chainlink: 价格预言机
  • Hardhat: 开发框架
  • Ethers.js: 以太坊交互库

许可证

MIT License

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published