1.功能描述
該合約主要功能描述如下:
用戶A發(fā)起盲拍項目赡盘,即提出拍賣申請。
競標(biāo)原則
1.所有人都可以對任何一個盲拍項目發(fā)出拍賣申請。
2.競拍用戶每次出價都需要給出一個對外可見的價格(顯式價格)森逮,同時給出一個自己心里認(rèn)為可以接受的價格(隱式價格)妖谴。顯式價格在競拍階段其他人是可以看見的,但是隱式價格別人看不見酵熙。因為這個隱式價格被該用戶利用自己定的密碼加密轧简。即每個人競標(biāo)時輸入兩個數(shù)字和一個密碼,隱式價格和密碼直接在remix編輯器中以參數(shù)的形式輸入匾二,顯式價格以value的形式將以太坊輸入合約內(nèi)哮独。也就是說如果我想買這個東西準(zhǔn)備花10eth,但是我想放出假話我要用12eth來買察藐,我就要先將12eth打入這個合約內(nèi)皮璧。
3.用戶可以重復(fù)對一個商品進行多次競拍(隱式價格可以改,但是你需要記住你最高的一次競拍的密碼和隱式價格)分飞,如果由于誤操作導(dǎo)致隱式價格和密碼兩次都輸入一樣悴务,那么第一次輸入合約的以太坊將無法返還。這點需要注意譬猫!
4.顯式價格必須大于隱式價格讯檐,否則在揭標(biāo)的時候會被認(rèn)作無效標(biāo)。無效競標(biāo)可以提交染服,用于迷惑競爭者别洪,揭標(biāo)時系統(tǒng)會自動退款。
5.競標(biāo)成功的人最終會以合約內(nèi)所有揭標(biāo)后的次高價購買到商品(買家花費的錢比心理預(yù)期少柳刮,賣家至少會得到起拍價)挖垛。
揭標(biāo)原則
1.只能在競標(biāo)和仲裁之間進行
2.競標(biāo)者在揭標(biāo)的相關(guān)函數(shù)中輸入每個發(fā)起過的競標(biāo)的隱式價格和密碼痒钝。這樣每一次發(fā)起的競標(biāo)會由合約進行判斷處理,如果不符合獲勝條件會自動返回給競標(biāo)發(fā)起人晕换。(如果兩次競標(biāo)同一個隱式價格和密碼午乓,只能對最后一次的標(biāo)進行揭標(biāo),前面標(biāo)的錢將丟失在合約中無法退回)
3.揭標(biāo)的時候會一直動態(tài)更新當(dāng)前產(chǎn)品的最高價闸准,次高價和出價人益愈。這時候的所有價格都是隱式價格。由于這個時候已經(jīng)無法競標(biāo)夷家,所以公開隱式價格已經(jīng)無所謂了蒸其,同時也可以讓競標(biāo)成功者知道次高價為多少。
4.競標(biāo)失敗的人會得到系統(tǒng)發(fā)回來的退款库快。
5.最高價的人得到顯式價格與隱式價格的差額摸袁。剩余在合約內(nèi)的前為隱式價格,到仲裁投票后會將與次高位出價的差額退回义屏。
6.如果參與競標(biāo)但是未及時揭標(biāo)靠汁,無法自動退款。所以揭標(biāo)是必須要做的闽铐!
仲裁原則
1.仲裁者不允許是買家或競標(biāo)者蝶怔,會有require()進行判斷。
- 創(chuàng)建一個合約兄墅,將次高價金額踢星、買家、賣家隙咸、仲裁人信息轉(zhuǎn)到第該合約內(nèi)沐悦。
- 仲裁結(jié)束后,將差額(最高價-次高價的)退還給競標(biāo)獲勝的買家五督。
仲裁投票原則
1.只有賣家藏否,競標(biāo)獲勝者和仲裁者可以參與投票。每個人只能投票一次充包,投票有兩個選擇秕岛,一個是支持付款給賣家,一個是付款給買家误证。這個過程是為了防止賣家不發(fā)貨继薛,或者買家拿到東西不愿意付錢設(shè)置的。2.兩個選擇得到票數(shù)先到達兩票時愈捅,合約會執(zhí)行對應(yīng)的付款行為遏考。
我所使用的solidity編譯器版本為0.5.0版本
代碼實現(xiàn)
1.定義競標(biāo)商品結(jié)構(gòu)
pragma solidity ^0.5.0;
contract Auction {
uint productIndex;
struct Product{
uint id;
string name;
string category;
//圖片的鏈接
string imageLink;
//商品描述信息的鏈接
string descLink;
uint startPrice;
uint revealStartTime;
uint arbitrateStartTime;
//商品的狀態(tài):競標(biāo)中,賣出成功蓝谨,賣出失敗
ProductStatus status;
//新的灌具,或者二手的
ProductCondition condition;
//最高價格
uint highestBid;
//次高價格
uint secondHighestBid;
//最高出價者
address payable highestBidder;
//所有的競標(biāo)人數(shù)
uint totalBids;
}
enum ProductStatus {OPEN,SOLD,UNSOLD}
enum ProductCondition {USED,NEW}
}
2.賣家添加競拍商品至商城
在合約中需要添加兩個mapping結(jié)構(gòu)青团,用于賣家-商品-商品id之間相互查找
mapping(address=>mapping(uint=>Product)) stores;
mapping(uint=>address payable) public productIdToOwmer;
添加函數(shù)
function addProductToStore(
string memory _name,
string memory _category,
string memory _imageLink,
string memory _descLink,
uint _startPrice,
uint _revealStartTime,
uint _arbitrateStartTime,
ProductCondition _condition) public{
productIndex++;
Product memory pro = Product({
id:productIndex,
name:_name,
category:_category,
imageLink:_imageLink,
descLink:_descLink,
startPrice:_startPrice,
revealStartTime:_revealStartTime,
arbitrateStartTime:_arbitrateStartTime,
status:ProductStatus.OPEN,
condition:_condition,
highestBid:0,
secondHighestBid:0,
highestBidder:address(0),
totalBids:0
});
stores[msg.sender][productIndex]=pro;
productIdToOwmer[productIndex]=msg.sender;
}
3.競標(biāo)
定義標(biāo)結(jié)構(gòu)
struct Bid {
//對應(yīng)拍賣品的ID
uint productId;
//該標(biāo)中的顯式價格
uint price2Show;
//是否揭標(biāo)標(biāo)志位,為了保證每個標(biāo)只能被揭一次
bool isRevealed;
//本次投標(biāo)的投標(biāo)人地址
address bidder;
}
由于每個人都可以對任何產(chǎn)品發(fā)起投標(biāo)咖楣,所以我們需要為每個商品添加一個管理競標(biāo)的數(shù)據(jù)結(jié)構(gòu)督笆。
設(shè)計思路:由于不想對心里的隱式價格保密,同時還希望能找到自己能找到該標(biāo)诱贿,別人找不到娃肿,設(shè)計數(shù)據(jù)結(jié)構(gòu)如下:
mapping(address=>mapping(bytes32=>Bid)) bids;
address是競標(biāo)人地址,byte32是隱式價格和密碼字符串packed后生成的哈希珠十。這樣料扰,這有自己能找到該標(biāo)。
注意:如果多次競標(biāo)時焙蹭,輸入與上次相同的隱式價格和密碼晒杈,所對應(yīng)的hash一樣。這樣導(dǎo)致key被覆蓋孔厉,上一次的標(biāo)就找不到了拯钻。這也是前面所提的,為什么輸入相同的隱式價格和密碼字符串時撰豺,上一次的競標(biāo)將丟失粪般,里面的以太坊也將丟失在合約內(nèi)無法退出的原因。
將該數(shù)據(jù)結(jié)構(gòu)加入Product結(jié)構(gòu)體
struct Product{
...
mapping(address=>mapping(bytes32=>Bid)) bids;
...
}
競標(biāo)函數(shù)
function bid(uint _productIndex,uint _idealPrice,string memory _password) public payable{
//對隱式價格和密碼打包并求哈希
bytes memory bidInfo = abi.encodePacked(_idealPrice,_password);
bytes32 bytesInfo = keccak256(bidInfo);
//通過商品編號找到該拍賣商品的實例
address owner = productIdToOwmer[_productIndex];
Product storage product = stores[owner][_productIndex];
//確保只能在揭標(biāo)前發(fā)起競標(biāo)
require(now<product.revealStartTime);
product.totalBids++;
//添加標(biāo)進管理數(shù)據(jù)結(jié)構(gòu)
Bid memory b = Bid(_productIndex, msg.value, false, msg.sender);
product.bids[msg.sender][bytesInfo]=b;
}
此時可以寫一些輔助函數(shù)來進行代碼階段性測試
function getBidById(uint _productIndex,uint _idealPrice,string memory _password) public view returns(uint,uint,bool,address){
address owner = productIdToOwmer[_productIndex];
bytes memory bidInfo = abi.encodePacked(_idealPrice,_password);
bytes32 bidBytes = keccak256(bidInfo);
Product storage pro = stores[owner][_productIndex];
Bid memory b = pro.bids[msg.sender][bidBytes];
return (b.productId,b.price2Show,b.isRevealed,b.bidder);
}
function getBalance() public view returns(uint){
return address(this).balance;
}
ps:
本人熱愛圖靈郑趁,熱愛中本聰刊驴,熱愛V神姿搜,熱愛一切被梨花照過的姑娘寡润。
以下是我個人的公眾號,如果有技術(shù)問題可以關(guān)注我的公眾號來跟我交流舅柜。
同時我也會在這個公眾號上每周更新我的原創(chuàng)文章梭纹,喜歡的小伙伴或者老伙計可以支持一下!