去中心化交易合约--第一版

现在去中心化的交易越来越火,去中心化交易把卖家和买家之间,交易执行的过程写到智能合约里,没有人能够篡改这个合约,完全避开了中心化交易所的控制,使交易更加透明,自由。因此先写了一个简单的去中心交易合约,具体代码如下:

pragma solidity >=0.4.22 <0.7.0;
/**
 * 交易合约
 * 每个价格只能有1个人
 * 如果是买代币,输入价格和数量,并转入基础币
 * 如果是卖代币,输入价格和数量,并转入代币
 */
contract Trade {
    address owner = msg.sender; //保存合约创建人
    mapping(uint => order) public buyList;//买单列表,key为档位,order为下单相关信息
    mapping(uint => order) public sellList;//卖单列表,key为档位,order为下单相关信息
    bool  isAddBuyList;//是否加入买单队列
    bool  isAddSellList;//是否加入卖单队列
    uint  assertId;//需要交易的币种的资产id
    bool  isInit;//是否初始化

    struct order{
        uint price; //下单价格
        uint amount; //下单数量
        address addr; //下单人
    }
    order buyRemove;//需要移除买队列的订单
    order sellRemove;//需要移除卖队列的订单
    /**
    * 初始化函数
    * _assetId:资产id
    */
    function init(uint _assetId) public{
        require(owner==msg.sender);//必须为合约所有者
        require(isInit==false);//必须没有初始化过
        isInit=true;//设置初始化为true
        assertId=_assetId;
    }

    // 获取买单
    function getBuyList(uint num) public returns (uint,uint){
        return (buyList[num].price,buyList[num].amount);
    }
    // 获取卖单
    function getSellList(uint num) public returns (uint,uint){
        return (sellList[num].price,sellList[num].amount);
    }

    // 撮合
    function matchTrade() internal{
        for (uint num=0;num<10;num++){
            // 获取买的价格
            uint buyPrice=buyList[0].price;
            uint buyAmount=buyList[0].amount;
            uint sellPrice=sellList[0].price;
            uint sellAmount=sellList[0].amount;
            bool isTrade;//是否成交

            if(sellPrice==0){
                return;
            }
            if (buyPrice==0){
                return;
            }
            //如果买价格大于卖价格,则成交,撮合
            if (buyPrice>=sellPrice){
                isTrade=true;
                //最终成交的数量
                uint sendAmount;
                // 如果买单数量大于卖单数量
                if (buyAmount>=sellAmount){
                    //统一按照买单价格转账
                    //更新买单数量和卖单数量
                    buyList[0].amount=buyAmount-sellAmount;
                    sellList[0].amount=0;
                    sendAmount=sellAmount;

                }else{
                    //更新买单数量和卖单数量
                    buyList[0].amount=0;
                    sellList[0].amount=sellAmount-buyAmount;
                    sendAmount=buyAmount;
                }

                //给买方转代币
                buyList[0].addr.transfer(assertId,sendAmount);
                //给卖方转基础币
                uint c=buyPrice*sendAmount;
                sellList[0].addr.transfer(0,c);
            }

            // 只有成交了才对买卖盘进行整理
            if (isTrade==true){
                // 对买盘进行整理
                // 如果买1的数量为0,则将后面的全部往前挪
                if (buyList[0].amount==0){
                    for (uint ii=0;ii<9;ii++){
                        buyList[ii]=buyList[ii+1];
                    }
                    // 将最后一个数据删除
                    delete buyList[9];
                }
                // 对卖盘进行整理
                if (sellList[0].amount==0){
                    for (uint j=0;j<9;j++){
                        sellList[j]=sellList[j+1];
                    }
                    // 将最后一个数据删除
                    delete sellList[9];
                }
            }
        }
    }
    //买操作
    function buy(uint price,uint amount) public payable{
        //转入的金额需要大于等于价格*数量
        require(price*amount<=msg.value);
        //转账的资产id必须正确,买单必须是主资产
        require(msg.assetid==0);
        isAddBuyList=false;
        //先判断价格在哪个范围
        //如果价格大于买1,则买1~买9一次往后挪,新的数据为买1
        for (uint j=0;j<10;j++){
            // 如果输入的价格大于当前档位,则当前档位后移
             if (buyList[j].price<price){
                //将需要移除的数据保存
                buyRemove=buyList[9];
                //加入买单队列,将标志设置为true
                isAddBuyList=true;
                // 将正确价格后面的数据后移
                for(uint i=9;i>j;i--){
                    buyList[i]=buyList[i-1];
                }
                //将新的订单赋值到对应位置
                buyList[j].price=price;
                buyList[j].amount=amount;
                buyList[j].addr=msg.sender;
                //跳出循环
                break;
             }
             //如果存在相同价格,则直接退币
             if(buyList[j].price==price){
                //msg.sender.transfer(0,msg.value);
                break;
             }
        }
        //如果没有加入买单队列,则把钱退回
        if (isAddBuyList==false){
            msg.sender.transfer(0,msg.value);
        }else{
            if (buyRemove.amount!=0){
                //如果有人加入了队列,需要把原来的人的钱返回
                buyRemove.addr.transfer(0,buyRemove.price*buyRemove.amount);
            }
            // 有人加入队列才调用撮合
            matchTrade();
        }

    }

    //卖操作
    function sell(uint price,uint amount) public payable{
        //转入资产必须是当前合约交易的资产
        require(assertId==msg.assetid);
        require(amount==msg.value);//必须足额转入
        isAddSellList=false;
        //先判断价格在哪个范围
        //如果价格小于卖1,则卖1~卖9一次往后挪,新的数据为买1
        for (uint j=0;j<10;j++){
            //当前档位没有数据
            if (sellList[j].price==0){
                //将需要移除的数据保存
                sellRemove=sellList[9];
                //加入卖单队列,将标志设置为true
                isAddSellList=true;
                //将新的订单赋值到对应位置
                sellList[j].price=price;
                sellList[j].amount=amount;
                sellList[j].addr=msg.sender;
                //跳出循环
                break;
            }else{
                 if(sellList[j].price>price){
                    //将需要移除的数据保存
                    sellRemove=sellList[9];
                    //加入卖单队列,将标志设置为true
                    isAddSellList=true;
                    // 将正确价格后面的数据后移
                    for(uint i=9;i>j;i--){
                        sellList[i]=sellList[i-1];
                    }
                    //将新的订单赋值到对应位置
                    sellList[j].price=price;
                    sellList[j].amount=amount;
                    sellList[j].addr=msg.sender;
                    //跳出循环
                    break;
                 }
                 //如果存在相同价格,则直接退币
                 if(sellList[j].price==price){
                    //msg.sender.transfer(assertId,msg.value);
                    break;
                 }
            }
        }
        //如果没有加入买单队列,则把钱退回
        if (isAddSellList==false){
            msg.sender.transfer(assertId,msg.value);
        }else{
            if (sellRemove.amount!=0){
                //如果有人加入了队列,需要把原来的人的钱返回
                sellRemove.addr.transfer(assertId,sellRemove.amount);
            }
            // 有人加入队列才调用撮合
            matchTrade();
        }
    }
    /**
    * 功能:撤单
    * orderType:订单类型,buy,sell
    * price:价格
    */
    function cancel(string orderType,uint price) public{
        //如果撤销买单
        if(orderType=="buy"){
            for (uint i=0;i<10;i++){
                //用户相同,并且价格相同
                if((buyList[i].addr==msg.sender) && (buyList[i].price==price)){
                    //将剩余的钱返回
                    msg.sender.transfer(0,buyList[i].price*buyList[i].amount);
                    //将后面的数据往前移
                    for (uint ii=i;ii<9;ii++){
                        buyList[ii]=buyList[ii+1];
                    }
                    // 将最后一个数据删除
                    delete buyList[9];
                    break;
                }
            }
        }else{
            //如果撤销卖单
            if(orderType=="sell"){
                for (uint j=0;j<10;j++){
                    //先确定用户是否相同
                    if((sellList[j].addr==msg.sender) && (sellList[j].price==price)){
                        //将剩余的钱返回
                        msg.sender.transfer(assertId,sellList[j].amount);
                        //将后面的数据往前移
                        for (uint jj=j;jj<9;jj++){
                            sellList[jj]=sellList[jj+1];
                        }
                        // 将最后一个数据删除
                        delete sellList[9];
                        break;
                    }
                }
            }
        }
    }
}

代码中有详细的注释,在此就不再一一的讲解代码,大家自行阅读就可以。有不明白的地方欢迎留言。
这里有几个问题不太合理:
1.每个档位只能有1个订单,这在显示中是不可能的
2.买盘和卖盘最多只能有10个档位,如果想再次下单,则不能成功,或者是把原来的订单挤掉,这个也不太合理

因此在下个版本中,会想办法修复这些问题。
起始这里面的关键是撮合,如何更高效的撮合,花费更小的gas。这将是后期研究的重点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值