智能合约开发之简易球星卡交易系统

个人自制编写了一个简易球星卡智能合约,暂不包括前端后端

此合约是在以太坊上部署一个集卡类游戏,玩家可以购买卡片获得自己喜爱的稀有的球星卡,玩家也可以在交易所卖出或者买入自己中意的卡片。

功能包括:
  • getplayer 查看当前用户拥有的卡片
  • getStarcard 查看指定卡片向合约购买的价格(ether)
  • getCreatesale 查看制定交易下标返回详细数值
  • getallCrea 返回当前所有的交易

  • Starcardbuy 输入指定卡片号码与转账ether向合约购买卡片
  • Createsale 输入指定卡片号码与指定数额创建一个交易
  • Starcardbuytran 输入指定交易下标与转账ether竞拍交易
  • open 输入指定下标,交易发起者可调用此合约结束竞拍,最高者获得指定卡片

代码如下:
pragma solidity ^0.4.20;

contract Starcard {
    address Boss;
    uint[20] StarID;
    uint[20] cardID;
    mapping (address => uint[20]) balances;
    struct tran{
        address Seller;
        uint8 ofcard;
        uint price;
        uint auction;
        uint time;
        address HighestBidder;
        uint HighestPrice;
        bool status1;
    }
     tran[] Tran;
    function Starcard() public{
        Boss = msg.sender;
        for(uint8 i=0;i<20;i++){
            StarID[i]=20-i;
        }
    }
    function getStarcard(uint i) public view returns(uint,bool){
        if(i<20){
            return (StarID[i],true);
        }
        else
            return (0,false);
    }
    function Starcardbuy(uint i)payable public returns(uint[20],bool){
        if(StarID[i]==msg.value/(10**18)){
           cardID=balances[msg.sender];
           cardID[i] = cardID[i]+1;
           balances[msg.sender] = cardID;
           return(balances[msg.sender],true);
        }
        else{
            msg.sender.transfer(msg.value);
            return(balances[msg.sender],false);
        }
    }
    function getplayer() public view returns(uint[20]){
        return balances[msg.sender];
    }
    function Createsale(uint8 thecard,uint theprice) public returns(uint,bool){
        cardID = balances[msg.sender];
        tran memory tra;
        if(cardID[thecard] != 0){
            tra.Seller = msg.sender;
            tra.ofcard = thecard;
            tra.price = theprice;
            tra.auction = tra.price*6/10;
            tra.status1 = true;
            tra.time = block.number;
            Tran.push(tra);
            cardID[thecard] = cardID[thecard]-1;
            balances[msg.sender] = cardID;
            return (Tran.length-1,true);
        }
        else
            return (0,false);
    }
    function Starcardbuytran(uint _number)payable public returns(string,bool){
        if(msg.sender != Tran[_number].Seller){
            if(Tran[_number].price == msg.value/(10**18)){
                if(Tran[_number].HighestBidder != 0){
                    Tran[_number].HighestBidder.transfer(Tran[_number].HighestPrice*(10**18));
                }
                Tran[_number].Seller.transfer(msg.value*9/10);
                cardID=balances[msg.sender];
                cardID[Tran[_number].ofcard] += 1;
                balances[msg.sender] = cardID;
                delete Tran[_number];
                return ("price",true);
            }
            else if(msg.value/(10**18) >= Tran[_number].auction && msg.value/(10**18) > Tran[_number].HighestPrice){
                if(Tran[_number].HighestBidder != 0){
                    Tran[_number].HighestBidder.transfer(Tran[_number].HighestPrice*(10**18));
                }
                Tran[_number].HighestBidder = msg.sender;
                Tran[_number].HighestPrice = msg.value/(10**18);
                return ("HighestBidder",true);
            }
            else {
                msg.sender.transfer(msg.value);
                return ("Low",false);
            }
        }
        else
            return ("FAQ",false);
    }
    function open(uint ofnumber)public returns(string,bool){
        if(Tran[ofnumber].Seller == msg.sender){
            if(Tran[ofnumber].time + 6 <= block.number){
                if(Tran[ofnumber].HighestPrice != 0){
                    msg.sender.transfer(Tran[ofnumber].HighestPrice*(10**18));
                    cardID = balances[Tran[ofnumber].HighestBidder];
                    cardID[Tran[ofnumber].ofcard] += 1;
                    balances[Tran[ofnumber].HighestBidder] = cardID;
                    delete Tran[ofnumber];
                    return ("OK",true);
                }
                else
                    return ("No HighestBidder",false);
            }
             else
                 return("No time",false);
        }
        else
            return ("you no Seller",false);
    }
    function() external payable {
        if(msg.value != 0)
            msg.sender.transfer(msg.value);
    }
    function getCreatesale(uint thnumbe) public view returns(uint8,uint,uint){
        return (Tran[thnumbe].ofcard,Tran[thnumbe].price,Tran[thnumbe].HighestPrice);
    }
    function getallCrea() public view returns(uint,uint8,uint,uint){
        for(uint dubi;dubi <= Tran.length-1;dubi++){
            if(Tran[dubi].Seller != 0){
                return (dubi,Tran[dubi].ofcard,Tran[dubi].price,Tran[dubi].HighestPrice);
            }
        }
    }
}

案例:向合约转账并读取合约余额

pragma solidity ^0.4.20;
//每一份合约前都要加这一句来定义使用的solidity的版本
contract SendMoney{
//定义一个名称为**的合约
    function () public payable{
    }
    //一个没有名称的方法它会向合约转账
    function getBalance() constant public returns(uint){
        return address(this).balance;
    }
    /*定义了一个查看当前合约余额的方法
      这里getBalance()为方法名 constant为标明本方法并不会产生数据,public为此方法可见returns(uint)标明此方法会返回一个uint类型的值.

        !return address(this).balance
        address(this).balance它的值为当前合约拥有多少余额,return会返回它*/
}

这个案例很简单又让人清晰看清solidity的语法,solidity向合约转账的方式具体有两种(详细的话三种),一种向合约转账与一种部署合约时转账,下面会有例子讲道如何部署合约时转账。

address(this).balance //返回合约余额

案例:将钱从合约中转出

    pragma solidity ^0.4.20;
    contract GetMoney{
        address owner;
        function GetMoney() public{  //GetMoney构造函数
            owner = msg.sender; //构造时调用的函数 owner合约发起人
        }
        function () public payable{
        }
        function getBalance() constant public returns(uint){
            return address(this).balance;
        }
        function showMeTheMoney() payable public returns(bool) { //有关于钱的方法定义都要+ payable
            address who = msg.sender; //who记录了是谁要钱
            if(getBalance() >= 1 ether) //调用getBalance方法判断余额>=1
            {
                who.transfer(1 ether); //向要钱的人转出 1 个以太币
                return true;
            }
            return false;
        }
        function kill() public{
            if (msg.sender == owner){
                selfdestruct(owner);
            }
        }
        //调用kill方法会验证msg.sender调用者是不是owner(合约发起人)是的话杀死此合约并将合约剩余的以太币发送到owner(合约发起人),注意selfdestruct中可以填入其他账户。
    }

这个案例比上一个案例多加了构造函数与几个方法,理解上一个案例这个案例将很好理解。

    msg.sender //返回当前账户
    payable //涉及钱的变动就要加此声明
    *.transfer(*) //想特定的账户转入特定的ether
    selfdestruct(owner);//死此合约并将合约剩余的以太币发送到owner(合约发起人),注意selfdestruct中可以填入其他账户。

案例:发红包

pragma solidity ^0.4.20;
// the Tutao put the money in contract,
// others can get Money from the redPacket
contract redPacket {
    address tuhao;
    int pieces;
    function redPacket(int _pieces) public payable {
        tuhao = msg.sender;
        pieces = _pieces;
    }
    function getBalance() public view returns (uint) { //view与constant标识基本相同,表示并不会产生数据修改
      //  return tuhao.balance; //返回tuhao的余额 !!此条语句为错误的并且会影响下面程序导致无法正常分红包!

        return address(this).balance;//此条语句才是正确语句,返回合约余额
    }   
    function showMeTheMoney() payable public returns (bool) {
        address who = msg.sender; //who记录了谁想分钱
        if(pieces > 0) //pieces为红包数
        {
            pieces --; //每次调用一次红包数-1
            uint hash = uint(block.blockhash(block.number-1));
            //!这里hash记录了当前区块的hash值block.blockhash(block.number)的返回值为当前区块的hash(哈希值)
            uint percent = hash % 100;//因为hash值是随机的 所以将hash值进行取余
            if(percent < 20) percent = 20; //分到的当前红包总金额比例不会小于20
            if(percent > 80) percent = 80;
            uint balance = getBalance(); //当前余额,因之前返回的tuhao的余额  所以无法正常运行程序!
            who.transfer(balance * percent / 100);
            return true;
        }
        return false;
    }
    function kill() public {
        if(msg.sender == tuhao) {
            selfdestruct(tuhao);
        }
    }
}
    block.blockhash(block.number)
    /*此函数返回了当前链的hash值,但hash值为bytes32类型的数值,所以用uint类型进行强制转换,但最终并没有给hash变量进行赋值。
    原因猜测有可能javascript vm并没有真正产生一个区块的hash值。猜测二为可能bytes32强转uint类型是出现了问题,随后安装了ganache进行测试第一种猜测。*/

案例:赌大小

pragma solidity ^0.4.20;
contract Bet{
    address owner;
    struct Player {//结构体
        address addr;
        uint money;
    }
    Player[] inBig;     //定义变量
    Player[] inSmall;
    uint blockNumber;
    uint totalBig;
    uint totalSmall;
    function Bet() public{ //构造函数
        owner = msg.sender;
        blockNumber = block.number;
        totalSmall = 0;
        totalBig = 0;
    }
    function getBalance() public view returns (uint) { //查看合约余额
        return address(this).balance;
    }
    function getBlockNumber() public view returns (uint, uint) {//查看现在距离新生成的区块的距离(下注时间)
        return (blockNumber, block.number);
    }
    function chipin(bool big) payable public returns (bool) {
        //投钱方法,当投的钱是0的时踢出,不是0的时候可以为奖池增加值。
        Player memory player = Player(msg.sender, msg.value);
        if(player.money == 0)
            return false;
        if (big) {
            inBig.push(player);
            totalBig += player.money;
        }
        else {
            inSmall.push(player);
            totalSmall += player.money;
        }
        return true;
    }
    function open() payable public returns (bool) {
    //开盘
        if(block.number < 2 + blockNumber) {
            return false; // 如果调用此函数时并没有超过下注时间就会退出
        }
        if(totalSmall == 0 || totalBig == 0) {
            return false;
        }
        uint hash = uint(block.blockhash(block.number-1));
        uint points = hash % 19; //使hash值随机到1-18
        uint count;
        uint i;
        Player memory player;
        if(points < 9) { // small win
            count = inSmall.length;
            for(i=0; i<count; ++i) {
                player = inSmall[i];
                player.addr.transfer(totalBig * player.money / totalSmall +     player.money
            }   
        }
        else { // big win
            count = inBig.length;
            for(i=0; i<count; ++i) {
                player = inBig[i];
                player.addr.transfer(totalSmall * player.money / totalBig + player.money
            }
        }
        return true;
    }
    function kill() public {
        if(msg.sender == owner) {
            selfdestruct(owner);
        }
    }
}

这个案例的赌博规则有些简陋,但它的确实现了一个赌大小的合约,并且可以通过返回钱的函数进行抽成,但还是有很多的漏洞,例如kill合约创建者在开没开盘的情况下就能卷了钱跑了等小漏洞外还是让我学习了很多。


猜你喜欢

转载自www.cnblogs.com/tokenpai/p/9075190.html