基於以太坊的拍賣系統-合約編寫(一)

安裝ganache-cli

ganache-cli是以太坊節點仿真器軟件ganache的命令行版本,可以方便開發者快速進行以太坊DApp的開發與測試。

npm install -g ganache-cli

啓動

~$ ganache-cli 

啓動選項

  • -a 或 --accounts: 指定啓動時要創建的測試賬戶數量。
  • -e 或 --defaultBalanceEther: 分配給每個測試賬戶的ether數量,默認值爲100。
  • -b 或r --blockTime: 指定自動挖礦的blockTime,以秒爲單位。默認值爲0,表示不進行自動挖礦。
  • -d 或 --deterministic: 基於預定的助記詞(mnemonic)生成固定的測試賬戶地址。
  • -n 或 --secure: 默認鎖定所有測試賬戶,有利於進行第三方交易簽名。
  • -m 或 --mnemonic: 用於生成測試賬戶地址的助記詞。
  • -p 或 --port: 設置監聽端口,默認值爲8545。
  • -h 或 --hostname: 設置監聽主機,默認值同NodeJS的server.listen() 
  • -s 或 --seed: 設置生成助記詞的種子。.
  • -g 或 --gasPrice: 設定Gas價格,默認值爲20000000000。
  • -l 或 --gasLimit: 設定Gas上限,默認值爲90000。
  • -f 或 --fork: 從一個運行中的以太坊節點客戶端軟件的指定區塊分叉。輸入值應當是該節點旳HTTP地址和端口,例如http://localhost:8545。 可選使用@標記來指定具體區塊,例如:http://localhost:8545@1599200
  • -i 或 --networkId:指定網絡id。默認值爲當前時間,或使用所分叉鏈的網絡id。
  • --db: 設置保存鏈數據的目錄。如果該路徑中已經有鏈數據,ganache-cli將用它初始化鏈而不是重新創建。
  • --debug:輸出VM操作碼,用於調試。
  • --mem:輸出ganache-cli內存使用統計信息,這將替代標準的輸出信息。
  • --noVMErrorsOnRPCResponse:不把失敗的交易作爲RCP錯誤發送。開啓這個標誌使錯誤報告方式兼容其他的節點客戶端,例如geth和Parity。

特殊選項

  • --account: 指定賬戶私鑰和賬戶餘額來創建初始測試賬戶。可多次設置:
$ ganache-cli --account="<privatekey>,balance" [--account="<privatekey>,balance"]

注意私鑰長度爲64字符,必須使用0x前綴的16進制字符串。賬戶餘額可以是整數,也可以是0x前綴的17進制字符串,單位爲wei。

使用--account選項時,不會自動創建HD錢包。

  • -u 或 --unlock: 解鎖指定賬戶,或解鎖指定序號的賬戶。可以設置多次。當與--secure選項同時使用時,這個選項將改變指定賬戶的鎖定狀態:
$ ganache-cli --secure --unlock "0x1234..." --unlock "0xabcd..."

也可以指定一個數字,按序號解鎖賬號:

$ ganache-cli --secure -u 0 -u 1

安裝Truffle

1、下載官網Nodejs12版本

2、解壓到對應目錄下,並改名爲node

3、配置環境變量

gedit ~/.bashrc

export NODE_HOME=/opt/node

export PATH=$PATH:$NODE_HOME/bin 

export NODE_PATH=$NODE_HOME/lib/node_modules

保存後
source ~/.bashrc

4、安裝Truffle

$ npm install -g truffle

結束後進入truffle命令行即成功

合約項目

1、創建項目路徑

mkdir auction_dapp
cd auction_dapp
truffle unbox webpack
rm constracts/ConvertLib.sol constracts/MetaCoin.sol 

2、創建EcommerceStore.sol文件,編寫滿足需求的合約

pragma solidity ^0.4.17;

contract EcommerceStore{
    
    enum ProductStatus{Open, Sold, Unsold}
    enum ProductCondition{New, Used}
    
    
    uint public productIndex;
    mapping (uint => address) productIdInstore;
    mapping (address => mapping(uint => Product)) stores;
    
    struct Bid{
        address bidder;
        uint productId;
        uint value;
        bool revealed;
    }
    
    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 constructor() public{
        productIndex = 0;
    }
    
    function addProductToStore(string _name,string _category, string _imageLink, string _descLink
                                ,uint _auctionStartTime,uint _auctionEndTime,uint _startPrice,uint _productCondition)public{
        require(_auctionStartTime < _auctionEndTime);
        productIndex += 1;
        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) public view 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);
        require(product.bids[msg.sender][_bid].bidder == 0);
        product.bids[msg.sender][_bid] = Bid(msg.sender, _productId,msg.value,false);
        product.totalBids += 1;
        return true;
    }
    
    function revealBid(uint _productId, string _amount, string _secret) public{
        Product storage product = stores[productIdInstore[_productId]][_productId];
        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);
        
        if(bidInfo.value < amount){
            refund = bidInfo.value;
        }else{
            if(address(product.highestBidder) == 0){//first time 
                product.secondHighestBid = product.highestBid;
                product.highestBidder.transfer(product.highestBid);
                product.highestBidder = msg.sender;
                product.highestBid = amount;
                refund = bidInfo.value - amount;
            }else{
                if(amount > product.highestBid){
                    product.secondHighestBid = product.highestBid;
                    product.highestBid = amount;
                    product.highestBidder = msg.sender;
                    
                }else if(amount > product.secondHighestBid){
                    product.secondHighestBid = amount;
                    refund = bidInfo.value;
                }else{
                    refund = amount;
                }
            }
        }
        
        product.bids[msg.sender][sealedBid].revealed = true;
        
        if (refund > 0) {
            msg.sender.transfer(refund);
        }
    }
    
    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) view public returns (uint) {
        Product memory product = stores[productIdInstore[_productId]][_productId];
        return product.totalBids;
    }
    
    function stringToUint(string s)pure private returns(uint){
        bytes memory b = bytes(s);
        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;
    }
}

3、將EcommerceStore.sol拷貝到項目的contracts目錄下,將本來存在的ConvertLib.sol和MetaCoin.sol刪除,保留Migration.sol和新合約EcommerceStore.sol

4、回到auction_dapp目錄下,修改對應的truffle-config.js文件

development:{
    host: "127.0.0.1",
    port: 8545,
    network_id: "*", //network的廣泛選擇性
}

compilers: {
    solc: {
       version: "0.4.17",    // 與編寫的合約版本相同
    }
}

5、truffle編譯

cd contracts
truffle compile

生成的結果到build/constracts下的json文件中

6、truffle部署相應的合約,前提是ganache-cli必須已經啓動

//是否重新部署
truffle migrate (--reset)

7*啓動控制檯類似於私鏈geth的使用

truffle console
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章