Commit ef710316 authored by harrylee's avatar harrylee Committed by vipwzw

add exchange dapp

parent f3fe57bb
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
#!/bin/sh
# 官方ci集成脚本
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${1}/$strapp"
#FLAG=$2
mkdir -p "${OUT_DIR}"
cp ./build/* "${OUT_DIR}"
/*Package commands implement dapp client commands*/
package commands
import (
"github.com/spf13/cobra"
)
/*
* 实现合约对应客户端
*/
// Cmd exchange client command
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exchange",
Short: "exchange command",
Args: cobra.MinimumNArgs(1),
}
cmd.AddCommand(
//add sub command
)
return cmd
}
package executor
import (
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* 执行器相关定义
* 重载基类相关接口
*/
var (
//日志
elog = log.New("module", "exchange.executor")
)
var driverName = exchangetypes.ExchangeX
// Init register dapp
func Init(name string, cfg *types.Chain33Config, sub []byte) {
drivers.Register(cfg, GetName(), newExchange, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// InitExecType Init Exec Type
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&exchange{}))
}
type exchange struct {
drivers.DriverBase
}
func newExchange() drivers.Driver {
t := &exchange{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
return t
}
// GetName get driver name
func GetName() string {
return newExchange().GetName()
}
func (e *exchange) GetDriverName() string {
return driverName
}
// CheckTx 实现自定义检验交易接口,供框架调用
func (e *exchange) CheckTx(tx *types.Transaction, index int) error {
//发送交易的时候就检查payload,做严格的参数检查
var exchange exchangetypes.ExchangeAction
types.Decode(tx.GetPayload(), &exchange)
if exchange.Ty == exchangetypes.TyLimitOrderAction {
limitOrder := exchange.GetLimitOrder()
left := limitOrder.GetLeftAsset()
right := limitOrder.GetRightAsset()
price := Truncate(limitOrder.GetPrice())
amount := limitOrder.GetAmount()
op := limitOrder.GetOp()
if !CheckExchangeAsset(left, right) {
return exchangetypes.ErrAsset
}
if !CheckPrice(price) {
return exchangetypes.ErrAssetPrice
}
if !types.CheckAmount(amount) {
return exchangetypes.ErrAssetAmount
}
if !CheckOp(op) {
return exchangetypes.ErrAssetOp
}
}
return nil
}
// GetPayloadValue get payload value
func (e *exchange) GetPayloadValue() types.Message {
return &exchangetypes.ExchangeAction{}
}
package executor
import (
"testing"
)
func TestTruncate(t *testing.T) {
a:=float32(1.00000212000000000001)
b:=float32(0.34567)
c:=float32(1234)
t.Log(Truncate(a))
t.Log(Truncate(b))
t.Log(Truncate(c))
}
\ No newline at end of file
package executor
import (
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
"github.com/gogo/protobuf/proto"
"math"
)
// Action action struct
type Action struct {
statedb dbm.KV
txhash []byte
fromaddr string
blocktime int64
height int64
execaddr string
localDB dbm.Lister
index int
api client.QueueProtocolAPI
}
func NewAction(e *exchange, tx *types.Transaction, index int) *Action {
hash := tx.Hash()
fromaddr := tx.From()
return &Action{e.GetStateDB(), hash, fromaddr,
e.GetBlockTime(), e.GetHeight(), dapp.ExecAddress(string(tx.Execer)), e.GetLocalDB(), index, e.GetAPI()}
}
//GetIndex get index
func (a *Action) GetIndex() int64 {
return a.height*types.MaxTxsPerBlock + int64(a.index)
}
//GetKVSet get kv set
func (a *Action) GetKVSet(order *et.Order) (kvset []*types.KeyValue) {
kvset = append(kvset, &types.KeyValue{Key: calcOrderKey(order.OrderID), Value: types.Encode(order)})
return kvset
}
//缓存
func (a *Action) updateStateDBCache(order *et.Order) {
a.statedb.Set(calcOrderKey(order.OrderID), types.Encode(order))
}
//反转
func (a *Action) OpSwap(op int32) int32 {
if op == et.OpBuy {
return et.OpSell
} else {
return et.OpBuy
}
}
//计算实际花费
func (a *Action) calcActualCost(op int32, amount int64, price float32) int64 {
if op == et.OpBuy {
return int64(float32(amount) * Truncate(price))
}
return amount
}
//price 精度允许范围小数点后面7位数,整数是1e8
func CheckPrice(price float32) bool {
if (Truncate(price) > 1e8) || (Truncate(price)*float32(1e8) <= 0) {
return false
}
return true
}
func CheckOp(op int32) bool {
if op == et.OpBuy || op == et.OpSell {
return true
}
return false
}
func CheckCount(count int32) bool {
if count > 20 {
return false
}
return true
}
func CheckDirection(direction int32) bool {
if direction == et.ListASC || direction == et.ListDESC {
return true
}
return false
}
func CheckStatus(status int32) bool {
if status == et.Ordered || status == et.Completed || status == et.Revoked {
return true
}
return false
}
//检查交易得资产是否合法
func CheckExchangeAsset(left, right *et.Asset) bool {
if left.Execer == "" || left.Symbol == "" || right.Execer == "" || right.Symbol == "" {
return false
}
if (left.Execer == "coins" && right.Execer == "coins") || (left.Symbol == right.Symbol) {
return false
}
return true
}
func (a *Action) LimitOrder(payload *et.LimitOrder) (*types.Receipt, error) {
leftAsset := payload.GetLeftAsset()
rightAsset := payload.GetRightAsset()
//TODO 参数要合法,必须有严格的校验,后面统一加入到checkTx里面
//coins执行器下面只有bty
if !CheckExchangeAsset(leftAsset, rightAsset) {
return nil, et.ErrAsset
}
if !types.CheckAmount(payload.GetAmount()) {
return nil, et.ErrAssetAmount
}
if CheckPrice(payload.GetPrice()) {
return nil, et.ErrAssetPrice
}
if !CheckOp(payload.GetOp()) {
return nil, et.ErrAssetOp
}
//TODO 这里symbol
cfg := a.api.GetConfig()
leftAssetDB, err := account.NewAccountDB(cfg, leftAsset.GetExecer(), leftAsset.GetSymbol(), a.statedb)
if err != nil {
return nil, err
}
rightAssetDB, err := account.NewAccountDB(cfg, rightAsset.GetExecer(), rightAsset.GetSymbol(), a.statedb)
if err != nil {
return nil, err
}
//先检查账户余额
if payload.GetOp() == et.OpBuy {
amount := int64(float32(payload.GetAmount()) * Truncate(payload.GetPrice()))
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Balance < amount {
elog.Error("LimitOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
return nil, et.ErrAssetBalance
}
return a.matchLimitOrder(payload, leftAssetDB, rightAssetDB)
}
if payload.GetOp() == et.OpSell {
amount := payload.GetAmount()
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Balance < amount {
elog.Error("LimitOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
return nil, et.ErrAssetBalance
}
return a.matchLimitOrder(payload, leftAssetDB, rightAssetDB)
}
return nil, fmt.Errorf("unknow op")
}
func (a *Action) RevokeOrder(payload *et.RevokeOrder) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kvs []*types.KeyValue
order, err := findOrderByOrderID(a.statedb, payload.GetOrderID())
if err != nil {
return nil, err
}
if order.Addr != a.fromaddr {
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status, "err", et.ErrAddr.Error())
return nil, et.ErrAddr
}
if order.Status == et.Completed || order.Status == et.Revoked {
elog.Error("RevokeOrder.OrderCheck", "addr", a.fromaddr, "order.addr", order.Addr, "order.status", order.Status, "err", et.ErrOrderSatus.Error())
return nil, et.ErrOrderSatus
}
leftAsset := order.GetLimitOrder().GetLeftAsset()
rightAsset := order.GetLimitOrder().GetRightAsset()
price := order.GetLimitOrder().GetPrice()
balance := order.GetBalance()
cfg := a.api.GetConfig()
if order.GetLimitOrder().GetOp() == et.OpBuy {
rightAssetDB, err := account.NewAccountDB(cfg, rightAsset.GetExecer(), rightAsset.GetSymbol(), a.statedb)
if err != nil {
return nil, err
}
amount := int64(float32(balance) * price)
rightAccount := rightAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if rightAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
return nil, et.ErrAssetBalance
}
receipt, err := rightAssetDB.ExecActive(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
if order.GetLimitOrder().GetOp() == et.OpSell {
leftAssetDB, err := account.NewAccountDB(cfg, leftAsset.GetExecer(), leftAsset.GetSymbol(), a.statedb)
if err != nil {
return nil, err
}
amount := balance
leftAccount := leftAssetDB.LoadExecAccount(a.fromaddr, a.execaddr)
if leftAccount.Frozen < amount {
elog.Error("RevokeOrder.BalanceCheck", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", et.ErrAssetBalance.Error())
return nil, et.ErrAssetBalance
}
receipt, err := leftAssetDB.ExecActive(a.fromaddr, a.execaddr, amount)
if err != nil {
elog.Error("RevokeOrder.ExecActive", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", amount, "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
//更新order状态
order.Status = et.Revoked
order.UpdateTime = a.blocktime
kvs = append(kvs, a.GetKVSet(order)...)
re := &et.ReceiptExchange{
Order: order,
Index: a.GetIndex(),
}
receiptlog := &types.ReceiptLog{Ty: et.TyRevokeOrderLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
return receipts, nil
}
//撮合交易逻辑方法
func (a *Action) matchLimitOrder(payload *et.LimitOrder, leftAccountDB, rightAccountDB *account.DB) (*types.Receipt, error) {
var logs []*types.ReceiptLog
var kvs []*types.KeyValue
var index int64
or := &et.Order{
OrderID: common.ToHex(a.txhash),
Value: &et.Order_LimitOrder{payload},
Ty: et.TyLimitOrderAction,
Executed: 0,
Balance: payload.GetAmount(),
Status: et.Ordered,
Addr: a.fromaddr,
UpdateTime: a.blocktime,
Index: a.GetIndex(),
}
re := &et.ReceiptExchange{
Order: or,
Index: a.GetIndex(),
}
//按先进先出的原则进行撮合
//单笔交易最多撮合100笔历史订单,最大可撮合得深度,系统得自我防护
for i := 0; i < 20; i++ {
orderIDs, err := findOrderIDListByPrice(a.localDB, payload.GetLeftAsset(), payload.GetRightAsset(), payload.GetPrice(), a.OpSwap(payload.Op), et.ListASC, index)
if err == types.ErrNotFound {
break
}
if err != nil {
return nil, err
}
for _, orderID := range orderIDs {
matchorder, err := findOrderByOrderID(a.statedb, orderID.ID)
if err != nil {
elog.Warn("matchLimitOrder.findOrderByOrderID", "order", "err", err.Error())
continue
}
//同地址不能交易
if matchorder.Addr == a.fromaddr {
continue
}
//TODO 这里得逻辑是否需要调整?当匹配的单数过多,会导致receipt日志数量激增,理论上存在日志存储攻击,需要加下最大匹配深度,防止这种攻击发生
if matchorder.GetBalance() >= or.GetBalance() {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, or.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
// match receiptorder
matchorder.Balance = matchorder.GetBalance() - or.GetBalance()
matchorder.Executed = matchorder.Executed + or.GetBalance()
matchorder.Status = func(a, b int64) int32 {
if a > b {
return et.Ordered
} else {
return et.Completed
}
}(matchorder.GetBalance(), or.GetBalance())
a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Balance = 0
or.Executed = or.Executed + or.GetBalance()
or.Status = et.Completed
//update receipt order
re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder)
a.updateStateDBCache(or)
kvs = append(kvs, a.GetKVSet(or)...)
//statedb 更新
receiptlog := &types.ReceiptLog{Ty: et.TyLimitOrderLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
return receipts, nil
} else {
//转移冻结资产
receipt, err := leftAccountDB.ExecTransferFrozen(matchorder.Addr, a.fromaddr, a.execaddr, a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransferFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(matchorder.GetLimitOrder().Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
//将达成交易的相应资产结算
receipt, err = rightAccountDB.ExecTransfer(a.fromaddr, matchorder.Addr, a.execaddr, a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()))
if err != nil {
elog.Error("matchLimitOrder.ExecTransfer", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(payload.Op, matchorder.GetBalance(), payload.GetPrice()), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
// match receiptorder
matchorder.Balance = 0
matchorder.Executed = matchorder.Executed + matchorder.GetBalance()
matchorder.Status = et.Completed
a.updateStateDBCache(matchorder)
kvs = append(kvs, a.GetKVSet(matchorder)...)
or.Balance = or.Balance - matchorder.Balance
or.Executed = or.Executed + matchorder.Balance
or.Status = et.Ordered
re.Order = or
re.MatchOrders = append(re.MatchOrders, matchorder)
a.updateStateDBCache(or)
}
}
//查询数据不满足5条说明没有了,跳出循环
if len(orderIDs) < int(et.Count) {
break
}
index = orderIDs[len(orderIDs)-1].Index
}
//冻结剩余未成交的资金
if payload.Op == et.OpBuy {
receipt, err := rightAccountDB.ExecFrozen(a.fromaddr, a.execaddr, a.calcActualCost(et.OpBuy, or.Balance, payload.Price))
if err != nil {
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(et.OpBuy, or.Balance, payload.Price), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
if payload.Op == et.OpSell {
receipt, err := leftAccountDB.ExecFrozen(a.fromaddr, a.execaddr, a.calcActualCost(et.OpSell, or.Balance, payload.Price))
if err != nil {
elog.Error("LimitOrder.ExecFrozen", "addr", a.fromaddr, "execaddr", a.execaddr, "amount", a.calcActualCost(et.OpSell, or.Balance, payload.Price), "err", err.Error())
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
}
//更新order状态
kvs = append(kvs, a.GetKVSet(or)...)
receiptlog := &types.ReceiptLog{Ty: et.TyLimitOrderLog, Log: types.Encode(re)}
logs = append(logs, receiptlog)
receipts := &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}
return receipts, nil
}
func findOrderByOrderID(statedb dbm.KV, orderID string) (*et.Order, error) {
data, err := statedb.Get(calcOrderKey(orderID))
if err != nil {
elog.Error("findOrderByOrderID.Get", "orderID", orderID, "err", err.Error())
return nil, err
}
var order et.Order
err = types.Decode(data, &order)
if err != nil {
elog.Error("findOrderByOrderID.Decode", "orderID", orderID, "err", err.Error())
return nil, err
}
return &order, nil
}
func findOrderIDListByPrice(localdb dbm.Lister, left, right *et.Asset, price float32, op, direction int32, index int64) ([]*et.OrderID, error) {
prefix := calcMarketDepthOrderPrefix(left, right, op, price)
key := calcMarketDepthOrderKey(left, right, op, price, index)
var values [][]byte
var err error
if index == 0 { //第一次查询
values, err = localdb.List(prefix, nil, et.Count, direction)
} else {
values, err = localdb.List(prefix, key, et.Count, direction)
}
if err != nil {
return nil, err
}
var list []*et.OrderID
for _, value := range values {
var orderID et.OrderID
err := types.Decode(value, &orderID)
if err != nil {
elog.Warn("findOrderIDListByPrice.Decode", "orderID", "err", err.Error())
continue
}
list = append(list, &orderID)
}
return list, nil
}
//localdb查询
func findObject(localdb dbm.KVDB, key []byte, msg proto.Message) error {
value, err := localdb.Get(key)
if err != nil {
elog.Warn("findObject.Decode", "key", string(key), "err", err.Error())
return err
}
return types.Decode(value, msg)
}
//买单深度是按价格倒序,由高到低
func Direction(op int32) int32 {
if op == et.OpBuy {
return et.ListDESC
}
return et.ListASC
}
//这里price当作索引来用,首次查询不需要填值
func QueryMarketDepth(localdb dbm.Lister, left, right *et.Asset, op int32, price float32, count int32) (types.Message, error) {
prefix := calcMarketDepthPrefix(left, right, op)
key := calcMarketDepthKey(left, right, op, price)
var values [][]byte
var err error
if price == 0 { //第一次查询,方向卖单由低到高,买单由高到低
values, err = localdb.List(prefix, nil, count, Direction(op))
} else {
values, err = localdb.List(prefix, key, count, Direction(op))
}
if err != nil {
return nil, err
}
var list et.MarketDepthList
for _, value := range values {
var marketDept et.MarketDepth
err := types.Decode(value, &marketDept)
if err != nil {
elog.Warn("QueryMarketDepth.Decode", "marketDept", "err", err.Error())
continue
}
list.List = append(list.List, &marketDept)
}
return &list, nil
}
//QueryCompletedOrderList
func QueryCompletedOrderList(localdb dbm.Lister, statedb dbm.KV, left, right *et.Asset, index int64, count, direction int32) (types.Message, error) {
prefix := calcCompletedOrderPrefix(left, right)
key := calcCompletedOrderKey(left, right, index)
var values [][]byte
var err error
if index == 0 { //第一次查询,默认展示最新得成交记录
values, err = localdb.List(prefix, nil, count, direction)
} else {
values, err = localdb.List(prefix, key, count, direction)
}
if err != nil {
return nil, err
}
var list []*et.OrderID
for _, value := range values {
var orderID et.OrderID
err := types.Decode(value, &orderID)
if err != nil {
elog.Warn("QueryCompletedOrderList.Decode", "marketDept", "err", err.Error())
continue
}
list = append(list, &orderID)
}
var orderList et.OrderList
for _, orderID := range list {
order, err := findOrderByOrderID(statedb, orderID.ID)
if err != nil {
continue
}
//替换索引index
order.Index = orderID.Index
orderList.List = append(orderList.List, order)
}
return &orderList, nil
}
//QueryOrderList,默认展示最新的
func QueryOrderList(localdb dbm.Lister, statedb dbm.KV, addr string, status, count, direction int32, index int64) (types.Message, error) {
prefix := calcUserOrderIDPrefix(status, addr)
key := calcUserOrderIDKey(status, addr, index)
var values [][]byte
var err error
if index == 0 { //第一次查询,默认展示最新得成交记录
values, err = localdb.List(prefix, nil, count, direction)
} else {
values, err = localdb.List(prefix, key, count, direction)
}
if err != nil {
return nil, err
}
var list []*et.OrderID
for _, value := range values {
var orderID et.OrderID
err := types.Decode(value, &orderID)
if err != nil {
elog.Warn("QueryOrderList.Decode", "marketDept", "err", err.Error())
continue
}
list = append(list, &orderID)
}
var orderList et.OrderList
for _, orderID := range list {
order, err := findOrderByOrderID(statedb, orderID.ID)
if err != nil {
continue
}
//替换索引index
order.Index = orderID.Index
orderList.List = append(orderList.List, order)
}
return &orderList, nil
}
//截取小数点后7位
func Truncate(price float32) float32 {
return float32(math.Trunc(float64(1e8)*float64(price)) / float64(1e8))
}
package executor
import (
"github.com/33cn/chain33/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* 实现交易的链上执行接口
* 关键数据上链(statedb)并生成交易回执(log)
*/
func (e *exchange) Exec_LimitOrder(payload *exchangetypes.LimitOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (e *exchange) Exec_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
func (e *exchange) Exec_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, index int) (*types.Receipt, error) {
var receipt *types.Receipt
//implement code
return receipt, nil
}
package executor
import (
"github.com/33cn/chain33/types"
)
/*
* 实现区块回退时本地执行的数据清除
*/
// ExecDelLocal 回退自动删除,重写基类
func (e *exchange) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
kvs, err := e.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
package executor
import (
"github.com/33cn/chain33/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* 实现交易相关数据本地执行,数据不上链
* 非关键数据,本地存储(localDB), 用于辅助查询,效率高
*/
func (e *exchange) ExecLocal_LimitOrder(payload *exchangetypes.LimitOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
if receiptData.Ty == types.ExecOk {
for _, log := range receiptData.Logs {
switch log.Ty {
case exchangetypes.TyLimitOrderLog:
receipt := &exchangetypes.ReceiptExchange{}
if err := types.Decode(log.Log, receipt); err != nil {
return nil, err
}
kv := e.updateIndex(receipt)
dbSet.KV = append(dbSet.KV, kv...)
}
}
}
return e.addAutoRollBack(tx, dbSet.KV), nil
}
func (e *exchange) ExecLocal_MarketOrder(payload *exchangetypes.MarketOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return e.addAutoRollBack(tx, dbSet.KV), nil
}
func (e *exchange) ExecLocal_RevokeOrder(payload *exchangetypes.RevokeOrder, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
dbSet := &types.LocalDBSet{}
//implement code
return e.addAutoRollBack(tx, dbSet.KV), nil
}
//设置自动回滚
func (e *exchange) addAutoRollBack(tx *types.Transaction, kv []*types.KeyValue) *types.LocalDBSet {
dbSet := &types.LocalDBSet{}
dbSet.KV = e.AddRollbackKV(tx, tx.Execer, kv)
return dbSet
}
func (e *exchange) updateIndex(receipt *exchangetypes.ReceiptExchange) (kvs []*types.KeyValue) {
switch receipt.Order.Status {
case exchangetypes.Ordered:
left := receipt.GetOrder().GetLimitOrder().GetLeftAsset()
right := receipt.GetOrder().GetLimitOrder().GetRightAsset()
op := receipt.GetOrder().GetLimitOrder().GetOp()
price := receipt.GetOrder().GetLimitOrder().GetPrice()
oderID := receipt.GetOrder().OrderID
index := receipt.GetIndex()
addr := receipt.GetOrder().Addr
var markDepth exchangetypes.MarketDepth
err := findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, op, price), &markDepth)
if err == types.ErrNotFound {
markDepth.Price = price
markDepth.LeftAsset = left
markDepth.RightAsset = right
markDepth.Op = op
markDepth.Amount = receipt.Order.Balance
}
markDepth.Amount = markDepth.Amount + receipt.Order.Balance
//marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&markDepth)})
//orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, op, price, receipt.Index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
//addr orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
if len(receipt.MatchOrders) > 0 {
//撮合交易更新
var balance int64
for _, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil})
//更新状态为已完成,索引index,改为当前的index
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})})
//calcCompletedOrderKey
kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})})
}
if matchOrder.Status == exchangetypes.Ordered {
//只需统一更改市场深度状态,其他不需要处理
balance = balance + matchOrder.Balance
}
}
//更改市场深度
var matchDepth exchangetypes.MarketDepth
err = findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, OpSwap(op), price), &matchDepth)
if err == types.ErrNotFound {
matchDepth.Price = price
matchDepth.LeftAsset = left
matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance
}
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
//marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)})
}
return
case exchangetypes.Completed:
left := receipt.GetOrder().GetLimitOrder().GetLeftAsset()
right := receipt.GetOrder().GetLimitOrder().GetRightAsset()
op := receipt.GetOrder().GetLimitOrder().GetOp()
price := receipt.GetOrder().GetLimitOrder().GetPrice()
oderID := receipt.GetOrder().OrderID
index := receipt.GetIndex()
addr := receipt.GetOrder().Addr
//user orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
if len(receipt.MatchOrders) > 0 {
//撮合交易更新
var balance int64
for _, matchOrder := range receipt.MatchOrders {
if matchOrder.Status == exchangetypes.Completed {
// 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, matchOrder.GetLimitOrder().Op, price, matchOrder.Index), Value: nil})
//删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, matchOrder.Addr, matchOrder.Index), Value: nil})
//更新状态为已完成,更新索引
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Completed, matchOrder.Addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})})
//calcCompletedOrderKey
kvs = append(kvs, &types.KeyValue{Key: calcCompletedOrderKey(left, right, index), Value: types.Encode(&exchangetypes.OrderID{ID: matchOrder.OrderID, Index: index})})
}
if matchOrder.Status == exchangetypes.Ordered {
//只需统一更改市场深度状态,其他不需要处理
balance = balance + matchOrder.Balance
}
}
//更改match市场深度
var matchDepth exchangetypes.MarketDepth
err := findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, OpSwap(op), price), &matchDepth)
if err == types.ErrNotFound {
matchDepth.Price = price
matchDepth.LeftAsset = left
matchDepth.RightAsset = right
matchDepth.Op = OpSwap(op)
matchDepth.Amount = balance
}
matchDepth.Amount = matchDepth.Amount - receipt.Order.Executed
//marketDepth
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, OpSwap(op), price), Value: types.Encode(&matchDepth)})
}
return
case exchangetypes.Revoked:
//只有状态时ordered状态的订单才能被撤回
left := receipt.GetOrder().GetLimitOrder().GetLeftAsset()
right := receipt.GetOrder().GetLimitOrder().GetRightAsset()
op := receipt.GetOrder().GetLimitOrder().GetOp()
price := receipt.GetOrder().GetLimitOrder().GetPrice()
oderID := receipt.GetOrder().OrderID
index := receipt.GetIndex()
addr := receipt.GetOrder().Addr
var marketDepth exchangetypes.MarketDepth
err := findObject(e.GetLocalDB(), calcMarketDepthKey(left, right, op, price), &marketDepth)
if err == nil {
//marketDepth
marketDepth.Amount = marketDepth.Amount - receipt.GetOrder().Balance
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthKey(left, right, op, price), Value: types.Encode(&marketDepth)})
}
// 删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcMarketDepthOrderKey(left, right, op, price, receipt.GetOrder().Index), Value: nil})
//删除原有状态orderID
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Ordered, addr, receipt.GetOrder().Index), Value: nil})
//添加撤销的订单
kvs = append(kvs, &types.KeyValue{Key: calcUserOrderIDKey(exchangetypes.Revoked, addr, index), Value: types.Encode(&exchangetypes.OrderID{ID: oderID, Index: index})})
}
return
}
func OpSwap(op int32) int32 {
if op == exchangetypes.OpBuy {
return exchangetypes.OpSell
} else {
return exchangetypes.OpBuy
}
}
package executor
import (
"fmt"
"github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* 用户合约存取kv数据时,key值前缀需要满足一定规范
* 即key = keyPrefix + userKey
* 需要字段前缀查询时,使用’-‘作为分割符号
*/
var (
//KeyPrefixStateDB state db key必须前缀
KeyPrefixStateDB = "mavl-exchange-"
//KeyPrefixLocalDB local db的key必须前缀
KeyPrefixLocalDB = "LODB-exchange-"
)
//状态数据库中存储具体挂单信息
func calcOrderKey(orderID string) []byte {
key := fmt.Sprintf("%s"+"orderID:%s", KeyPrefixStateDB, orderID)
return []byte(key)
}
func calcMarketDepthPrefix(left, right *types.Asset, op int32) []byte {
key := fmt.Sprintf("%s"+"depth-%s-%s-%d:", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op)
return []byte(key)
}
//市场深度
func calcMarketDepthKey(left, right *types.Asset, op int32, price float32) []byte {
// 设置精度为1e8
key := fmt.Sprintf("%s"+"depth-%s-%s-%d:%016d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op, int64(Truncate(price)*float32(1e8)))
return []byte(key)
}
func calcMarketDepthOrderPrefix(left, right *types.Asset, op int32, price float32) []byte {
// 设置精度为1e8
key := fmt.Sprintf("%s"+"order-%s-%s-%d:%016d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op, int64(Truncate(price)*float32(1e8)))
return []byte(key)
}
// localdb中存储市场挂单ID
func calcMarketDepthOrderKey(left, right *types.Asset, op int32, price float32, index int64) []byte {
// 设置精度为1e8
key := fmt.Sprintf("%s"+"order-%s-%s-%d:%016d:%018d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), op, int64(Truncate(price)*float32(1e8)), index)
return []byte(key)
}
//最新已经成交的订单,这里状态固定都是完成状态,这个主要给外部使用,可以查询最新得成交信息
func calcCompletedOrderKey(left, right *types.Asset, index int64) []byte {
// 设置精度为1e8
key := fmt.Sprintf("%s"+"completed-%s-%s-%d:%018d", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), types.Completed, index)
return []byte(key)
}
func calcCompletedOrderPrefix(left, right *types.Asset) []byte {
// 设置精度为1e8
key := fmt.Sprintf("%s"+"completed-%s-%s-%d:", KeyPrefixLocalDB, left.GetSymbol(), right.GetSymbol(), types.Completed)
return []byte(key)
}
//根据地址和订单状态,去查询订单列表,包含所有交易对
func calcUserOrderIDPrefix(status int32, addr string) []byte {
key := fmt.Sprintf("%s"+"addr:%s:%d:", KeyPrefixLocalDB, addr, status)
return []byte(key)
}
func calcUserOrderIDKey(status int32, addr string, index int64) []byte {
key := fmt.Sprintf("%s"+"addr:%s:%d:%018d", KeyPrefixLocalDB, addr, status, index)
return []byte(key)
}
package executor
import (
"github.com/33cn/chain33/types"
et "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
//查询市场深度
func (s *exchange) Query_QueryMarketDepth(in *et.QueryMarketDepth) (types.Message, error) {
if !CheckCount(in.Count) {
return nil, et.ErrCount
}
if in.Count == 0 {
in.Count = 10
}
if !CheckExchangeAsset(in.LeftAsset, in.RightAsset) {
return nil, et.ErrAsset
}
if !CheckPrice(in.Price) {
return nil, et.ErrAssetPrice
}
if !CheckOp(in.Op) {
return nil, et.ErrAssetOp
}
return QueryMarketDepth(s.GetLocalDB(), in.LeftAsset, in.RightAsset, in.Op, in.Price, in.Count)
}
//查询已经完成得订单
func (s *exchange) Query_QueryCompletedOrderList(in *et.QueryCompletedOrderList) (types.Message, error) {
if !CheckExchangeAsset(in.LeftAsset, in.RightAsset) {
return nil, et.ErrAsset
}
if in.Count > 20 {
return nil, et.ErrCount
}
if !CheckDirection(in.Direction) {
return nil, et.ErrDirection
}
return QueryCompletedOrderList(s.GetLocalDB(), s.GetStateDB(), in.LeftAsset, in.RightAsset, in.Index, in.Count, in.Direction)
}
//根据orderID查询订单信息
func (s *exchange) Query_QueryOrder(in *et.QueryOrder) (types.Message, error) {
if in.OrderID == "" {
return nil, et.ErrOrderID
}
return findOrderByOrderID(s.GetStateDB(), in.OrderID)
}
//根据订单状态,查询订单信息(这里面包含所有交易对)
func (s *exchange) Query_QueryOrderList(in *et.QueryOrderList) (types.Message, error) {
if !CheckStatus(in.Status) {
return nil, et.ErrStatus
}
if !CheckCount(in.Count) {
return nil, et.ErrCount
}
if !CheckDirection(in.Direction) {
return nil, et.ErrDirection
}
if in.Address == "" {
return nil, et.ErrAddr
}
return QueryOrderList(s.GetLocalDB(), s.GetStateDB(), in.Address, in.Status, in.Count, in.Direction, in.Index)
}
package types
import (
"github.com/33cn/chain33/pluginmgr"
"github.com/33cn/plugin/plugin/dapp/exchange/commands"
"github.com/33cn/plugin/plugin/dapp/exchange/executor"
"github.com/33cn/plugin/plugin/dapp/exchange/rpc"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* 初始化dapp相关的组件
*/
func init() {
pluginmgr.Register(&pluginmgr.PluginBase{
Name: exchangetypes.ExchangeX,
ExecName: executor.GetName(),
Exec: executor.Init,
Cmd: commands.Cmd,
RPC: rpc.Init,
})
}
all:
./create_protobuf.sh
#!/bin/sh
# proto生成命令,将pb.go文件生成到types/目录下, chain33_path支持引用chain33框架的proto文件
chain33_path=$(go list -f '{{.Dir}}' "github.com/33cn/chain33")
protoc --go_out=plugins=grpc:../types ./*.proto --proto_path=. --proto_path="${chain33_path}/types/proto/"
syntax = "proto3";
package types;
message Exchange {
}
message ExchangeAction {
oneof value {
LimitOrder limitOrder = 1;
// MarketOrder marketOrder = 2;
RevokeOrder revokeOrder = 3;
}
int32 ty = 6;
}
//限价订单
message LimitOrder {
//交易对
Asset leftAsset = 1;
//交易对
Asset rightAsset = 2;
//价格
float price = 3;
//总量
int64 amount = 4;
//操作, 1为买,2为卖
int32 op = 5;
}
//市价委托
message MarketOrder {
//资产1
Asset leftAsset = 1;
//资产2
Asset rightAsset = 2;
//总量
int64 amount = 3;
//操作, 1为买,2为卖
int32 op = 4;
}
//撤回订单
message RevokeOrder {
//订单号
string orderID = 1;
}
//资产类型
message Asset {
string execer = 1;
string symbol = 2;
}
//订单信息
message Order {
string orderID = 1;
oneof value {
LimitOrder limitOrder = 2;
MarketOrder marketOrder = 3;
}
//挂单类型
int32 ty = 4;
//已经成交的数量
int64 executed = 5;
//余额
int64 balance = 6;
//状态,0 挂单中ordered, 1 完成completed, 2撤回 revoked
int32 status = 7;
//用户地址
string addr = 8;
//更新时间
int64 updateTime = 9;
//索引
int64 index = 10;
}
//挂单价
message OrderPrice {
float price = 1;
int64 index = 2;
}
//单号
message OrderID {
string ID = 1;
int64 index = 2;
}
//查询接口
message QueryMarketDepth {
//资产1
Asset leftAsset = 1;
//资产2
Asset rightAsset = 2;
//操作, 1为买,2为卖
int32 op = 3;
// 这里用价格作为索引值
float price = 4;
//单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
int32 count = 5;
}
//市场深度
message MarketDepth {
//资产1
Asset leftAsset = 1;
//资产2
Asset rightAsset = 2;
//价格
float price = 3;
//总量
int64 amount = 4;
//操作, 1为买,2为卖
int32 op = 5;
}
//查询接口返回的市场深度列表
message MarketDepthList {
repeated MarketDepth list = 1;
}
//查询最新得成交信息,外部接口
message QueryCompletedOrderList {
//资产1
Asset leftAsset = 1;
//资产2
Asset rightAsset = 2;
// 索引值
int64 index = 3;
//单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
int32 count = 4;
// 0降序,1升序,默认降序
int32 direction = 5;
}
//根据orderID去查询订单信息
message QueryOrder {
string orderID = 1;
}
//根据地址,状态查询用户自己的挂单信息
message QueryOrderList {
//挂单状态必填(默认是0,只查询ordered挂单中的)
int32 status = 1;
//用户地址信息,必填
string address = 2;
// 索引值
int64 index = 3;
//单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
int32 count = 4;
// 0降序,1升序,默认降序
int32 direction = 5;
}
//订单列表
message OrderList {
repeated Order list = 1;
}
//exchange执行票据日志
message ReceiptExchange {
Order order = 1;
repeated Order matchOrders = 2;
int64 index = 3;
}
service exchange {
}
package rpc
/*
* 实现json rpc和grpc service接口
* json rpc用Jrpc结构作为接收实例
* grpc使用channelClient结构作为接收实例
*/
package rpc
import (
rpctypes "github.com/33cn/chain33/rpc/types"
exchangetypes "github.com/33cn/plugin/plugin/dapp/exchange/types"
)
/*
* rpc相关结构定义和初始化
*/
// 实现grpc的service接口
type channelClient struct {
rpctypes.ChannelClient
}
// Jrpc 实现json rpc调用实例
type Jrpc struct {
cli *channelClient
}
// Grpc grpc
type Grpc struct {
*channelClient
}
// Init init rpc
func Init(name string, s rpctypes.RPCServer) {
cli := &channelClient{}
grpc := &Grpc{channelClient: cli}
cli.Init(name, s, &Jrpc{cli: cli}, grpc)
//存在grpc service时注册grpc server,需要生成对应的pb.go文件
exchangetypes.RegisterExchangeServer(s.GRPC(), grpc)
}
package types
import "fmt"
// some errors definition
var (
ErrAssetAmount = fmt.Errorf("%s", "The asset amount is not valid!")
ErrAssetPrice = fmt.Errorf("%s", "The asset price is not valid!")
ErrAssetOp = fmt.Errorf("%s", "The asset op is not define!")
ErrAssetBalance = fmt.Errorf("%s", "Insufficient balance!")
ErrOrderSatus = fmt.Errorf("%s", "The order status is reovked or completed!")
ErrAddr = fmt.Errorf("%s", "Wrong Addr!")
ErrAsset = fmt.Errorf("%s", "The asset's execer or symbol can't be nil,The same assets cannot be exchanged!")
ErrCount = fmt.Errorf("%s", "The param count can't large 20")
ErrDirection = fmt.Errorf("%s", "The direction only 0 or 1!")
ErrStatus = fmt.Errorf("%s", "The status only in 0 , 1, 2!")
ErrOrderID = fmt.Errorf("%s", "Wrong OrderID!")
)
package types
import (
log "github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
)
/*
* 交易相关类型定义
* 交易action通常有对应的log结构,用于交易回执日志记录
* 每一种action和log需要用id数值和name名称加以区分
*/
// action类型id和name,这些常量可以自定义修改
const (
TyUnknowAction = iota + 200
TyLimitOrderAction
TyMarketOrderAction
TyRevokeOrderAction
NameLimitOrderAction = "LimitOrder"
NameMarketOrderAction = "MarketOrder"
NameRevokeOrderAction = "RevokeOrder"
FuncNameQueryMarketDepth = "QueryMarketDepth"
FuncNameQueryCompletedOrderList = "QueryCompletedOrderList"
FuncNameQueryOrder = "QueryOrder"
FuncNameQueryOrderList = "QueryOrderList"
)
// log类型id值
const (
TyUnknownLog = iota + 200
TyLimitOrderLog
TyMarketOrderLog
TyRevokeOrderLog
)
// OP
const (
OpBuy = iota + 1
OpSell
)
//order status
const (
Ordered = iota
Completed
Revoked
)
//const
const (
ListDESC = int32(0)
ListASC = int32(1)
ListSeek = int32(2)
)
//单次list还回条数
const (
Count = int32(5)
MaxCount = int32(20)
)
var (
//ExchangeX 执行器名称定义
ExchangeX = "exchange"
//定义actionMap
actionMap = map[string]int32{
NameLimitOrderAction: TyLimitOrderAction,
NameMarketOrderAction: TyMarketOrderAction,
NameRevokeOrderAction: TyRevokeOrderAction,
}
//定义log的id和具体log类型及名称,填入具体自定义log类型
logMap = map[int64]*types.LogInfo{
//LogID: {Ty: reflect.TypeOf(LogStruct), Name: LogName},
}
tlog = log.New("module", "exchange.types")
)
// init defines a register function
func init() {
types.AllowUserExec = append(types.AllowUserExec, []byte(ExchangeX))
//注册合约启用高度
types.RegFork(ExchangeX, InitFork)
types.RegExec(ExchangeX, InitExecutor)
}
// InitFork defines register fork
func InitFork(cfg *types.Chain33Config) {
cfg.RegisterDappFork(ExchangeX, "Enable", 0)
}
// InitExecutor defines register executor
func InitExecutor(cfg *types.Chain33Config) {
types.RegistorExecutor(ExchangeX, NewType(cfg))
}
type exchangeType struct {
types.ExecTypeBase
}
func NewType(cfg *types.Chain33Config) *exchangeType {
c := &exchangeType{}
c.SetChild(c)
c.SetConfig(cfg)
return c
}
// GetPayload 获取合约action结构
func (e *exchangeType) GetPayload() types.Message {
return &ExchangeAction{}
}
// GeTypeMap 获取合约action的id和name信息
func (e *exchangeType) GetTypeMap() map[string]int32 {
return actionMap
}
// GetLogMap 获取合约log相关信息
func (e *exchangeType) GetLogMap() map[int64]*types.LogInfo {
return logMap
}
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: exchange.proto
/*
Package types is a generated protocol buffer package.
It is generated from these files:
exchange.proto
It has these top-level messages:
Exchange
ExchangeAction
LimitOrder
MarketOrder
RevokeOrder
Asset
Order
OrderPrice
OrderID
QueryMarketDepth
MarketDepth
MarketDepthList
QueryCompletedOrderList
QueryOrder
QueryOrderList
OrderList
ReceiptExchange
*/
package types
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type Exchange struct {
}
func (m *Exchange) Reset() { *m = Exchange{} }
func (m *Exchange) String() string { return proto.CompactTextString(m) }
func (*Exchange) ProtoMessage() {}
func (*Exchange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
type ExchangeAction struct {
// Types that are valid to be assigned to Value:
// *ExchangeAction_LimitOrder
// *ExchangeAction_RevokeOrder
Value isExchangeAction_Value `protobuf_oneof:"value"`
Ty int32 `protobuf:"varint,6,opt,name=ty" json:"ty,omitempty"`
}
func (m *ExchangeAction) Reset() { *m = ExchangeAction{} }
func (m *ExchangeAction) String() string { return proto.CompactTextString(m) }
func (*ExchangeAction) ProtoMessage() {}
func (*ExchangeAction) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
type isExchangeAction_Value interface {
isExchangeAction_Value()
}
type ExchangeAction_LimitOrder struct {
LimitOrder *LimitOrder `protobuf:"bytes,1,opt,name=limitOrder,oneof"`
}
type ExchangeAction_RevokeOrder struct {
RevokeOrder *RevokeOrder `protobuf:"bytes,3,opt,name=revokeOrder,oneof"`
}
func (*ExchangeAction_LimitOrder) isExchangeAction_Value() {}
func (*ExchangeAction_RevokeOrder) isExchangeAction_Value() {}
func (m *ExchangeAction) GetValue() isExchangeAction_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *ExchangeAction) GetLimitOrder() *LimitOrder {
if x, ok := m.GetValue().(*ExchangeAction_LimitOrder); ok {
return x.LimitOrder
}
return nil
}
func (m *ExchangeAction) GetRevokeOrder() *RevokeOrder {
if x, ok := m.GetValue().(*ExchangeAction_RevokeOrder); ok {
return x.RevokeOrder
}
return nil
}
func (m *ExchangeAction) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*ExchangeAction) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _ExchangeAction_OneofMarshaler, _ExchangeAction_OneofUnmarshaler, _ExchangeAction_OneofSizer, []interface{}{
(*ExchangeAction_LimitOrder)(nil),
(*ExchangeAction_RevokeOrder)(nil),
}
}
func _ExchangeAction_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*ExchangeAction)
// value
switch x := m.Value.(type) {
case *ExchangeAction_LimitOrder:
b.EncodeVarint(1<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.LimitOrder); err != nil {
return err
}
case *ExchangeAction_RevokeOrder:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.RevokeOrder); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("ExchangeAction.Value has unexpected type %T", x)
}
return nil
}
func _ExchangeAction_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*ExchangeAction)
switch tag {
case 1: // value.limitOrder
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(LimitOrder)
err := b.DecodeMessage(msg)
m.Value = &ExchangeAction_LimitOrder{msg}
return true, err
case 3: // value.revokeOrder
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(RevokeOrder)
err := b.DecodeMessage(msg)
m.Value = &ExchangeAction_RevokeOrder{msg}
return true, err
default:
return false, nil
}
}
func _ExchangeAction_OneofSizer(msg proto.Message) (n int) {
m := msg.(*ExchangeAction)
// value
switch x := m.Value.(type) {
case *ExchangeAction_LimitOrder:
s := proto.Size(x.LimitOrder)
n += proto.SizeVarint(1<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *ExchangeAction_RevokeOrder:
s := proto.Size(x.RevokeOrder)
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// 限价订单
type LimitOrder struct {
// 交易对
LeftAsset *Asset `protobuf:"bytes,1,opt,name=leftAsset" json:"leftAsset,omitempty"`
// 交易对
RightAsset *Asset `protobuf:"bytes,2,opt,name=rightAsset" json:"rightAsset,omitempty"`
// 价格
Price float32 `protobuf:"fixed32,3,opt,name=price" json:"price,omitempty"`
// 总量
Amount int64 `protobuf:"varint,4,opt,name=amount" json:"amount,omitempty"`
// 操作, 1为买,2为卖
Op int32 `protobuf:"varint,5,opt,name=op" json:"op,omitempty"`
}
func (m *LimitOrder) Reset() { *m = LimitOrder{} }
func (m *LimitOrder) String() string { return proto.CompactTextString(m) }
func (*LimitOrder) ProtoMessage() {}
func (*LimitOrder) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} }
func (m *LimitOrder) GetLeftAsset() *Asset {
if m != nil {
return m.LeftAsset
}
return nil
}
func (m *LimitOrder) GetRightAsset() *Asset {
if m != nil {
return m.RightAsset
}
return nil
}
func (m *LimitOrder) GetPrice() float32 {
if m != nil {
return m.Price
}
return 0
}
func (m *LimitOrder) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
func (m *LimitOrder) GetOp() int32 {
if m != nil {
return m.Op
}
return 0
}
// 市价委托
type MarketOrder struct {
// 资产1
LeftAsset *Asset `protobuf:"bytes,1,opt,name=leftAsset" json:"leftAsset,omitempty"`
// 资产2
RightAsset *Asset `protobuf:"bytes,2,opt,name=rightAsset" json:"rightAsset,omitempty"`
// 总量
Amount int64 `protobuf:"varint,3,opt,name=amount" json:"amount,omitempty"`
// 操作, 1为买,2为卖
Op int32 `protobuf:"varint,4,opt,name=op" json:"op,omitempty"`
}
func (m *MarketOrder) Reset() { *m = MarketOrder{} }
func (m *MarketOrder) String() string { return proto.CompactTextString(m) }
func (*MarketOrder) ProtoMessage() {}
func (*MarketOrder) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} }
func (m *MarketOrder) GetLeftAsset() *Asset {
if m != nil {
return m.LeftAsset
}
return nil
}
func (m *MarketOrder) GetRightAsset() *Asset {
if m != nil {
return m.RightAsset
}
return nil
}
func (m *MarketOrder) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
func (m *MarketOrder) GetOp() int32 {
if m != nil {
return m.Op
}
return 0
}
// 撤回订单
type RevokeOrder struct {
// 订单号
OrderID string `protobuf:"bytes,1,opt,name=orderID" json:"orderID,omitempty"`
}
func (m *RevokeOrder) Reset() { *m = RevokeOrder{} }
func (m *RevokeOrder) String() string { return proto.CompactTextString(m) }
func (*RevokeOrder) ProtoMessage() {}
func (*RevokeOrder) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} }
func (m *RevokeOrder) GetOrderID() string {
if m != nil {
return m.OrderID
}
return ""
}
// 资产类型
type Asset struct {
Execer string `protobuf:"bytes,1,opt,name=execer" json:"execer,omitempty"`
Symbol string `protobuf:"bytes,2,opt,name=symbol" json:"symbol,omitempty"`
}
func (m *Asset) Reset() { *m = Asset{} }
func (m *Asset) String() string { return proto.CompactTextString(m) }
func (*Asset) ProtoMessage() {}
func (*Asset) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} }
func (m *Asset) GetExecer() string {
if m != nil {
return m.Execer
}
return ""
}
func (m *Asset) GetSymbol() string {
if m != nil {
return m.Symbol
}
return ""
}
// 订单信息
type Order struct {
OrderID string `protobuf:"bytes,1,opt,name=orderID" json:"orderID,omitempty"`
// Types that are valid to be assigned to Value:
// *Order_LimitOrder
// *Order_MarketOrder
Value isOrder_Value `protobuf_oneof:"value"`
// 挂单类型
Ty int32 `protobuf:"varint,4,opt,name=ty" json:"ty,omitempty"`
// 已经成交的数量
Executed int64 `protobuf:"varint,5,opt,name=executed" json:"executed,omitempty"`
// 余额
Balance int64 `protobuf:"varint,6,opt,name=balance" json:"balance,omitempty"`
// 状态,0 挂单中ordered, 1 完成completed, 2撤回 revoked
Status int32 `protobuf:"varint,7,opt,name=status" json:"status,omitempty"`
// 用户地址
Addr string `protobuf:"bytes,8,opt,name=addr" json:"addr,omitempty"`
// 更新时间
UpdateTime int64 `protobuf:"varint,9,opt,name=updateTime" json:"updateTime,omitempty"`
// 索引
Index int64 `protobuf:"varint,10,opt,name=index" json:"index,omitempty"`
}
func (m *Order) Reset() { *m = Order{} }
func (m *Order) String() string { return proto.CompactTextString(m) }
func (*Order) ProtoMessage() {}
func (*Order) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} }
type isOrder_Value interface {
isOrder_Value()
}
type Order_LimitOrder struct {
LimitOrder *LimitOrder `protobuf:"bytes,2,opt,name=limitOrder,oneof"`
}
type Order_MarketOrder struct {
MarketOrder *MarketOrder `protobuf:"bytes,3,opt,name=marketOrder,oneof"`
}
func (*Order_LimitOrder) isOrder_Value() {}
func (*Order_MarketOrder) isOrder_Value() {}
func (m *Order) GetValue() isOrder_Value {
if m != nil {
return m.Value
}
return nil
}
func (m *Order) GetOrderID() string {
if m != nil {
return m.OrderID
}
return ""
}
func (m *Order) GetLimitOrder() *LimitOrder {
if x, ok := m.GetValue().(*Order_LimitOrder); ok {
return x.LimitOrder
}
return nil
}
func (m *Order) GetMarketOrder() *MarketOrder {
if x, ok := m.GetValue().(*Order_MarketOrder); ok {
return x.MarketOrder
}
return nil
}
func (m *Order) GetTy() int32 {
if m != nil {
return m.Ty
}
return 0
}
func (m *Order) GetExecuted() int64 {
if m != nil {
return m.Executed
}
return 0
}
func (m *Order) GetBalance() int64 {
if m != nil {
return m.Balance
}
return 0
}
func (m *Order) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *Order) GetAddr() string {
if m != nil {
return m.Addr
}
return ""
}
func (m *Order) GetUpdateTime() int64 {
if m != nil {
return m.UpdateTime
}
return 0
}
func (m *Order) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
// XXX_OneofFuncs is for the internal use of the proto package.
func (*Order) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
return _Order_OneofMarshaler, _Order_OneofUnmarshaler, _Order_OneofSizer, []interface{}{
(*Order_LimitOrder)(nil),
(*Order_MarketOrder)(nil),
}
}
func _Order_OneofMarshaler(msg proto.Message, b *proto.Buffer) error {
m := msg.(*Order)
// value
switch x := m.Value.(type) {
case *Order_LimitOrder:
b.EncodeVarint(2<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.LimitOrder); err != nil {
return err
}
case *Order_MarketOrder:
b.EncodeVarint(3<<3 | proto.WireBytes)
if err := b.EncodeMessage(x.MarketOrder); err != nil {
return err
}
case nil:
default:
return fmt.Errorf("Order.Value has unexpected type %T", x)
}
return nil
}
func _Order_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) {
m := msg.(*Order)
switch tag {
case 2: // value.limitOrder
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(LimitOrder)
err := b.DecodeMessage(msg)
m.Value = &Order_LimitOrder{msg}
return true, err
case 3: // value.marketOrder
if wire != proto.WireBytes {
return true, proto.ErrInternalBadWireType
}
msg := new(MarketOrder)
err := b.DecodeMessage(msg)
m.Value = &Order_MarketOrder{msg}
return true, err
default:
return false, nil
}
}
func _Order_OneofSizer(msg proto.Message) (n int) {
m := msg.(*Order)
// value
switch x := m.Value.(type) {
case *Order_LimitOrder:
s := proto.Size(x.LimitOrder)
n += proto.SizeVarint(2<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case *Order_MarketOrder:
s := proto.Size(x.MarketOrder)
n += proto.SizeVarint(3<<3 | proto.WireBytes)
n += proto.SizeVarint(uint64(s))
n += s
case nil:
default:
panic(fmt.Sprintf("proto: unexpected type %T in oneof", x))
}
return n
}
// 挂单价
type OrderPrice struct {
Price float32 `protobuf:"fixed32,1,opt,name=price" json:"price,omitempty"`
Index int64 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"`
}
func (m *OrderPrice) Reset() { *m = OrderPrice{} }
func (m *OrderPrice) String() string { return proto.CompactTextString(m) }
func (*OrderPrice) ProtoMessage() {}
func (*OrderPrice) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} }
func (m *OrderPrice) GetPrice() float32 {
if m != nil {
return m.Price
}
return 0
}
func (m *OrderPrice) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
// 单号
type OrderID struct {
ID string `protobuf:"bytes,1,opt,name=ID" json:"ID,omitempty"`
Index int64 `protobuf:"varint,2,opt,name=index" json:"index,omitempty"`
}
func (m *OrderID) Reset() { *m = OrderID{} }
func (m *OrderID) String() string { return proto.CompactTextString(m) }
func (*OrderID) ProtoMessage() {}
func (*OrderID) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} }
func (m *OrderID) GetID() string {
if m != nil {
return m.ID
}
return ""
}
func (m *OrderID) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
// 查询接口
type QueryMarketDepth struct {
// 资产1
LeftAsset *Asset `protobuf:"bytes,1,opt,name=leftAsset" json:"leftAsset,omitempty"`
// 资产2
RightAsset *Asset `protobuf:"bytes,2,opt,name=rightAsset" json:"rightAsset,omitempty"`
// 操作, 1为买,2为卖
Op int32 `protobuf:"varint,3,opt,name=op" json:"op,omitempty"`
// 这里用价格作为索引值
Price float32 `protobuf:"fixed32,4,opt,name=price" json:"price,omitempty"`
// 单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
Count int32 `protobuf:"varint,5,opt,name=count" json:"count,omitempty"`
}
func (m *QueryMarketDepth) Reset() { *m = QueryMarketDepth{} }
func (m *QueryMarketDepth) String() string { return proto.CompactTextString(m) }
func (*QueryMarketDepth) ProtoMessage() {}
func (*QueryMarketDepth) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} }
func (m *QueryMarketDepth) GetLeftAsset() *Asset {
if m != nil {
return m.LeftAsset
}
return nil
}
func (m *QueryMarketDepth) GetRightAsset() *Asset {
if m != nil {
return m.RightAsset
}
return nil
}
func (m *QueryMarketDepth) GetOp() int32 {
if m != nil {
return m.Op
}
return 0
}
func (m *QueryMarketDepth) GetPrice() float32 {
if m != nil {
return m.Price
}
return 0
}
func (m *QueryMarketDepth) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
// 市场深度
type MarketDepth struct {
// 资产1
LeftAsset *Asset `protobuf:"bytes,1,opt,name=leftAsset" json:"leftAsset,omitempty"`
// 资产2
RightAsset *Asset `protobuf:"bytes,2,opt,name=rightAsset" json:"rightAsset,omitempty"`
// 价格
Price float32 `protobuf:"fixed32,3,opt,name=price" json:"price,omitempty"`
// 总量
Amount int64 `protobuf:"varint,4,opt,name=amount" json:"amount,omitempty"`
// 操作, 1为买,2为卖
Op int32 `protobuf:"varint,5,opt,name=op" json:"op,omitempty"`
}
func (m *MarketDepth) Reset() { *m = MarketDepth{} }
func (m *MarketDepth) String() string { return proto.CompactTextString(m) }
func (*MarketDepth) ProtoMessage() {}
func (*MarketDepth) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} }
func (m *MarketDepth) GetLeftAsset() *Asset {
if m != nil {
return m.LeftAsset
}
return nil
}
func (m *MarketDepth) GetRightAsset() *Asset {
if m != nil {
return m.RightAsset
}
return nil
}
func (m *MarketDepth) GetPrice() float32 {
if m != nil {
return m.Price
}
return 0
}
func (m *MarketDepth) GetAmount() int64 {
if m != nil {
return m.Amount
}
return 0
}
func (m *MarketDepth) GetOp() int32 {
if m != nil {
return m.Op
}
return 0
}
// 查询接口返回的市场深度列表
type MarketDepthList struct {
List []*MarketDepth `protobuf:"bytes,1,rep,name=list" json:"list,omitempty"`
}
func (m *MarketDepthList) Reset() { *m = MarketDepthList{} }
func (m *MarketDepthList) String() string { return proto.CompactTextString(m) }
func (*MarketDepthList) ProtoMessage() {}
func (*MarketDepthList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} }
func (m *MarketDepthList) GetList() []*MarketDepth {
if m != nil {
return m.List
}
return nil
}
// 查询最新得成交信息,外部接口
type QueryCompletedOrderList struct {
// 资产1
LeftAsset *Asset `protobuf:"bytes,1,opt,name=leftAsset" json:"leftAsset,omitempty"`
// 资产2
RightAsset *Asset `protobuf:"bytes,2,opt,name=rightAsset" json:"rightAsset,omitempty"`
// 索引值
Index int64 `protobuf:"varint,3,opt,name=index" json:"index,omitempty"`
// 单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
Count int32 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
// 0降序,1升序,默认降序
Direction int32 `protobuf:"varint,5,opt,name=direction" json:"direction,omitempty"`
}
func (m *QueryCompletedOrderList) Reset() { *m = QueryCompletedOrderList{} }
func (m *QueryCompletedOrderList) String() string { return proto.CompactTextString(m) }
func (*QueryCompletedOrderList) ProtoMessage() {}
func (*QueryCompletedOrderList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} }
func (m *QueryCompletedOrderList) GetLeftAsset() *Asset {
if m != nil {
return m.LeftAsset
}
return nil
}
func (m *QueryCompletedOrderList) GetRightAsset() *Asset {
if m != nil {
return m.RightAsset
}
return nil
}
func (m *QueryCompletedOrderList) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
func (m *QueryCompletedOrderList) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
func (m *QueryCompletedOrderList) GetDirection() int32 {
if m != nil {
return m.Direction
}
return 0
}
// 根据orderID去查询订单信息
type QueryOrder struct {
OrderID string `protobuf:"bytes,1,opt,name=orderID" json:"orderID,omitempty"`
}
func (m *QueryOrder) Reset() { *m = QueryOrder{} }
func (m *QueryOrder) String() string { return proto.CompactTextString(m) }
func (*QueryOrder) ProtoMessage() {}
func (*QueryOrder) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} }
func (m *QueryOrder) GetOrderID() string {
if m != nil {
return m.OrderID
}
return ""
}
// 根据地址,状态查询用户自己的挂单信息
type QueryOrderList struct {
// 挂单状态必填(默认是0,只查询ordered挂单中的)
Status int32 `protobuf:"varint,1,opt,name=status" json:"status,omitempty"`
// 用户地址信息,必填
Address string `protobuf:"bytes,2,opt,name=address" json:"address,omitempty"`
// 索引值
Index int64 `protobuf:"varint,3,opt,name=index" json:"index,omitempty"`
// 单页返回多少条记录,默认返回10条,为了系统安全最多单次只能返回20条
Count int32 `protobuf:"varint,4,opt,name=count" json:"count,omitempty"`
// 0降序,1升序,默认降序
Direction int32 `protobuf:"varint,5,opt,name=direction" json:"direction,omitempty"`
}
func (m *QueryOrderList) Reset() { *m = QueryOrderList{} }
func (m *QueryOrderList) String() string { return proto.CompactTextString(m) }
func (*QueryOrderList) ProtoMessage() {}
func (*QueryOrderList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} }
func (m *QueryOrderList) GetStatus() int32 {
if m != nil {
return m.Status
}
return 0
}
func (m *QueryOrderList) GetAddress() string {
if m != nil {
return m.Address
}
return ""
}
func (m *QueryOrderList) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
func (m *QueryOrderList) GetCount() int32 {
if m != nil {
return m.Count
}
return 0
}
func (m *QueryOrderList) GetDirection() int32 {
if m != nil {
return m.Direction
}
return 0
}
// 订单列表
type OrderList struct {
List []*Order `protobuf:"bytes,1,rep,name=list" json:"list,omitempty"`
}
func (m *OrderList) Reset() { *m = OrderList{} }
func (m *OrderList) String() string { return proto.CompactTextString(m) }
func (*OrderList) ProtoMessage() {}
func (*OrderList) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} }
func (m *OrderList) GetList() []*Order {
if m != nil {
return m.List
}
return nil
}
// exchange执行票据日志
type ReceiptExchange struct {
Order *Order `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"`
MatchOrders []*Order `protobuf:"bytes,2,rep,name=matchOrders" json:"matchOrders,omitempty"`
Index int64 `protobuf:"varint,3,opt,name=index" json:"index,omitempty"`
}
func (m *ReceiptExchange) Reset() { *m = ReceiptExchange{} }
func (m *ReceiptExchange) String() string { return proto.CompactTextString(m) }
func (*ReceiptExchange) ProtoMessage() {}
func (*ReceiptExchange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} }
func (m *ReceiptExchange) GetOrder() *Order {
if m != nil {
return m.Order
}
return nil
}
func (m *ReceiptExchange) GetMatchOrders() []*Order {
if m != nil {
return m.MatchOrders
}
return nil
}
func (m *ReceiptExchange) GetIndex() int64 {
if m != nil {
return m.Index
}
return 0
}
func init() {
proto.RegisterType((*Exchange)(nil), "types.Exchange")
proto.RegisterType((*ExchangeAction)(nil), "types.ExchangeAction")
proto.RegisterType((*LimitOrder)(nil), "types.LimitOrder")
proto.RegisterType((*MarketOrder)(nil), "types.MarketOrder")
proto.RegisterType((*RevokeOrder)(nil), "types.RevokeOrder")
proto.RegisterType((*Asset)(nil), "types.Asset")
proto.RegisterType((*Order)(nil), "types.Order")
proto.RegisterType((*OrderPrice)(nil), "types.OrderPrice")
proto.RegisterType((*OrderID)(nil), "types.OrderID")
proto.RegisterType((*QueryMarketDepth)(nil), "types.QueryMarketDepth")
proto.RegisterType((*MarketDepth)(nil), "types.MarketDepth")
proto.RegisterType((*MarketDepthList)(nil), "types.MarketDepthList")
proto.RegisterType((*QueryCompletedOrderList)(nil), "types.QueryCompletedOrderList")
proto.RegisterType((*QueryOrder)(nil), "types.QueryOrder")
proto.RegisterType((*QueryOrderList)(nil), "types.QueryOrderList")
proto.RegisterType((*OrderList)(nil), "types.OrderList")
proto.RegisterType((*ReceiptExchange)(nil), "types.ReceiptExchange")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Exchange service
type ExchangeClient interface {
}
type exchangeClient struct {
cc *grpc.ClientConn
}
func NewExchangeClient(cc *grpc.ClientConn) ExchangeClient {
return &exchangeClient{cc}
}
// Server API for Exchange service
type ExchangeServer interface {
}
func RegisterExchangeServer(s *grpc.Server, srv ExchangeServer) {
s.RegisterService(&_Exchange_serviceDesc, srv)
}
var _Exchange_serviceDesc = grpc.ServiceDesc{
ServiceName: "types.exchange",
HandlerType: (*ExchangeServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{},
Metadata: "exchange.proto",
}
func init() { proto.RegisterFile("exchange.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
// 649 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xdd, 0x6a, 0xd4, 0x40,
0x14, 0xee, 0xe4, 0xa7, 0xdb, 0x9c, 0x95, 0xad, 0x0e, 0xa2, 0x41, 0x44, 0x96, 0x5c, 0xd4, 0x22,
0xba, 0x42, 0x0b, 0xfe, 0x5c, 0x56, 0x2b, 0xb4, 0x50, 0xa9, 0x0e, 0xbe, 0x40, 0x9a, 0x1c, 0xbb,
0xa1, 0xd9, 0x4d, 0x48, 0x26, 0xa5, 0x8b, 0xaf, 0x20, 0x78, 0xe7, 0x13, 0x28, 0xf8, 0x12, 0xe2,
0xab, 0xc9, 0x9c, 0x4c, 0x32, 0xd3, 0x1f, 0xa9, 0xa0, 0x7b, 0x97, 0x6f, 0xce, 0x4f, 0xbe, 0x73,
0xce, 0x77, 0x66, 0x60, 0x84, 0x67, 0xc9, 0x34, 0x9e, 0x1f, 0xe3, 0xa4, 0xac, 0x0a, 0x59, 0x70,
0x5f, 0x2e, 0x4a, 0xac, 0x23, 0x80, 0xb5, 0x37, 0xda, 0x10, 0x7d, 0x65, 0x30, 0xea, 0xc0, 0x4e,
0x22, 0xb3, 0x62, 0xce, 0xb7, 0x01, 0xf2, 0x6c, 0x96, 0xc9, 0xc3, 0x2a, 0xc5, 0x2a, 0x64, 0x63,
0xb6, 0x39, 0xdc, 0xba, 0x35, 0xa1, 0xd0, 0xc9, 0x41, 0x6f, 0xd8, 0x5b, 0x11, 0x96, 0x1b, 0x7f,
0x06, 0xc3, 0x0a, 0x4f, 0x8b, 0x13, 0x6c, 0xa3, 0x5c, 0x8a, 0xe2, 0x3a, 0x4a, 0x18, 0xcb, 0xde,
0x8a, 0xb0, 0x1d, 0xf9, 0x08, 0x1c, 0xb9, 0x08, 0x57, 0xc7, 0x6c, 0xd3, 0x17, 0x8e, 0x5c, 0xbc,
0x1a, 0x80, 0x7f, 0x1a, 0xe7, 0x0d, 0x46, 0xdf, 0x18, 0x80, 0xf9, 0x1b, 0x7f, 0x04, 0x41, 0x8e,
0x1f, 0xe5, 0x4e, 0x5d, 0xa3, 0xd4, 0x9c, 0x6e, 0xe8, 0xec, 0x74, 0x26, 0x8c, 0x99, 0x3f, 0x06,
0xa8, 0xb2, 0xe3, 0xa9, 0x76, 0x76, 0xae, 0x70, 0xb6, 0xec, 0xfc, 0x36, 0xf8, 0x65, 0x95, 0x25,
0x48, 0x9c, 0x1d, 0xd1, 0x02, 0x7e, 0x07, 0x56, 0xe3, 0x59, 0xd1, 0xcc, 0x65, 0xe8, 0x8d, 0xd9,
0xa6, 0x2b, 0x34, 0x52, 0x7c, 0x8b, 0x32, 0xf4, 0x5b, 0xbe, 0x45, 0x19, 0x7d, 0x61, 0x30, 0x7c,
0x1b, 0x57, 0x27, 0xb8, 0x74, 0x9e, 0x86, 0x91, 0x7b, 0x05, 0x23, 0xaf, 0x67, 0xf4, 0x10, 0x86,
0x56, 0xbf, 0x79, 0x08, 0x83, 0x42, 0x7d, 0xec, 0xef, 0x12, 0x9d, 0x40, 0x74, 0x30, 0x7a, 0x0e,
0x7e, 0x9f, 0x19, 0xcf, 0x30, 0xd1, 0xc3, 0x0e, 0x84, 0x46, 0xea, 0xbc, 0x5e, 0xcc, 0x8e, 0x8a,
0x9c, 0xb8, 0x05, 0x42, 0xa3, 0xe8, 0x97, 0x03, 0xfe, 0x35, 0xc9, 0x2f, 0x88, 0xc8, 0xf9, 0x6b,
0x11, 0xcd, 0x4c, 0x2f, 0x2f, 0x88, 0xc8, 0xea, 0xb2, 0x12, 0x91, 0xe5, 0xa8, 0x45, 0xe4, 0x75,
0x22, 0xe2, 0xf7, 0x60, 0x4d, 0x95, 0xd0, 0x48, 0x4c, 0x69, 0x54, 0xae, 0xe8, 0xb1, 0xa2, 0x7c,
0x14, 0xe7, 0xf1, 0x3c, 0x41, 0x52, 0x9d, 0x2b, 0x3a, 0x48, 0xe5, 0xca, 0x58, 0x36, 0x75, 0x38,
0xa0, 0x4c, 0x1a, 0x71, 0x0e, 0x5e, 0x9c, 0xa6, 0x55, 0xb8, 0x46, 0x15, 0xd2, 0x37, 0x7f, 0x00,
0xd0, 0x94, 0x69, 0x2c, 0xf1, 0x43, 0x36, 0xc3, 0x30, 0xa0, 0x44, 0xd6, 0x89, 0x12, 0x55, 0x36,
0x4f, 0xf1, 0x2c, 0x04, 0x32, 0xb5, 0xc0, 0x88, 0xfb, 0x05, 0x00, 0x31, 0x7f, 0x47, 0x5a, 0xeb,
0x15, 0xc8, 0x6c, 0x05, 0xf6, 0x29, 0x1c, 0x2b, 0x45, 0xf4, 0x14, 0x06, 0x87, 0xba, 0xc5, 0x23,
0x70, 0xfa, 0xbe, 0x3b, 0xfb, 0xbb, 0x7f, 0x08, 0xf8, 0xc1, 0xe0, 0xe6, 0xfb, 0x06, 0xab, 0x45,
0xdb, 0xbf, 0x5d, 0x2c, 0xe5, 0x74, 0x89, 0x2a, 0x6d, 0xd5, 0xe8, 0x76, 0x6a, 0x34, 0xb5, 0x79,
0x17, 0x6a, 0x4b, 0x48, 0xca, 0xed, 0x22, 0xb5, 0x20, 0xfa, 0xde, 0xef, 0xd2, 0xb2, 0x59, 0xfe,
0xdb, 0xce, 0xbf, 0x84, 0x75, 0x8b, 0xe6, 0x41, 0x56, 0x4b, 0xbe, 0x01, 0x5e, 0x9e, 0xd5, 0x8a,
0xa5, 0x7b, 0x49, 0xb2, 0xe4, 0x25, 0xc8, 0x1e, 0xfd, 0x64, 0x70, 0x97, 0xa6, 0xf1, 0xba, 0x98,
0x95, 0x39, 0x4a, 0x4c, 0x69, 0x9a, 0x94, 0x63, 0xa9, 0xe5, 0xb6, 0xca, 0x70, 0x2d, 0x65, 0x98,
0x21, 0x78, 0xd6, 0x10, 0xf8, 0x7d, 0x08, 0xd2, 0xac, 0x42, 0x7a, 0x0a, 0x74, 0xcd, 0xe6, 0x20,
0xda, 0x00, 0x20, 0xfa, 0xd7, 0xdd, 0x2d, 0x9f, 0x19, 0x8c, 0x8c, 0x23, 0x95, 0x67, 0xd6, 0x8b,
0x9d, 0x5b, 0xaf, 0x10, 0x06, 0x6a, 0xa5, 0xb0, 0xae, 0xf5, 0x35, 0xd3, 0xc1, 0xff, 0x48, 0xfb,
0x09, 0x04, 0x86, 0xc8, 0xf8, 0xdc, 0xac, 0xba, 0xae, 0x91, 0x5d, 0x4f, 0xe9, 0x13, 0xac, 0x0b,
0x4c, 0x30, 0x2b, 0x65, 0xf7, 0x34, 0xf2, 0x08, 0xfc, 0xc2, 0x7a, 0x0f, 0xcf, 0x47, 0xb5, 0x26,
0x3e, 0x51, 0xd7, 0x97, 0x4c, 0xa6, 0x74, 0xa8, 0xaa, 0xb9, 0x9c, 0xdf, 0x76, 0xb8, 0xba, 0xbe,
0x2d, 0x50, 0x97, 0x57, 0xfb, 0xd7, 0xa3, 0x55, 0x7a, 0xb7, 0xb7, 0x7f, 0x07, 0x00, 0x00, 0xff,
0xff, 0xe3, 0xe1, 0xf2, 0x06, 0xc9, 0x07, 0x00, 0x00,
}
...@@ -7,6 +7,7 @@ import ( ...@@ -7,6 +7,7 @@ import (
_ "github.com/33cn/plugin/plugin/dapp/dposvote" //auto gen _ "github.com/33cn/plugin/plugin/dapp/dposvote" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/echo" //auto gen _ "github.com/33cn/plugin/plugin/dapp/echo" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen _ "github.com/33cn/plugin/plugin/dapp/evm" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/exchange" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/game" //auto gen _ "github.com/33cn/plugin/plugin/dapp/game" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/guess" //auto gen _ "github.com/33cn/plugin/plugin/dapp/guess" //auto gen
_ "github.com/33cn/plugin/plugin/dapp/hashlock" //auto gen _ "github.com/33cn/plugin/plugin/dapp/hashlock" //auto gen
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment