程序员的自我救赎---12.2.2: 虚拟币交易平台(区块链) 中 【开发交易所】

《前言》

(一) Winner2.0 框架基础分析

(二)PLSQL报表系统

(三)SSO单点登录

(四) 短信中心与消息中心

(五)钱包系统

(六)GPU支付中心

(七)权限系统

(八)监控系统

(九)会员中心

(十) APP版本控制系统

(十一)Winner前端框架与RPC接口规范讲解

(十二)上层应用案例

(十三)总结

 

 

虚拟币交易平台(区块链) 中 【开发交易所】

 

对于,如果没有看上一篇文章的,建议先看一下上一篇文章了解如何发行一个区块链代币: 12.2.1: 虚拟币交易平台(区块链) 上【发行区块链代币】

 

首先我们要知道一个概念,虽然区块链是去中心化的,但是交易所却是中心化的。这也是为什么区块链技术被吹捧的那么厉害,却还是又发生那么多比特币、莱特币被盗事件。

在我们国家,去年(2017年)9月4号之前是没有明确的法律法规说不允许做ICO,也没有明确指出不允许做区块链代币交易所。 直到去年9月4号七部委联合发文,比特币、莱特币等虚拟币也应声降价,之后国内所有交易所基本都关了。

 

这里我引用一下百度上的解释:

 

公告指出,代币发行融资中使用的代币或“虚拟货币”不由货币当局发行,不具有法偿性与强制性等货币属性,不具有与货币等同的法律地位,不能也不应作为货币在市场上流通使用。

公告中表明:任何组织和个人不得非法从事代币发行融资活动,各金融机构和非银行支付机构不得开展与代币发行融资交易相关的业务。

 

 

我们要知道,比特币、莱特币各种代币并不等于区块链,所以各国在法律法规对于比特币和区块是两种态度,一方面打压比特币、莱特币这种代币,一方面又支持区块链技术的发展。

 

这里我也呼吁一下,希望大家不要去从事ICO非法融资,这种钱说不定有命赚,没命花。

 

===================================================华丽的分割线=======================================

 

回到正题,我们知道区块链,是通过记账来确认交易,而记账是记载在区块上。拿比特币来说每10分钟才出一个区块6个区块才确认一笔交易,这个过程是非常慢的。

所以虽然叫"比特币" 它却没有像我们平时网银转账那样的及时性。 这就衍生出了交易所,而交易所是中心化的,也就是服务端的数据库操作。

 

(现在有人研究去中心化的交易所,但是目前还没有很好解决各种区块链之间转账,所以去中心化的交易所目前还没有落地)

 

说道这里就好做,网站这种东西,我们平时真的是做太多了。说做网站,肯定先从数据库说起,因为我们的项目基于Winner2.0 框架,所以这里我们会省去很多环节,比如用户,权限等。不清楚的就看我前面的博客吧。

 

 

 

 

 

 

 

 

 

 ==========================================华丽的分割线==============================================================

 

最重要的就以上五张表了,我们来简单分析一下这五张表, 我们先看看前端的UI界面图:

 

 

 

 

 这样就一目了然知道各个表是干什么用的:

 

 

数字货币表:存储当前平台可以交易的数字代币,就是左上角的“比特币”,“莱特币”

货币动态表:保存该数字代币的价格浮动信息,比如比特币的今日最高价,价格走势图。

委托交易表:简单来说就是我们的挂单信息表,像“我的挂单”,还有右侧的委托信息,都在张表。

撮合信息表:撮合简单来说就是比如有人出10块卖,有人出100块买,本身价格是不对应的,但是我们认定出100块的人更愿意出10块买,所以我们促成他们交易。

                     最终他们会在撮合机制下,以10块的价格达成交易。 而撮合信息表本质来说就是“成交信息表”,比如左侧的成交记录。

 

 

 

==========================================================华丽的分割线================================================

 

由于上一篇文章 【发行区块链代币】 这篇文章很多人说我实在写的太长了。

 

所以今天这一篇我们直接简单粗暴一点。看完了数据库核心的四张表,我来看看核心的代码。

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Winner.Balance.Facade;
using Winner.Balance.GlobalCurrency;
using Winner.DCTS.DataAccess;
using Winner.DCTS.Entities;
using Winner.DCTS.Entities.enums;
using Winner.Framework.Core.Facade;
using Winner.Framework.Utils;

namespace Winner.DCTS.Facade
{
    public class MatchTransfer : FacadeBase
    {
        private eBankTransaction EBankTransaction { get; set; }
        private Tdct_Match daMatch { get; set; }

        public bool DoTransfer(Tdct_Match match)
        {
            daMatch = match;
            
            //开启事务
            BeginTransaction();

            //关联事务
            EBankTransaction = Transfer.GeteBankTransaction(); 

            //出售者把币转到购买者
            if (!SellToBuy())
            {
                Rollback(); //回滚事务

                UpdateFail(this.PromptInfo.MessageStack); 
                return false;
            }
            //购买者把钱转到出售者 + 手续费
            if (!BuyToSell())
            {
                Rollback();
                UpdateFail(this.PromptInfo.MessageStack);
                return false;
            }
            daMatch.TransferId = this.EBankTransaction;

            //撮合成功时修改撮合信息表状态
            if (!UpdateSuccess())
            {
                Rollback();
                return false;
            }

            //解除代币以及人名币锁定
            if (!UnFreeze())
            {
                Rollback();
                return false;
            }

           //同步代币动态交易信息
            if (!SyncDynamice())
            {
                Rollback();
                return false;
            }
            Commit();
            return true;
        }

        //出售者把币转到购买者
        private bool SellToBuy()
        {
            BeginTransaction();
            Currency currency = new Currency(CurrencyType.RMB, daMatch.BuyCount);
            UserPurse sellPurse = UserPurseProvider.Get(daMatch.SellUserId, daMatch.SellCurrency);
            UserPurse buyPurse = UserPurseProvider.Get(daMatch.BuyUserId, daMatch.SellCurrency);
            Transfer transfer = new Transfer(EBankTransaction);
            transfer.ReferenceTransactionFrom(this.Transaction);
            //如果买和卖都是同一个人则需要用转到系统用户再转入
            if (daMatch.SellUserId == daMatch.BuyUserId)
            {
                //系统用户钱包
                UserPurse transitPurse = UserPurseProvider.Get(AppConfig.TransitUserId, daMatch.SellCurrency);
                if (!transfer.DoTransferAndUnFreeze(sellPurse, transitPurse, currency, (int)TransferReson.出售者转入购买者, "出售货币中转出账", daMatch.SellFreezeId, "购买货币中转入账"))
                {
                    Rollback();
                    Alert("出售者转中转钱包失败!", transfer.PromptInfo);
                    return false;
                }
                if (!transfer.DoTransfer(transitPurse, buyPurse, currency, (int)TransferReson.出售者转入购买者, "出售货币中转出账", "购买货币中转入账"))
                {
                    Rollback();
                    Alert("中转者转购买者失败!", transfer.PromptInfo);
                    return false;
                }
            }
            else
            {
                if (!transfer.DoTransferAndUnFreeze(sellPurse, buyPurse, currency, (int)TransferReson.出售者转入购买者, "出售货币出账", daMatch.SellFreezeId, "购买货币入账"))
                {
                    Rollback();
                    Alert("出售者转购买者失败!", transfer.PromptInfo);
                    return false;
                }
            }
            Commit();
            return true;
        }


        //购买者把钱转到出售者 + 手续费
        private bool BuyToSell()
        {
            BeginTransaction();
            Currency currency = new Currency(CurrencyType.RMB, daMatch.Amount);
            UserPurse buyPurse = UserPurseProvider.Get(daMatch.BuyUserId, daMatch.BuyCurrency);
            UserPurse sellPurse = UserPurseProvider.Get(daMatch.SellUserId, daMatch.BuyCurrency);
            //收取手续费

            Transfer transfer = new Transfer(EBankTransaction);
            transfer.ReferenceTransactionFrom(this.Transaction);
            //如果买和卖都是同一个人则需要用转到系统用户再转入
            if (daMatch.BuyUserId == daMatch.SellUserId)
            {
                UserPurse transitPurse = UserPurseProvider.Get(AppConfig.TransitUserId, daMatch.BuyCurrency);
                if (!transfer.DoTransferAndUnFreeze(buyPurse, transitPurse, currency, (int)TransferReson.购买者转入出售者, "购买货币中转付款", daMatch.BuyFreezeId, "出售货币中转入账"))
                {
                    Rollback();
                    Alert("购买者转中转者失败!", transfer.PromptInfo);
                    return false;
                }
                if (!transfer.DoTransfer(transitPurse, sellPurse, currency, (int)TransferReson.购买者转入出售者, "购买货币中转付款", "出售货币中转入账"))
                {
                    Rollback();
                    Alert("中转者转出售者失败!", transfer.PromptInfo);
                    return false;
                }
            }
            else
            {
                if (!transfer.DoTransferAndUnFreeze(buyPurse, sellPurse, currency, (int)TransferReson.购买者转入出售者, "购买货币付款", daMatch.BuyFreezeId, "出售货币入账"))
                {
                    Rollback();
                    Alert("购买者转出售者失败!", transfer.PromptInfo);
                    return false;
                }
            }

            if (daMatch.Fee <= 0)
            {
                Commit();
                return true;
            }
            UserPurse feePurse = UserPurseProvider.Get(AppConfig.SystemUserId, daMatch.BuyCurrency);
            Currency feeCurrency = new Currency(feePurse.CurrencyType, daMatch.Fee);
            if (!transfer.DoTransfer(sellPurse, feePurse, feeCurrency, (int)TransferReson.收取出售者手续费, "收取出售者手续费"))
            {
                Rollback();
                Alert("收取出售者手续费失败!", transfer.PromptInfo);
                return false;
            }
            Commit();
            return true;
        }

        //修改撮合成功信息
        private bool UpdateSuccess()
        {
            daMatch.ReferenceTransactionFrom(this.Transaction);
            if (!daMatch.UpdateTransferSuccess(daMatch.MatchId, daMatch.TransferId.Value))
            {
                Alert("修改撮合历史成功时发现失败", daMatch.PromptInfo);
                return false;
            }
            return true;
        }


        //修改撮合失败信息
        private bool UpdateFail(string remarks)
        {
            Tdct_Match match = new Tdct_Match();
            if (!daMatch.UpdateTransferFail(daMatch.MatchId, remarks))
            {
                Alert("修改撮合历史成功时发现失败", daMatch.PromptInfo);
                return false;
            }
            return true;
        }


        //解除挂单的代币锁定
        public bool UnFreeze()
        {
            Tdct_EntrustCollection daEntrustColl = new Tdct_EntrustCollection();
            daEntrustColl.ReferenceTransactionFrom(this.Transaction);
            daEntrustColl.ListWaitRevokeRedundant(daMatch.SellEntrust, daMatch.BuyEntrust);
            Log.Info("解冻冗余[{0}笔]:", daEntrustColl.Count);
            if (daEntrustColl.Count <= 0)
            {
                return true;
            }
            foreach (Tdct_Entrust item in daEntrustColl)
            {
                Log.Info("[{0}]解冻就绪", item.Id);
                decimal amount = item.EAmount - item.TAmount;
                Currency currency = new Currency(CurrencyType.RMB, amount);
                Log.Info("[{0}]委托剩余解冻{1}金额", item.Id, amount);
                UserPurse userPurse = UserPurseProvider.Get(item.UserId, item.TCurrency);
                userPurse.ReferenceTransactionFrom(this.Transaction);
                if (!userPurse.UnFreeze(item.FreezeId, currency))
                {
                    Alert(userPurse.PromptInfo);
                    Log.Info("[{0}]解冻失败:{1}", item.Id, userPurse.PromptInfo.MessageStack);
                    return false;
                }
                Log.Info("[{0}]解冻成功", item.Id);
            }
            return true;
        }


        //同步代币动态信息
        private bool SyncDynamice()
        {
            Tdct_Daily_Dynamics daDynamice = new Tdct_Daily_Dynamics();
            daDynamice.ReferenceTransactionFrom(this.Transaction);
            if (daDynamice.SelectByDate(daMatch.SellCurrency, daMatch.BuyCurrency))
            {
                if (!daDynamice.UpdateNewSycn(daDynamice.Id, daMatch.Price, daMatch.BuyCount))
                {
                    Alert("同步每日动态失败");
                    return false;
                }
                return true;
            }
            daDynamice.BuyCurrencyId = daMatch.BuyCurrency;
            daDynamice.SellCurrencyId = daMatch.SellCurrency;
            daDynamice.LastTime = DateTime.Now;
            daDynamice.MaxPrice = daMatch.Price;
            daDynamice.MinPrice = daMatch.Price;
            daDynamice.NewPrice = daMatch.Price;
            daDynamice.StartPrice = daMatch.Price;
            daDynamice.TCount = daMatch.BuyCount;
            if (!daDynamice.Insert())
            {
                Alert("保存每日动态数据失败!", daDynamice.PromptInfo);
                return false;
            }
            return true;
        }
    }
}

 



上面的代码我基本上都加了注释,基本上能理解撮合交易的概念,配合我提供的这段代码以及数据库设计,就对于开发代币交易所的基本没有问题。

前端有个价格是实时动态的,如果技术水平还的话可以做个实时推送,如果觉得麻烦就做个定时器3秒轮训一次也可以。

 

======================================================华丽的分割线=======================================================

 

再多说几句,区块链之所以那么火热是在于它的技术性特,比如"去中心化"  可以帮助人们解除中心存储的信任问题,“UXTO”机制可以保证每一笔钱都能查的清清楚楚,“不可修改” 的特性可以保证数据的唯一性和一致性。

本身比特币,只是在我们每个为什么要去同步区块?同步区块以及挖矿(记账)我有什么好处?这时就给予了比特币的奖励!俗气一点说,比特币就是这个用途,当然我们可以高尚去说他解决了 “货币超发”,“通货膨胀”,“中心化不可信任”等问题。

 

现在国家基本上是不让做交易所了,所以去年底所有交易所也纷纷清退,关停了。这也让我们更清晰的去看待“区块链”技术,而不是只有“炒币”。

 

不可否认的是,肯定还有很多币的交易所在见不得光的运作着,我觉得就是早期在比特币和ICO来临的时候,没有圈到钱,并且有着一种“不甘心”的心态在执着。

如果只是去发一个没有技术含量的“空气币” 然后借着区块链的名头“割韭菜”,这其实就涉嫌"非法吸收公众存款"的罪名。钱不会凭空产生,也不会凭空消失,有人赚钱就注定有人在亏钱。

 

“空气币”本身不具备任何价值,只有将区块链技术应用到生活,区块链对应的代币才有价值。

 

就写到这吧,下一篇文章我将会回到“以太坊”的区块链技术,讲解如何将“.net” 技术以及C# 这们技术语言与“以太坊”区块链相结合。(C# 在移动互联网时代没落,希望在区块链的风口上能再次崛起!)

 

如果你觉得这篇文章对你有帮助,请捐助:

 

                                                                                                               

 

 

有兴趣一起探讨Winner2.0框架的可以加我们QQ群:261083244。或者扫描左侧二维码加群。

 

 

 

 

 

posted @ 2018-03-07 18:06  Near_wen  阅读(2551)  评论(5编辑  收藏  举报