盲拍智能合约solidity代码
盲拍:
盲拍分为竞价阶段和最终竞价比较阶段,在竞价期间,竞价者并不发送他们的真实竞价,而是一个哈希数据(bytes32 blindedBid)。
竞价期结束后,竞价者必须出示他们的竞价,即多个真假竞价信息数组组合,哈希数据用于帮助合约检查哈希值是否与竞价期提供的哈希值相同。
此外,为防止竞价者在赢得拍卖后不给钱,唯一方法是让竞价者把钱和出价一起寄出去,由于ether转账在以太坊中不能被加密,任何人都可以看到竞价。
下文的contract通过接受任何大于最高竞价来解决这个问题。由于只能在披露阶段进行检查,一些出价可能是无效的,投标者可以通过放置几个高或低的无效出价来混淆竞争。
下文代码在solidity官方英文文档基础上添加很多注释用于帮助加深理解。
pragma solidity ^0.8.4;
//盲拍,Remix编译
contract BlindAuction{
struct Bid{
bytes32 blindedBid;
uint deposit;
}
address payable public beneficiary;//竞价受益人
uint public biddingEnd;//盲拍规定周期
uint public revealEnd;
bool public ended;//竞价状态,默认值为false
//一个竞价者对应有多个竞价信息,用bids保存,其中只有一个为真,其他都为假
mapping(address => Bid[]) public bids;
address public highestBidder;//最高竞价者地址
uint public highestBid;//最高竞价
//mapping类似于散列表和字典,只能声明为状态变量,不支持迭代,支持嵌套
mapping(address => uint) pendingReturns;//保存所有最高竞价信息
//调用event可以将合约中某些内容的更改记录到日志(记录在区块链上),用关键字emit修饰调用
//事件(event)和日志不能在合约内部访问,可以被子合约调用
event AuctionEnded(address winner, uint highestBid);//记录当前最高竞价者
error TooEarly(uint time);//标识盲拍周期还未开始
error TooLate(uint time);//标识盲拍周期已结束
error AuctionEndAlreadyCalled();//标识盲拍已进行
//modifier类似于一个可以通用的函数供其他function重复调用,减少代码量
//_;可以放在modifier结构体{}内的任何位置来运行调用modifier的function代码
//当前时间已错过盲拍周期
modifier onlyBefore(uint time){
if(block.timestamp >= time)
revert TooLate(time);
_;
}
//盲拍还未开始
modifier onlyAfter(uint time){
if(block.timestamp <= time)
revert TooEarly(time);
_;
}
//构造函数,仅在部署合约时调用一次,初始化盲拍受益者地址、盲拍竞价周期、
constructor(uint biddingTime,uint revealTime,address payable beneficiaryAddress){
beneficiary = beneficiaryAddress;
biddingEnd = block.timestamp + biddingTime;
revealEnd = biddingEnd + revealEnd;
}
//先判断当前时间是否在竞拍周期内,再将竞拍信息写入bids
function bid(bytes32 blindedBid) external payable onlyBefore(biddingEnd){
//注:msg.sender指调用该函数的地址,而不是调用整个合约的地址,.push是动态数组方法
bids[msg.sender].push(Bid({
blindedBid:blindedBid,
deposit:msg.value
}));
}
//calldata用于存储函数参数,是不可修改、非持久的函数参数存储区域
//先判断该function是否处于正确的盲拍周期内,values[]存储所有真假竞价信息
//fakes[]标记values[]中对应信息的真假,secrets[]仅用于辅助计算加密信息,无实际意义
//reveal()用于从多个真假竞拍信息中找出真的并进行转账
function reveal(uint[] calldata values,bool[] calldata fakes,bytes32[] calldata secrets) external
onlyAfter(biddingEnd) onlyBefore(revealEnd){
uint length = bids[msg.sender].length;//记录调用该function的地址的竞拍次数
//require()中判断条件为true则继续,为false则退出该function,回退该function内所有更改
require(values.length == length);//values[]、fakes[]、secrets[]的长度均相等
require(fakes.length == length);//否则退出该function
require(secrets.length == length);
uint refund;//用于保存真的那个竞价信息
//keccak256是SHA-3成熟的一种加密算法
//遍历调用者的所有竞拍信息,可有多个真的竞价信息
for(uint i=0;i<length;i++){
Bid storage bidToCheck = bids[msg.sender][i];//取出调用者的第i条竞拍信息
(uint value,bool fake,bytes32 secret) = (values[i],fakes[i],secrets[i]);//calldata类型数据只读,不能修改,故需赋值
//abi.encodePacked(...) returns (bytes memory)
//abi.encodePacked()是solidity中数据打包、连接方法
//元素之间用逗号连接,支持多种不同数据类型(struct和嵌套数组除外)
//keccak256(bytes memory) returns (bytes32)用于加密数据
if(bidToCheck.blindedBid != keccak256(abi.encodePacked(value,fake,secret))){
continue;//跳出本次循环继续下一次循环
}
refund += bidToCheck.deposit;//找到真的竞价信息就将竞价金额deposit取出
if(!fake && bidToCheck.deposit >= value){
if(placeBid(msg.sender,value))
refund -= value;
}//若该条竞价信息为真且该竞价者的钱足够支付,则调用placeBid()转钱并置空refund
bidToCheck.blindedBid = bytes32(0);//将此条竞价标识置为0x00
}
//运行到此处refund==0,为防止for循环出错,返还调用者竞价金额
payable(msg.sender).transfer(refund);//给调用此function的地址转账
}
//重置盲拍状态
function auctionEnd() external onlyAfter(revealEnd){
if(ended)
revert AuctionEndAlreadyCalled();//若成立则退出函数,回退已更改状态
emit AuctionEnded(highestBidder,highestBid);//记录最高竞价者、最高竞价为事件于日志上
ended = true;
beneficiary.transfer(highestBid);//给盲拍受益人转账
}
//退钱
function withdraw() external{
uint amount = pendingReturns[msg.sender];
if(amount>0){
pendingReturns[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
}
//用于转帐
function placeBid(address bidder,uint value) internal returns(bool success){
if(value <= highestBid){
return false;//当前竞价并非最高,竞价失败
}
if(highestBidder != address(0)){
pendingReturns[highestBidder] += highestBid;
}//若竞价者地址有效,则添加竞价信息
highestBid = value;//重置最高竞价
highestBidder = bidder;//重置最高竞价者地址
return true;
}
}
来源(solidity官方英文文档0.8.13):https://docs.soliditylang.org/en/v0.8.13/solidity-by-example.html#id2
solidity官方中文文档0.8.0:https://learnblockchain.cn/docs/solidity/solidity-by-example.html#id5
keccak256()官方英文文档介绍:https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#non-standard-packed-mode
abi.encodePacked()官方英文文档介绍:https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#non-standard-packed-mode

浙公网安备 33010602011771号