尚硅谷区块链项目硅谷拍卖系统
Solidity代码
EcommerceStore
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
import "contracts/Escrow.sol";
contract EcommerceStore{
enum ProductStatue { Open, Sold, Unsold }
enum ProductCondition { New, Used }
uint256 public productIndex;
// find owner by producId
mapping(uint256 => address) productInStore;
// find product by owner and onwer's producId
mapping(address => mapping(uint256 => Product)) stores;
mapping(uint256 => address) productEscrow;
struct Product{
uint256 id;
string name;
string category;
string imageLink;
string descLink;
uint256 auctionStartTime;
uint256 auctionEndTime;
uint256 startPrice;
address highestBidder;
uint256 highestBid;
uint256 secondHighestBid;
uint256 totalBids;
ProductStatue status;
ProductCondition condition;
mapping(address => mapping(bytes32 => Bid)) bids;
}
struct Bid{
address bidder;
uint256 productId;
uint256 value;
bool revealed;
}
constructor(){
productIndex = 0;
}
function addProductStore(string memory _name, string memory _category, string memory _imageLink, string memory _descLink, uint256 _auctionStartTime, uint256 _auctionEndTime, uint256 _startPrice, uint256 _productCondition) public returns(uint256){
require(_auctionStartTime < _auctionEndTime);
productIndex += 1;
Product storage product = stores[msg.sender][productIndex];
product.id = productIndex;
product.name = _name;
product.category = _category;
product.imageLink = _imageLink;
product.descLink = _descLink;
product.auctionStartTime = _auctionStartTime;
product.auctionEndTime = _auctionEndTime;
product.startPrice = _startPrice;
product.highestBidder = address(0);
product.highestBid = 0;
product.secondHighestBid = 0;
product.totalBids = 0;
product.status = ProductStatue.Open;
product.condition = ProductCondition(_productCondition);
productInStore[productIndex] = msg.sender;
return productIndex;
}
function bid(uint256 _productId, bytes32 _bidHash) public payable returns (bool){
Product storage product = stores[productInStore[_productId]][_productId];
// require(block.timestamp >= product.auctionStartTime, "current time early");
// require(block.timestamp <= product.auctionEndTime, "current time late");
// require(msg.value > product.startPrice);
product.bids[msg.sender][_bidHash] = Bid(msg.sender, _productId, msg.value, false);
product.totalBids += 1;
return true;
}
function getProduct(uint256 _productId) public view returns(uint256, string memory, string memory, string memory, string memory, uint256, uint256, uint256, ProductStatue, ProductCondition){
// 1. find owner by producId
// 2. find product by productId
Product storage product = stores[productInStore[_productId]][_productId];
return (product.id, product.name, product.category, product.imageLink, product.descLink, product.auctionStartTime, product.auctionEndTime, product.startPrice, product.status, product.condition);
}
function revealBid(uint256 _productId, string memory _amount, string memory _secret) public {
Product storage product = stores[productInStore[_productId]][_productId];
require(block.timestamp >= product.auctionStartTime);
bytes32 sealedBid = sha256(abi.encodePacked(_amount, _secret));
Bid memory bidInfor = product.bids[msg.sender][sealedBid];
require(bidInfor.revealed == false);
uint256 refund;
uint256 newAmount = stringToUint(_amount);
if(bidInfor.value < newAmount){
refund = bidInfor.value;
}else{
// first time
if(product.highestBidder == address(0)){
product.highestBidder = msg.sender;
product.highestBid = newAmount;
product.secondHighestBid = product.startPrice;
refund = bidInfor.value - newAmount;
}else{
// higher than current highest price
if(newAmount > product.highestBid){
product.secondHighestBid = product.highestBid;
// return fund
payable(product.highestBidder).transfer(product.highestBid);
product.highestBid = newAmount;
product.highestBidder = msg.sender;
refund = bidInfor.value - newAmount;
//higher than second price
}else if(newAmount > product.secondHighestBid){
product.secondHighestBid = newAmount;
refund = bidInfor.value;
//lower than second price
}else{
refund = bidInfor.value;
}
}
}
if(refund > 0){
payable(msg.sender).transfer(refund);
}
product.bids[msg.sender][sealedBid].revealed = true;
}
function testHash(string memory a, string memory b) public pure returns(bytes32){
return sha256(abi.encodePacked(a, b));
}
//string to uint
function stringToUint(string memory s) public pure returns(uint256){
bytes memory b = bytes(s);
uint256 result = 0;
for(uint256 i=0; i<b.length; i++){
if(uint8(b[i]) >= 48 && uint8(b[i]) <= 57){
result = result * 10 + uint256(uint8(b[i]) - 48);
}
}
return result;
}
function highestBidderInfor(uint256 _productId) public view returns(address, uint256, uint256){
Product storage product = stores[productInStore[_productId]][_productId];
return(product.highestBidder, product.highestBid, product.secondHighestBid);
}
function totalBids(uint256 _productId) public view returns(uint256){
Product storage product = stores[productInStore[_productId]][_productId];
return product.totalBids;
}
function finalizeAuction(uint256 _productId) public{
Product storage product = stores[productInStore[_productId]][_productId];
require(block.timestamp > product.auctionEndTime);
require(product.status == ProductStatue.Open);
require(msg.sender != productInStore[_productId]);
require(msg.sender != product.highestBidder);
if(product.totalBids == 0){
product.status = ProductStatue.Unsold;
}else{
Escrow escrow = (new Escrow){value: product.secondHighestBid}(_productId, productInStore[_productId], product.highestBidder, msg.sender);
productEscrow[_productId] = address(escrow);
product.status = ProductStatue.Sold;
uint256 refund = product.highestBid - product.secondHighestBid;
payable(product.highestBidder).transfer(refund);
}
}
function escrowInfor(uint256 _productId) public view returns(address, address, address, bool, uint256, uint256){
return Escrow(productEscrow[_productId]).escrowInfor();
}
function escrowAddressForProduct(uint256 _productId) public view returns(address){
return productEscrow[_productId];
}
function releaseAmountToSeller(uint256 _productId) public{
return Escrow(productEscrow[_productId]).realseAmountToSeller(msg.sender);
}
function refundAmountToBuyer(uint256 _productId) public{
return Escrow(productEscrow[_productId]).refundAmountToBuyer(msg.sender);
}
}
Escrow
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract Escrow{
uint256 public productId;
address public seller;
address public buyer;
address public arbiter;
uint256 public amount;
mapping(address=>bool) releaseAmount;
mapping(address=>bool) refundAmount;
uint256 public releaseCount;
uint256 public refundCount;
bool public fundsDisbursed;
event CreateEscrow(uint256 _productId, address _seller, address _buyer, address _arbiter, uint256 _amount);
event UnlockAmount(uint256 _productId, string _operation, address _operator);
event DisburseAmount(uint256 _productId, uint256 _amount, address _beneficiary);
constructor(uint256 _productId, address _seller, address _buyer, address _arbiter) payable {
productId = _productId;
seller = _seller;
buyer = _buyer;
arbiter = _arbiter;
amount = msg.value;
fundsDisbursed = false;
emit CreateEscrow(_productId, _seller, _buyer, _arbiter, amount);
}
function realseAmountToSeller(address caller) public{
require(!fundsDisbursed);
require(caller == seller || caller == buyer || caller == arbiter);
if(!releaseAmount[caller]){
releaseAmount[caller] == true;
refundCount += 1;
emit UnlockAmount(productId, "release to seller", caller);
}
if(releaseCount >= 2){
payable(seller).transfer(amount);
fundsDisbursed = true;
emit DisburseAmount(productId, amount, seller);
}
}
function refundAmountToBuyer(address caller) public{
require(!fundsDisbursed);
require(caller == seller || caller == buyer || caller == arbiter);
if(!refundAmount[caller]){
refundAmount[caller] = true;
refundCount += 1;
emit UnlockAmount(productId, "refund to buyer", caller);
}
if(releaseCount >= 2){
payable(buyer).transfer(amount);
fundsDisbursed = true;
emit DisburseAmount(productId, amount, seller);
}
}
function escrowInfor() public view returns(address, address, address, bool, uint256, uint256){
return (seller, buyer, arbiter, fundsDisbursed, releaseCount, refundCount);
}
}