cryptopunks的代碼解釋

1.imageHash
就是將punk全部圖像合在一塊兒的那張圖punks.png進行hash獲得一個值,並將該值存儲到鏈上,用處就是你能夠經過將圖像hash而後跟該值對比看圖像對不對。這就是它的用處,在代碼中它沒用。即該圖punks.png,在https://github.com/larvalabs/cryptopunks/tree/master/test能獲得:html


2.函數簡單介紹
CryptoPunksMarket
建立10000個token,該合同的擁有者即該合約的部署者owner = msg.sender

setInitialOwner\setInitialOwners
將token初始無償送給一些用戶的函數,只有合同擁有者才能調用這兩個函數(if (msg.sender != owner) throw;)當變量allPunksAssigned爲false時這兩個函數才能調用,這時候其餘的函數都不能調用。該兩個函數是在合同剛部署時使用的,由於當allPunksAssigned被設爲true後,這兩個函數將永遠不能被調用。即便一個token剛剛送給了別的用戶,合同擁有者仍是能經過函數setInitialOwner將其拿回,轉送給另外一個用戶

allInitialOwnersAssigned
將變量allPunksAssigned設爲true,這樣,上面的兩個無償贈送的函數就不能使用了,只能使用下面的其餘函數

getPunk
用戶仍是能夠經過這份函數來無償得到token,不一樣之處在於:
首先不須要是合同擁有者也能調用這個函數,可是這有那些無主的token才能被get

transferPunk
把本身擁有的token轉贈給別的用戶

punkNoLongerForSale
把以前標價打算要賣出去的token取消了,就是不打算sell了

offerPunkForSale
把本身的token標一個最低價想要賣出

offerPunkForSaleToAddress
把本身的token標一個最低價想要賣給一個指定的用戶

buyPunk
購買那些標價賣出的token

withdraw
將本身臨時帳戶中的錢取出來
enterBidForPunk
進入到某個token的競標市場,只有出價比以前最高價高時該競標纔回成功,成爲最高價

acceptBidForPunk
sell方接受競標

withdrawBidForPunk
競標方放棄競標

3.整個代碼的詳細介紹git

pragma solidity ^0.4.8;
contract CryptoPunksMarket {

    // 圖片的hash值,用於驗證圖片文件的正確性
    string public imageHash = "ac39af4793119ee46bbff351d8cb6b5f23da60222126add4268e261199a2921b";

//該合約的擁有者聲明
    address owner;
//該token的一些定義信息
    string public standard = 'CryptoPunks';
    string public name;
    string public symbol;
    uint8 public decimals;
//token的總量聲明
    uint256 public totalSupply;

//下一個被分配的token的索引,從0開始
    uint public nextPunkIndexToAssign = 0;
//用於上鎖函數
    bool public allPunksAssigned = false;
//剩餘的可以進行分配的token數量
    uint public punksRemainingToAssign = 0;

//將token索引映射到擁有者的地址,punkIndexToAddress[0]即獲得索引爲0的token的擁有者地址
    mapping (uint => address) public punkIndexToAddress;

 //用戶所擁有的token的數量
    mapping (address => uint256) public balanceOf;

//聲明賣token的結構體
    struct Offer {
        bool isForSale;//true即token正在賣出
        uint punkIndex;
        address seller;//賣方,及其主人
        uint minValue;          // in ether,賣出最低價
        address onlySellTo;     //用於設置賣給誰,不設則賣給誰均可以
    }

//聲明競標token的結構體
    struct Bid {
        bool hasBid;//是否正在競標
        uint punkIndex;
        address bidder;
        uint value;
    }

//經過token索引來查看該token的賣出信息,也可能沒有
    mapping (uint => Offer) public punksOfferedForSale;

//經過token索引來查看該token的最高價競標信息,也可能沒有
    mapping (uint => Bid) public punkBids;
//用戶的臨時帳戶,存放其賣token的回報或者競標失敗退回的競標額
    mapping (address => uint) public pendingWithdrawals;

//用於事件監聽
    event Assign(address indexed to, uint256 punkIndex);
    event Transfer(address indexed from, address indexed to, uint256 value);
    event PunkTransfer(address indexed from, address indexed to, uint256 punkIndex);
    event PunkOffered(uint indexed punkIndex, uint minValue, address indexed toAddress);
    event PunkBidEntered(uint indexed punkIndex, uint value, address indexed fromAddress);
    event PunkBidWithdrawn(uint indexed punkIndex, uint value, address indexed fromAddress);
    event PunkBought(uint indexed punkIndex, uint value, address indexed fromAddress, address indexed toAddress);
    event PunkNoLongerForSale(uint indexed punkIndex);

    //構造函數,初始化該token
    function CryptoPunksMarket() payable {
     
        owner = msg.sender;
        totalSupply = 10000;                        //token總數爲10000
        punksRemainingToAssign = totalSupply; //餘量爲10000
        name = "CRYPTOPUNKS";                                   // Set the name for display purposes
        symbol = "Ͼ";                               // Set the symbol for display purposes
        decimals = 0;                                       // Amount of decimals for display purposes
    }

//合約擁有者經過調用該函數將token送給某些用戶
    function setInitialOwner(address to, uint punkIndex) {
        if (msg.sender != owner) throw;    //函數調用者必須是合約擁有者
        if (allPunksAssigned) throw;      //allPunksAssigned要爲false
        if (punkIndex >= 10000) throw;    //punkIndex即token的索引要小於token總數10000
        if (punkIndexToAddress[punkIndex] != to) { //token的主人不能是要送給的用戶
            if (punkIndexToAddress[punkIndex] != 0x0) {//送出去的token能夠收回再送給別的用戶
                balanceOf[punkIndexToAddress[punkIndex]]--;
            } else {
                punksRemainingToAssign—;   //該token以前沒被贈送過,可分配token數減1
            }
            punkIndexToAddress[punkIndex] = to;   //更換token擁有者爲to
            balanceOf[to]++;   //to用戶的token擁有總數加1
            Assign(to, punkIndex);   //事件event Assign,監聽到該事件則說明該函數調用成功
        }
    }

//同時將多個token送給多個用戶
    function setInitialOwners(address[] addresses, uint[] indices) {
        if (msg.sender != owner) throw;
        uint n = addresses.length;
        for (uint i = 0; i < n; i++) {
            setInitialOwner(addresses[i], indices[i]);
        }
    }
//將變量allPunksAssigned設置爲true,用以中止上面兩個函數的使用,開始下面函數的使用
    function allInitialOwnersAssigned() {
        if (msg.sender != owner) throw;
        allPunksAssigned = true;
    }

//任何用戶均可以經過該函數來得到無主的token
    function getPunk(uint punkIndex) {
        if (!allPunksAssigned) throw;  //allPunksAssigned爲true
        if (punksRemainingToAssign == 0) throw;   //剩下可以分配的token數要大於0
        if (punkIndexToAddress[punkIndex] != 0x0) throw; //只能獲得無主token
        if (punkIndex >= 10000) throw;   //punkIndex即token的索引要小於token總數10000
        punkIndexToAddress[punkIndex] = msg.sender;
        balanceOf[msg.sender]++;
        punksRemainingToAssign--;
        Assign(msg.sender, punkIndex);   //事件event Assign,監聽到該事件則說明該函數調用成功
    }

    // 轉贈token
    function transferPunk(address to, uint punkIndex) {
        if (!allPunksAssigned) throw;   //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] != msg.sender) throw;  //函數調用者必須是token的主人
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
        if (punksOfferedForSale[punkIndex].isForSale) {  //若是以前想要sell這個token,則先取消sell
            punkNoLongerForSale(punkIndex);
        }
        punkIndexToAddress[punkIndex] = to;
        balanceOf[msg.sender]--;
        balanceOf[to]++;
        Transfer(msg.sender, to, 1);  //事件event Transfer,監聽到該事件則說明該函數調用成功
        PunkTransfer(msg.sender, to, punkIndex); //事件
        // Check for the case where there is a bid from the new owner and refund it.
        // Any other bid can stay in place.
//查看被贈方是否以前有對該token進行投標,有則取消,並將其投標的金額放進其臨時帳戶中
        Bid bid = punkBids[punkIndex];
        if (bid.bidder == to) {
            // Kill bid and refund value
            pendingWithdrawals[to] += bid.value;
            punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0);//清空投標信息,並設置狀態爲false
        }
    }

//取消以前設置的token賣出信息
    function punkNoLongerForSale(uint punkIndex) {
        if (!allPunksAssigned) throw;   //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] != msg.sender) throw; //函數調用者必須是token的主人
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
//清空賣出offer信息,並設置狀態爲false       
 punksOfferedForSale[punkIndex] = Offer(false, punkIndex, msg.sender, 0, 0x0);
        PunkNoLongerForSale(punkIndex);
    }

//想將某token賣出,將相應信息寫入offer中,用以告知你們
    function offerPunkForSale(uint punkIndex, uint minSalePriceInWei) {
        if (!allPunksAssigned) throw;   //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] != msg.sender) throw;  //函數調用者必須是token的主人
        if (punkIndex >= 10000) throw;   //punkIndex即token的索引要小於token總數10000
//將相應的信息寫入結構體offer中
        punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, 0x0);
        PunkOffered(punkIndex, minSalePriceInWei, 0x0);//事件PunkOffered,用以告知函數調用成功
    }

//聲明某token想要賣給某個特定的用戶
    function offerPunkForSaleToAddress(uint punkIndex, uint minSalePriceInWei, address toAddress) {
        if (!allPunksAssigned) throw; //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] != msg.sender) throw; //函數調用者必須是token的主人
        if (punkIndex >= 10000) throw;    //punkIndex即token的索引要小於token總數10000
//將相應的信息寫入結構體offer中
        punksOfferedForSale[punkIndex] = Offer(true, punkIndex, msg.sender, minSalePriceInWei, toAddress);
        PunkOffered(punkIndex, minSalePriceInWei, toAddress);//事件PunkOffered,用以告知函數調用成功
    }

//購買在offer中設置爲賣出的token
    function buyPunk(uint punkIndex) payable {
        if (!allPunksAssigned) throw;      //allPunksAssigned爲true
        Offer offer = punksOfferedForSale[punkIndex];  //token的賣出信息
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
        if (!offer.isForSale) throw;                // token的賣出狀態要爲true
//token指定的賣出用戶要是函數調用者或者沒有指定賣出用戶
        if (offer.onlySellTo != 0x0 && offer.onlySellTo != msg.sender) throw;
        if (msg.value < offer.minValue) throw;      // 你的出價必須大於或等於offer中標出的價格
        if (offer.seller != punkIndexToAddress[punkIndex]) throw; //offer中代表的賣方必須仍是token的主人

        address seller = offer.seller;

        punkIndexToAddress[punkIndex] = msg.sender;
        balanceOf[seller]--;
        balanceOf[msg.sender]++;
        Transfer(seller, msg.sender, 1); //事件Transfer,說明買賣成功

        punkNoLongerForSale(punkIndex);  //清空賣出offer信息
        pendingWithdrawals[seller] += msg.value;  //將賣出的錢msg.value寫入seller的臨時帳戶
        PunkBought(punkIndex, msg.value, seller, msg.sender); //事件

       //若是該函數調用者以前有投標過該token,則取消,並將投標錢放入臨時帳戶中
        Bid bid = punkBids[punkIndex];
        if (bid.bidder == msg.sender) {
            // Kill bid and refund value
            pendingWithdrawals[msg.sender] += bid.value;
            punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0);//清空投標信息
        }
    }

//將臨時帳戶中的錢拿出,其實就是要求合約地址send回錢
    function withdraw() {
        if (!allPunksAssigned) throw;   //allPunksAssigned爲true
        uint amount = pendingWithdrawals[msg.sender];
        // Remember to zero the pending refund before
        // sending to prevent re-entrancy attacks
        pendingWithdrawals[msg.sender] = 0;  //清空臨時帳戶
        msg.sender.transfer(amount);  //合約地址send回錢amount給msg.sender,即合約調用者
    }

//進入某個token的投標市場
    function enterBidForPunk(uint punkIndex) payable {
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
        if (!allPunksAssigned) throw;       //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] == 0x0) throw;  //該token要有主
        if (punkIndexToAddress[punkIndex] == msg.sender) throw;  //該token的主人不是函數調用者
        if (msg.value == 0) throw;   //投標價格必定要大於0
        Bid existing = punkBids[punkIndex];   //以前的最高價的投標信息
        if (msg.value <= existing.value) throw;   //出的投標價高於以前的最高價時,該投標才成功
        if (existing.value > 0) {//以前投標的人的投標價會返回到它的臨時帳戶中
            // Refund the failing bid
            pendingWithdrawals[existing.bidder] += existing.value;
        }
        punkBids[punkIndex] = Bid(true, punkIndex, msg.sender, msg.value); //覆蓋投標信息
        PunkBidEntered(punkIndex, msg.value, msg.sender); //事件
    }

//接受目前出最高投標價的投標者的投標
    function acceptBidForPunk(uint punkIndex, uint minPrice) {
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
        if (!allPunksAssigned) throw;    //allPunksAssigned爲true
        if (punkIndexToAddress[punkIndex] != msg.sender) throw; //只有token主人才能接受投標
        address seller = msg.sender;  //賣方地址
        Bid bid = punkBids[punkIndex]; //投標信息
        if (bid.value == 0) throw;  //投標價等於0說明沒人投標
        if (bid.value < minPrice) throw;  //投標價要大於接受投標的最小价格

        punkIndexToAddress[punkIndex] = bid.bidder;
        balanceOf[seller]--;
        balanceOf[bid.bidder]++;
        Transfer(seller, bid.bidder, 1);
//成功後,不管是賣出offer仍是投標bid信息都要被清空,offer中的主人會換成投標者
        punksOfferedForSale[punkIndex] = Offer(false, punkIndex, bid.bidder, 0, 0x0);
        uint amount = bid.value;
        punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0);
        pendingWithdrawals[seller] += amount;  //seller賺到的錢放入臨時帳戶
        PunkBought(punkIndex, bid.value, seller, bid.bidder);//事件
    }

//取消對某個token的投標
    function withdrawBidForPunk(uint punkIndex) {
        if (punkIndex >= 10000) throw;  //punkIndex即token的索引要小於token總數10000
        if (!allPunksAssigned) throw;       //allPunksAssigned爲true         
        if (punkIndexToAddress[punkIndex] == 0x0) throw;   //該token要有主
        if (punkIndexToAddress[punkIndex] == msg.sender) throw;  //該token的主人不是函數調用者
        Bid bid = punkBids[punkIndex];  //投標信息
        if (bid.bidder != msg.sender) throw;  //投標者即函數調用者
        PunkBidWithdrawn(punkIndex, bid.value, msg.sender); //事件
        uint amount = bid.value;
        punkBids[punkIndex] = Bid(false, punkIndex, 0x0, 0); //清空投標信息
        // Refund the bid money
        msg.sender.transfer(amount);  //直接將投標價send給投標者,不放入臨時帳戶
    }

}

 



注:
1.爲何要設置臨時帳戶:
由於當用戶調用定義爲payable的函數時,它經過msg.value    傳入的金額其實已經從他的帳戶中轉到了該合約地址當中,就是調用函數的交易的from爲函數調用者,to爲合約地址。當其後面想要取消該函數的調用時,好比以前投標bid了某token,後面想取消時,函數就會講bid結構體中記錄的你的投標價格放入你的臨時帳戶中,語句msg.sender.transfer(金額數)就是合約地址將該金額轉回給你了


對裏面使用到的solidity的介紹,看這裏solidity學習-cryptoPunks爲實例


github

相關文章
相關標籤/搜索