// GetRawTx return rawtx of specifc tx. func GetRawTx(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.GetRawTxReq{} if err := c.BindJSON(&req); err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } rawtx, err := coin.GetRawTx(req.GetTxid()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } res := pp.GetRawTxRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), CoinType: req.CoinType, Rawtx: pp.PtrString(rawtx), } return c.SendJSON(&res) } return c.Error(rlt) } }
// GetAddresses get all addresses in wallet. // mode: GET // url: /api/v1/wallet/addresses?id=[:id] // params: // id: wallet id. func GetAddresses(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { id := r.FormValue("id") if id == "" { rlt = pp.MakeErrRes(errors.New("id is required")) break } addrs, err := wallet.GetAddresses(id) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } res := struct { Result *pp.Result `json:"result"` Addresses []string `json:"addresses"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Addresses: addrs, } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// NewAddress create address in wallet. // mode: POST // url: /api/v1/wallet/:id/address?&id=[:id] // params: // id: wallet id. func NewAddress(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get wallet id wltID := r.FormValue("id") if wltID == "" { rlt = pp.MakeErrRes(errors.New("id is required")) break } addrEntries, err := wallet.NewAddresses(wltID, 1) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } res := struct { Result *pp.Result Address string `json:"address"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Address: addrEntries[0].Address, } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// GetAddrBalance get balance of specific address. func GetAddrBalance(ee engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.GetAddrBalanceReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } coin, err := ee.GetCoin(req.GetCoinType()) if err != nil { rlt = pp.MakeErrRes(err) logger.Error(err.Error()) break } addrs := strings.Split(req.GetAddrs(), ",") b, err := coin.GetBalance(addrs) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := pp.GetAddrBalanceRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Balance: &b, } return c.SendJSON(&res) } return c.Error(rlt) } }
// GetBalance return balance of specific account. func GetAccountBalance(ee engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { rlt := &pp.EmptyRes{} for { req := pp.GetAccountBalanceReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // validate pubkey pubkey := req.GetPubkey() if err := validatePubkey(pubkey); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } a, err := ee.GetAccount(pubkey) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_NotExits) break } bal := a.GetBalance(req.GetCoinType()) bres := pp.GetAccountBalanceRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Balance: &pp.Balance{Amount: pp.PtrUint64(bal)}, } return c.SendJSON(&bres) } return c.Error(rlt) } }
// GetAccount get account that matchs the condition in url param. // mode: GET // url: /api/v1/account?active=[:active] // params: // active: optional condition, must be 1, if not exist, then retun all accounts. func GetAccount(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // get active res := struct { Result *pp.Result `json:"result"` Accounts []accountResult `json:"accounts,omitempty"` }{} active := r.FormValue("active") switch active { case "1": a, err := account.GetActive() if err != nil { // no active account. res.Result = pp.MakeResult(pp.ErrCode_NotExits, err.Error()) sendJSON(w, &res) return } res.Result = pp.MakeResultWithCode(pp.ErrCode_Success) res.Accounts = make([]accountResult, 1) res.Accounts[0].Pubkey = a.Pubkey res.Accounts[0].WalletID = make(map[string]string) for cp, id := range a.WltIDs { res.Accounts[0].WalletID[cp] = id } sendJSON(w, &res) case "": accounts := account.GetAll() res.Result = pp.MakeResultWithCode(pp.ErrCode_Success) res.Accounts = func(accounts []account.Account) []accountResult { as := make([]accountResult, len(accounts)) for i, a := range accounts { as[i].Pubkey = a.Pubkey as[i].WalletID = make(map[string]string) for cp, id := range a.WltIDs { as[i].WalletID[cp] = id } } return as }(accounts) sendJSON(w, &res) default: sendJSON(w, pp.MakeErrResWithCode(pp.ErrCode_WrongRequest)) } } }
func btcWithdraw(rp *ReqParams) (*pp.WithdrawalRes, *pp.EmptyRes) { ee := rp.Values["engine"].(engine.Exchange) acnt := rp.Values["account"].(account.Accounter) amt := rp.Values["amt"].(uint64) ct := rp.Values["cointype"].(string) toAddr := rp.Values["toAddr"].(string) // verify the toAddr if _, err := cipher.BitcoinDecodeBase58Address(toAddr); err != nil { return nil, pp.MakeErrRes(errors.New("invalid bitcoin address")) } var success bool var btcTxRlt *BtcTxResult var err error // decrease balance and check if the balance is sufficient. if err := acnt.DecreaseBalance(ct, amt+ee.GetBtcFee()); err != nil { return nil, pp.MakeErrRes(err) } defer func() { if !success { go func() { if btcTxRlt != nil { ee.PutUtxos(bitcoin.Type, btcTxRlt.UsingUtxos) } acnt.IncreaseBalance(ct, amt+ee.GetBtcFee()) }() } else { //TODO: handle the saving failure. ee.SaveAccount() } }() btcTxRlt, err = createBtcWithdrawTx(ee, amt, toAddr) if err != nil { return nil, pp.MakeErrRes(errors.New("failed to create withdrawal tx")) } rawtx, err := btcTxRlt.Tx.Serialize() if err != nil { return nil, pp.MakeErrRes(errors.New("tx serialize failed")) } newTxid, err := bitcoin.BroadcastTx(hex.EncodeToString(rawtx)) if err != nil { logger.Error(err.Error()) return nil, pp.MakeErrResWithCode(pp.ErrCode_BroadcastTxFail) } success = true if btcTxRlt.ChangeAddr != "" { logger.Debug("change address:%s", btcTxRlt.ChangeAddr) ee.WatchAddress(ct, btcTxRlt.ChangeAddr) } resp := pp.WithdrawalRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), NewTxid: &newTxid, } return &resp, nil }
// GetCoins get supported coins. func GetCoins(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { coins := pp.CoinsRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Coins: egn.GetSupportCoins(), } return c.SendJSON(&coins) } }
// JSON encrypt the data and write response. func (c *Context) SendJSON(data interface{}) error { encData, nonce, err := pp.Encrypt(data, c.Pubkey, c.ServSeckey) if err != nil { return err } res := pp.EncryptRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Encryptdata: encData, Nonce: nonce, } return c.Resp.SendJSON(res) }
// CreateWallet api for creating local wallet. // mode: POST // url: /api/v1/wallet?type=[:type]&seed=[:seed] // params: // type: bitcoin or skycoin // seed: wallet seed. func CreateWallet(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { // get coin type cp := r.FormValue("type") // get seed sd := r.FormValue("seed") if sd == "" { rlt = pp.MakeErrRes(errors.New("seed is required")) break } wlt, err := wallet.New(cp, sd) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } // bind the wallet to current account. a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } a.WltIDs[cp] = wlt.GetID() // update the account. account.Set(a) res := struct { Result *pp.Result `json:"result"` ID string `json:"id"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), ID: wlt.GetID(), } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// GetNewAddress account create new address for depositing. func GetNewAddress(ee engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { rlt := &pp.EmptyRes{} for { req := pp.GetDepositAddrReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // validate pubkey pubkey := req.GetPubkey() if err := validatePubkey(pubkey); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } at, err := ee.GetAccount(pubkey) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_NotExits) break } ct := req.GetCoinType() // get the new address for depositing addr := ee.GetNewAddress(ct) // add the new address to engin for watching it's utxos. at.AddDepositAddress(ct, addr) ee.WatchAddress(ct, addr) ds := pp.GetDepositAddrRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), CoinType: req.CoinType, Address: &addr, } return c.SendJSON(&ds) } return c.Error(rlt) } }
// GetOrders get order list. func GetOrders(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { rlt := &pp.EmptyRes{} for { req := pp.GetOrderReq{} if err := c.BindJSON(&req); err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } op, err := order.TypeFromStr(req.GetType()) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } ords, err := egn.GetOrders(req.GetCoinPair(), op, req.GetStart(), req.GetEnd()) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } res := pp.GetOrderRes{ CoinPair: req.CoinPair, Type: req.Type, Orders: make([]*pp.Order, len(ords)), } for i := range ords { res.Orders[i] = &pp.Order{ Id: &ords[i].ID, Type: req.Type, Price: &ords[i].Price, Amount: &ords[i].Amount, RestAmt: &ords[i].RestAmt, CreatedAt: &ords[i].CreatedAt, } } res.Result = pp.MakeResultWithCode(pp.ErrCode_Success) return c.SendJSON(&res) } return c.Error(rlt) } }
// UpdateCredit update credit. func UpdateCredit(ee engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.UpdateCreditReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // validate the dst pubkey. dstPubkey := req.GetDst() if err := validatePubkey(dstPubkey); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } // get account. a, err := ee.GetAccount(dstPubkey) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } // get coin type. if err := a.SetBalance(req.GetCoinType(), req.GetAmount()); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } ee.SaveAccount() res := pp.UpdateCreditRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), } return c.SendJSON(&res) } return c.Error(rlt) } }
// SignRawTx sign transaction. // mode: POST // url: /api/v1/signr_awtx?coin_type=[:coin_type]&rawtx=[:rawtx] // params: // coin_type: skycoin or bitcoin. // rawtx: raw transaction. func SignRawTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // check coin type cp := r.FormValue("coin_type") // get raw tx rawtx := r.FormValue("rawtx") if rawtx == "" { err := errors.New("rawtx is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } coin, err := se.GetCoin(cp) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } tx, err := coin.SignRawTx(rawtx, getPrivKey(cp)) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := struct { Result *pp.Result `json:"result"` Rawtx string `json:"rawtx"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Rawtx: tx, } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// GetTx get transaction by id. func GetTx(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.GetTxReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // brief validate transaction id if !coin.ValidateTxid(req.GetTxid()) { rlt = pp.MakeErrRes(errors.New("invalid transaction id")) break } tx, err := coin.GetTx(req.GetTxid()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := pp.GetTxRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), CoinType: req.CoinType, Tx: tx, } return c.SendJSON(&res) } return c.Error(rlt) } }
// GetUtxos gets bitcoin utxos of specific addresses. func (btc *Bitcoin) GetUtxos(addrs []string) (interface{}, error) { utxos, err := GetUnspentOutputs(addrs) if err != nil { return nil, err } btcUxs := make([]*pp.BtcUtxo, len(utxos)) for i, u := range utxos { btcUxs[i] = &pp.BtcUtxo{ Address: pp.PtrString(u.GetAddress()), Txid: pp.PtrString(u.GetTxid()), Vout: pp.PtrUint32(u.GetVout()), Amount: pp.PtrUint64(u.GetAmount()), } } var res = pp.GetUtxoRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), BtcUtxos: btcUxs, } return res, nil }
// GetKeys get keys of specific address in wallet. // mode: GET // url: /api/v1/wallet/address/keys?id=[:id]&address=[:address] func GetKeys(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get wallet id wltID := r.FormValue("id") if wltID == "" { rlt = pp.MakeErrRes(errors.New("no id")) break } // get address addr := r.FormValue("address") if addr == "" { rlt = pp.MakeErrRes(errors.New("no address")) break } p, s, err := wallet.GetKeypair(wltID, addr) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } res := struct { Result *pp.Result Pubkey string `json:"pubkey"` Seckey string `json:"seckey"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Pubkey: p, Seckey: s, } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// ActiveAccount active the specific account. // mode: PUT // url: /api/v1/account/state?pubkey=[:pubkey] func ActiveAccount(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get pubkey pk := r.FormValue("pubkey") if pk == "" { logger.Error("pubkey is empty") rlt = pp.MakeErrRes(errors.New("pubkey is empty")) break } // validate the pubkey if _, err := cipher.PubKeyFromHex(pk); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(errors.New("invalid pubkey")) break } // active the account if err := account.SetActive(pk); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := struct { Result *pp.Result }{ pp.MakeResultWithCode(pp.ErrCode_Success), } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// InjectTx inject transaction. func InjectTx(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var rlt *pp.EmptyRes for { req := pp.InjectTxnReq{} if err := c.BindJSON(&req); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // get coin gateway coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // inject tx. txid, err := coin.InjectTx(req.GetTx()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := pp.InjectTxnRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Txid: pp.PtrString(txid), } return c.SendJSON(&res) } return c.Error(rlt) } }
// Withdraw api for handlering withdraw process. func Withdraw(ee engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { rlt := &pp.EmptyRes{} for { reqParam, err := getWithdrawReqParams(c, ee) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } cp := reqParam.Values["cointype"].(string) a := reqParam.Values["account"].(account.Accounter) amt := reqParam.Values["amt"].(uint64) outAddr := reqParam.Values["outAddr"].(string) // get handler for creating txIns and txOuts base on the coin type. createTxInOut, err := getTxInOutHandler(cp) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // create txIns and txOuts. inOutSet, err := createTxInOut(ee, a, amt, outAddr) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } var success bool defer func() { if !success { // if not success, invoke the teardown, for putting back utxos, and reset balance. inOutSet.Teardown() } }() // get coin gateway. coin, err := ee.GetCoin(cp) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // create raw tx rawtx, err := coin.CreateRawTx(inOutSet.TxIns, inOutSet.TxOuts) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // sign the tx rawtx, err = coin.SignRawTx(rawtx, getAddrPrivKey(ee, cp)) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // inject the transaction. txid, err := coin.InjectTx(rawtx) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } success = true resp := pp.WithdrawalRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), NewTxid: &txid, } return c.SendJSON(&resp) } return c.Error(rlt) } }
func skyWithdrawl(nodeAddr string, rp *ReqParams) (*pp.WithdrawalRes, *pp.EmptyRes) { ee := rp.Values["engine"].(engine.Exchange) acnt := rp.Values["account"].(account.Accounter) amt := rp.Values["amt"].(uint64) ct := rp.Values["cointype"].(string) toAddr := rp.Values["toAddr"].(string) if err := skycoin.VerifyAmount(amt); err != nil { return nil, pp.MakeErrRes(err) } // verify the toAddr if _, err := cipher.DecodeBase58Address(toAddr); err != nil { return nil, pp.MakeErrRes(errors.New("invalid skycoin address")) } var success bool var skyTxRlt *SkyTxResult var err error if err := acnt.DecreaseBalance(ct, amt); err != nil { return nil, pp.MakeErrRes(err) } defer func() { if !success { go func() { if skyTxRlt != nil { ee.PutUtxos(skycoin.Type, skyTxRlt.UsingUtxos) } acnt.IncreaseBalance(ct, amt) }() } else { //TODO: handle the saving failure. ee.SaveAccount() } }() skyTxRlt, err = createSkyWithdrawTx(ee, amt, toAddr) if err != nil { return nil, pp.MakeErrRes(errors.New("failed to create withdrawal tx")) } rawtx, err := skyTxRlt.Tx.Serialize() if err != nil { return nil, pp.MakeErrRes(errors.New("skycoin tx serialize failed")) } newTxid, err := skycoin.BroadcastTx(nodeAddr, hex.EncodeToString(rawtx)) if err != nil { logger.Error(err.Error()) return nil, pp.MakeErrResWithCode(pp.ErrCode_BroadcastTxFail) } success = true if skyTxRlt.ChangeAddr != "" { logger.Debug("change address:%s", skyTxRlt.ChangeAddr) ee.WatchAddress(ct, skyTxRlt.ChangeAddr) } resp := pp.WithdrawalRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), NewTxid: &newTxid, } return &resp, nil }
// CreateRawTx create raw tx base on some utxos. // mode: POST // url: /api/v1/create_rawtx?coin_type=[:coin_type] // request json: // different in bitcoin and skycoin. func CreateRawTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes loop: for { // get coin type cp := r.FormValue("coin_type") // get request body params := rawTxParams{} if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } coin, err := se.GetCoin(cp) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } var rawtx string switch cp { case bitcoin.Type: outs := make([]bitcoin.TxOut, len(params.TxOuts)) for i, o := range params.TxOuts { outs[i].Addr = o.Addr outs[i].Value = o.Value } rawtx, err = coin.CreateRawTx(params.TxIns, outs) case skycoin.Type: outs := make([]skycoin.TxOut, len(params.TxOuts)) for i, o := range params.TxOuts { addr, err := cipher.DecodeBase58Address(o.Addr) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break loop } outs[i].Address = addr outs[i].Coins = o.Value outs[i].Hours = o.Hours } rawtx, err = coin.CreateRawTx(params.TxIns, outs) } if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } res := struct { Result *pp.Result `json:"result"` Rawtx string `json:"rawtx"` }{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), Rawtx: rawtx, } sendJSON(w, &res) return } sendJSON(w, rlt) } }
// CreateOrder create specifc order. func CreateOrder(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { rlt := &pp.EmptyRes{} req := &pp.OrderReq{} for { if err := c.BindJSON(req); err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } // validate pubkey pubkey := req.GetPubkey() if err := validatePubkey(pubkey); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } // get order type op, err := order.TypeFromStr(req.GetType()) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } // find the account acnt, err := egn.GetAccount(pubkey) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) logger.Error(err.Error()) break } cp, bal, err := needBalance(op, req) if err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } if acnt.GetBalance(cp) < bal { err := fmt.Errorf("%s balance is not sufficient", cp) rlt = pp.MakeErrRes(err) logger.Debug(err.Error()) break } var success bool if op == order.Bid { defer func() { if success { egn.SaveAccount() } else { acnt.IncreaseBalance(cp, bal) } }() // decrease the balance, in case of double use the coins. logger.Info("account:%s decrease %s:%d", acnt.GetID(), cp, bal) if err := acnt.DecreaseBalance(cp, bal); err != nil { rlt = pp.MakeErrRes(err) logger.Error(err.Error()) break } } odr := order.New(pubkey, op, req.GetPrice(), req.GetAmount()) oid, err := egn.AddOrder(req.GetCoinPair(), *odr) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } success = true logger.Info(fmt.Sprintf("new %s order:%d", op, oid)) res := pp.OrderRes{ Result: pp.MakeResultWithCode(pp.ErrCode_Success), OrderId: &oid, } return c.SendJSON(&res) } return c.Error(rlt) } }