基于以太坊truffle框架实践去中心化竞标商城(二)

前言:本文主要介绍合约实现竞标逻辑以及合约中使用到的语法解释

一、竞标拍卖原理规则(也叫第二价格密封拍卖):

见: 维克瑞拍卖_百度百科

二、关系图:
image.png
三、合约代码
pragma solidity ^0.4.18;
contract EbayStore{
uint public productIndex;
function EbayStore() public{
    productIndex =0;
}
enum ProductStatus{
    Open,Sold,Unsold
}
enum ProductCondition{
    New,Used
}
struct Bid{
    address bidder;
    uint productId;
    uint value;
    bool revealed; //是否公告
}
//存储所有商品,mapping类似数组,根据前面的条件可以获得最后一个参数的数据
mapping(address=>mapping(uint=>Product)) stores;
//存储商品ID与所有者的mapping
mapping(uint=>address) productIdInStore; 

struct Product{ 
    uint id;
    string name;
    string category;//分类
    string imageLink;
    string descLink;
    uint auctionStartTime; //开始竞标时间
    uint auctionEndTime; //结束竞标时间
    uint startPrice;//拍卖价格
    address highestBidder;//赢家的钱包地址
    uint highestBid; //竞标的价格
    uint secondHighestBid; //第二高出价
    uint totalBids; //总共多少人参与竞标
    ProductStatus status;
    ProductCondition condition;
    mapping(address => mapping(bytes32 => Bid)) bids;
}
function addProductToStore(string _name, string _category, string _imageLink, string _descLink, 
    uint _auctionStartTime, uint _auctionEndTime, uint _startPrice, uint _productCondition) public{
    require(_auctionStartTime < _auctionEndTime);
    productIndex ++;
    Product memory product = Product(productIndex, _name, _category, _imageLink, _descLink, _auctionStartTime, _auctionEndTime, _startPrice, 0, 0, 0, 0, ProductStatus.Open, ProductCondition(_productCondition));
    stores[msg.sender][productIndex] = product;
    productIdInStore[productIndex] = msg.sender;
}
function getProduct(uint _productId) view public returns(uint,string,string,string,string,uint,uint,uint,ProductStatus,ProductCondition){
    Product memory product = stores[productIdInStore[_productId]][_productId];
    return (product.id, product.name, product.category, product.imageLink, product.descLink, product.auctionStartTime, product.auctionEndTime, product.startPrice, product.status, product.condition);  
}
//出价竞标
function bid(uint _productId,bytes32 _bid) payable public returns(bool) {
    Product storage product = stores[productIdInStore[_productId]][_productId];
    require(now >= product.auctionStartTime);
    require(now >= product.auctionEndTime);
    require(msg.value > product.startPrice);  //mask的值需要大于初始竞标价
    product.bids[msg.sender][_bid] = Bid(msg.sender,_productId,msg.value,false);
    product.totalBids++;
    return true;
}
//公示_amount:实际的价格
function revealBid(uint _productId,string _amount,string _secret){
    Product storage product = stores[productIdInStore[_productId]][_productId];//从mapping中获取product对象
    //条件判断
    require(now > product.auctionEndTime);
    bytes32 sealedBid = sha3(_amount,_secret);//将实际出价+密钥加密成哈希
    Bid memory bidInfo = product.bids[msg.sender][sealedBid];//取出投标者的投标对象
    require(bidInfo.bidder > 0);
    require(bidInfo.revealed == false); //之前没有公示
    uint refund;//退款金额

    uint amount = stringToUint(_amount); //好奇为什么不直接传uint的amount,导致这里需要转换一次
    //mask金额 小于实际报价,则直接全额退款
    if(bidInfo.value < amount ) {
        refund = bidInfo.value;
    }else {
        //如果是第一次出价
        if(product.highestBidder == 0){
            product.highestBidder = msg.sender;
            product.highestBid = amount;
            product.secondHighestBid = product.startPrice;
            refund = bidInfo.value - amount;
        }else{
            if(amount > product.highestBid){
                product.secondHighestBid = product.highestBid;
                //退款,往原最高金额的账户转账之前的最高金额
                product.highestBidder.transfer(product.highestBid);
                product.highestBid = amount;
                product.highestBidder = bidInfo.bidder;//?与源码不一致,按道理bidInfo.address==msg.sender
                //当前投标者还有退款金额
                refund = bidInfo.value - amount;
            }else{
                refund = amount;
            }
        }
    }
    if(refund > 0){
        msg.sender.transfer(refund);
        product.bids[msg.sender][sealedBid].revealed = true;
    }

}
//工具包
function highestBidderInfo(uint _productId) view public returns(address,uint,uint){
    Product memory product = stores[productIdInStore[_productId]][_productId];
    return (product.highestBidder,product.highestBid,product.secondHighestBid);
}
function totalBids(uint _productId) public returns(uint){
    Product memory product = stores[productIdInStore[_productId]][_productId];
    return product.totalBids;
}
//根据ascii转uint规则
function stringToUint(string _str) public returns(uint){
    bytes memory b = bytes(_str);
    uint result = 0;
    for(uint i=0;i<b.length;i++){
        if(b[i]>=48 && b[i] <= 57){
            result = result*10 + (uint(b[i]) - 48);
        }
    }
    return result;
}
}

然后再重新编译compile,部署migrate(注意删除原有编译的合约文件)

四、遇到的问题

如果是手动一个个敲出来的代码,那么应该会遇到一下一些问题。

1、更改sol合约代码之后,compile后重新migrate,会出现以下错误

Error: Attempting to run transaction which calls a contract function, but recipient address 0x8cdaf0cd259887258bc13a92c0a6da92698644c0 is not a contract address
解决办法:
将build的合约删除。(删除目录:build/contracts),再重新compile、migrate即可。

2、struct会有默认的构造方法嘛? contract呢

如在addProductToStore函数中的第三行
Product memory product = Product(productIndex,......);product初始化

struct在初始化时按照顺序struct(param1,param2...)初始化,但是忽略mapping。如

struct A{
    uint i;
    string j;
    mapping map;
    string m;
}

初始化可以是:

A memory a=A(1,"str","str");
3、memory 与 storage 的作用

memory :值传递(默认)
storage: 指针传递
详见:https://blog.csdn.net/liyuechun520/article/details/78408588

4、msg.sender是默认有值吗,如addProduct

msg.sender总是存放着当前函数的外部调用者的地址。

5、提示 CONNECTION ERROR: Couldn't connect to node http://127.0.0.1:9545/

很奇怪,我的truffle.js中明明已经是8545端口了,但这里却报错9545
我的做法:
重新vi编辑了一下truffle.js文件,保存,然后重新truffle develop
在控制端输入web3.accounts就正常了。


目前还是出现该问题了,之前的做法不生效,先留着

6、view、constant、pure修饰的区别

constant:用于返回状态变量时
pure:用于返回写死的常量时,如下图的“HelloWorld”
view:以上情况之外,如:msg.sender


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容