如何创建荷兰式拍卖智能合约

概述

通常要在两个不受信任的方之间执行任何交易,需要一个受信任的中间人;智能合约完全消除了对中间人的需求。在本文中,我们将学习如何创建荷兰拍卖智能合约,这将使整个拍卖过程无需信任。
先决条件

0_zmJJ8o3c5AByT39a

使用智能合约的拍卖

拍卖是通过竞标过程公开出售商品的平台,通常出价最高的人赢得拍卖并获得物品的所有权。虽然这是拍卖运作的主要形式,但拍卖还有一些其他规则。

不同类型的拍卖是:

英式拍卖(公开升价拍卖):这是众所周知的传统拍卖,出价最高的人即为拍卖的获胜者。

荷兰式拍卖(公开降价拍卖):这类拍卖主要用于易腐烂的物品,比如鲜花、食品、衣服等。有一个起拍价,随着时间的推移,价格下降一定百分比,出价高于或等于当前价格的投标人赢得拍卖,或者当预设的持续时间超过最后一个出价的投标人赢得拍卖。

第一价密封投标拍卖(盲拍):在这种类型的拍卖中,所有投标人在不知道对方出价的情况下,在信封中提交他们的出价,然后拍卖师打开信封,出价最高的获胜。

第二级密封投标拍卖(Vickrey 拍卖):这与第一价密封投标拍卖相同。唯一的区别是获胜者是第二高的出价。

在每种类型的拍卖中,中间人是负责进行拍卖并确定获胜者并收取费用的拍卖师,通常是总售价的百分比。智能合约可以消除对拍卖师的需求,并且整个过程可以自动化、无需信任且安全,因为我们将在以太坊区块链上执行此操作。

什么是荷兰式拍卖?

荷兰式拍卖,也称为公开降序拍卖,是一种拍卖类型,卖方首先设置起始价格、持续时间和折扣率。随着时间的推移,物品的价格会不断下降,直到预设的持续时间结束。例如,假设您想要一个非常好的包,但超出了您的预算。在那种情况下,随着时间的推移,这个包会变得越来越便宜;首先是 10% 的折扣,然后是 30%,然后是 50%,直到包包便宜到足以让您购买为止。这就是荷兰式拍卖的概念。为了在以太坊上进行这项工作,我们需要创建和部署 ERC721 合约和荷兰拍卖智能合约。

启动我们的以太坊节点

我们将使用 Remix IDE 和 MetaMask 钱包在以太坊的 Ropsten 测试网上部署我们的合约。我们可以在 MetaMask 上使用默认的 Ropsten 网络,但 MetaMask 是大多数以太坊开发人员使用的非常流行的工具,因此有时网络会变得拥挤。为避免这种情况,我们将在 QuickNode 上创建一个免费试用的 Ropsten 节点,并将其添加为 MetaMask 中的自定义提供程序。

Quicknode Ropsten 端点的屏幕截图

复制 HTTP URL 并按照指南将自定义提供程序添加到 MetaMask

您还应该在 MetaMask 钱包中放置一些 Ropsten 测试 ETH 来支付 gas。如果你没有,你可以从Ropsten 水龙头那里得到一些。

创建和部署荷兰式拍卖合约

在开始下面的内容之前,假设您已经阅读了这篇,了解如何创建 ERC721 (NFT) 代币并使用Remix IDE部署您的 ERC721 代币合约,并铸造了 NFT。

现在,创建一个新的 solidity 文件 dutchAuction.sol ,并将以下代码粘贴到其中:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC721 {
    function transferFrom(
        address _from,
        address _to,
        uint _nftId
    ) external;
}

contract dutchAuction {
    uint private constant DURATION = 7 days;

    IERC721 public immutable nft;
    uint public immutable nftId;

    address payable public immutable seller;
    uint public immutable startingPrice;
    uint public immutable discountRate;
    uint public immutable startAt;
    uint public immutable expiresAt;

    constructor(
        uint _startingPrice,
        uint _discountRate,
        address _nft,
        uint _nftId
    ) {
        seller = payable(msg.sender);
        startingPrice = _startingPrice;
        discountRate = _discountRate;
        startAt = block.timestamp;
        expiresAt = block.timestamp + DURATION;

        require(_startingPrice >= _discountRate * DURATION, "Starting price is too low");

        nft = IERC721(_nft);
        nftId = _nftId;
    }

    function getPrice() public view returns (uint) {
        uint timeElapsed = block.timestamp - startAt;
        uint discount = discountRate * timeElapsed;
        return startingPrice - discount;
    }

    function buy() external payable {
        require(block.timestamp < expiresAt, "This auction has ended");

        uint price = getPrice();
        require(msg.value >= price, "The amount of ETH sent is less than the price of token");

        nft.transferFrom(seller, msg.sender, nftId);
        uint refund = msg.value - price;
        if (refund > 0) {
            payable(msg.sender).transfer(refund);
        }
        selfdestruct(seller);
    }
}

上述合约解释说明:

第 1 行:指定SPDX 许可证类型,这是 Solidity ^0.6.8 之后添加的。每当智能合约的源代码向公众开放时,这些许可证都可以帮助解决/避免版权问题。如果您不想指定任何许可类型,您可以使用特殊值 UNLICENSED 或直接跳过整个注释(不会导致错误,只是警告)。

第 2 行:声明 Solidity 版本。

第 4-10 行:扩展IERC721合约接口以在此合约中使用 ERC721 方法,我们将需要它们与我们的 NFT 一起使用。

第 12 行:将变量DURATION声明为私有,它将存储拍卖活动的时间。

第 15-16 行:创建两个状态变量nftnftId来存储我们代币的 NFT 地址和 nft id。这两个变量都是公开的和不可变的,这意味着它们在合约范围之外是可见的,并且一旦部署合约就不可更改。

第 18-22 行:创建一个变量 seller(它是应付的,这意味着它可以收到资金)来存储卖方的地址,一个变量startingPrice 来存储NFT 的起始价格,一个变量 discountRate 来存储我们的 NFT 随时间减少的比率,变量startAt 存储拍卖的开始时间戳,变量expiresAt 存储拍卖的结束时间戳。所有这些变量都是公开的且不可变的。

第 24-29 行:在构造函数中初始化上述状态变量。

第 30 行:将卖方设置为合约的部署者。

第 31-34 行:将startingPrice设置为 _startingPrice,将discountRate设置为 **_discountRate,**这将来自输入。

  • startAt设置为block.timestamp意味着开始时间将是当前时间戳,即合约部署的时间。
  • expiresAt设置为block.timestamp + DURATION意味着拍卖将在当前时间戳(此处为 7 天)的持续时间完成时到期。

第 36 行:检查以确保 NFT 的价格始终大于或等于零,如果检查失败,则会显示错误消息。

第 38-39 行:从输入中将 nft 设置为**_nft**,并将nftId设置为**_nftId**。

第 42-46 行:一个名为**getPrice()**的函数/方法,用于获取 NFT 的当前价格。

  • 变量timeElapsed用于存储自合约部署以来经过的时间,计算方法是用startAt减去当前时间戳。
  • 变量 discount 存储当前折扣率的变量折扣,该折扣率通过使用timeElapsed减去初始设置的discountRate计算得出。
  • 通过使用discount减去 startPrice 返回当前价格**,因此每当调用getPrice()**函数时,它将返回 NFT 的当前价格。

第 48-59 行:购买 NFT 的函数。

  • 检查以确保当前时间戳小于拍卖到期时间**expiresAt,**如果检查失败,则会显示错误消息。
  • 变量 price,用于存储 NFT 的当前价格,它将从**getPrice()**方法获得。
  • 检查确保投标人/买方发送的 ETH 数量 ( msg.value ) 始终大于或等于 NFT 的当前价格,如果检查失败,则会显示错误消息。
  • 使用 IERC721 的 transferFrom 函数传输 nft。NFT 将在nftId的帮助下被识别,并将从 seller 转移到当前的msg.sender(即当前与合约交互的人)。
  • 变量 refund 用于存储买家购买 NFT 后剩余的任何多余的 ETH 金额,其计算方法是用 NFT 的当前价格减去买家发送的 ETH 数量 ( msg.value ),即price
  • 检查退款变量的值是否为零,如果是合约将把该值发回给买方。
  • 使用 selfdestruct 函数删除合约并将 ETH 转移给卖方。

编译合约;如果在编译过程中出现错误,请确保选择正确的solidity 编译器版本。

https://img.chengxuka.com

现在,转到 deploy 选项卡,在“ENVIRONMENT”选项下选择“Injected Web3”,同时确保在其下方看到“Ropsten (3) network”;如果没有,请选择我们之前添加的 QuickNode Ropsten 节点,然后从下拉“CONTRACT”选项中选择 dutchAuction,然后单击部署按钮旁边的小箭头并填写以下详细信息。

  1. NFT 起始价格以gwei为单位 ,此处为 10,000,000 gwei。
  2. 自合约部署到 7 天或直到价格大于零(以较早者为准),NFT 价格每秒下降的折扣率。这里填1。
  3. 我们之前部署的 NFT 合约的地址。
  4. 我们 NFT 的 ID。

https://img.chengxuka.com

现在单击“transact button”并从 MetaMask 批准该交易。一旦交易获得批准,我们的荷兰式拍卖合约就会被部署。

执行拍卖

现在我们的荷兰式拍卖合约已经部署,让我们看看它的实际效果。这里的第一步是批准 dutchAcution 合约以便能够转让 NFT。打开已部署的 NFT 合约并展开 approve 函数,在第一个字段中粘贴 dutchAuction 合约的地址和我们正在出售的代币的 NFT id。

https://img.chengxuka.com

现在,在 MetaMask 中切换到另一个账户,然后展开部署的 dutchAuction 合约并执行以下步骤:

  1. 单击“getPrice”按钮以获取 NFT 的当前价格。
  2. 复制该值并向上滚动并将其粘贴到我们在部署合约时选择合约名称的正上方的值字段中。
  3. 向下滚动回部署的 dutchAuction 合约并点击购买。

https://img.chengxuka.com

https://img.chengxuka.com

https://img.chengxuka.com

一旦交易完成,NFT的所有权就会转移,荷兰式拍卖就完成了。

此外,合约现在已被破坏。它不会返回任何输出:

https://img.chengxuka.com

结论

如果你成功了,恭喜你;您正在成为 Solidity 专业人才的路上越走越远。在本文中,我们了解了使用智能合约进行拍卖,以及在 Solidity 上编写和部署智能合约以执行荷兰式拍卖。

猜你喜欢

转载自blog.csdn.net/hanru723/article/details/125801739