zoukankan      html  css  js  c++  java
  • cryptopunks的代码解释

    1.imageHash
    就是将punk所有图像合在一起的那张图punks.png进行hash得到一个值,并将该值存储到链上,用处就是你可以通过将图像hash然后跟该值对比看图像对不对。这就是它的用处,在代码中它没用。即该图punks.png,在https://github.com/larvalabs/cryptopunks/tree/master/test能得到:


    2.函数简单介绍
    CryptoPunksMarket
    创建10000个token,该合同的拥有者即该合约的部署者owner = msg.sender

    setInitialOwnersetInitialOwners
    将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.整个代码的详细介绍

    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为实例


  • 相关阅读:
    [小技巧]C#中如何为枚举类型添加描述方法
    如何在ASP.NET Core程序启动时运行异步任务(3)
    如何在ASP.NET Core程序启动时运行异步任务(2)
    如何在ASP.NET Core程序启动时运行异步任务(1)
    如何将Azure DevOps中的代码发布到Azure App Service中
    ASP.NET Core WebApi中使用FluentValidation验证数据模型
    探索ASP.NET Core中的IStartupFilter
    C# 8中的可空引用类型
    ASP.NET Core WebAPI中的分析工具MiniProfiler
    ASP.NET Core中如何针对一个使用HttpClient对象的类编写单元测试
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9506390.html
Copyright © 2011-2022 走看看