// 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) } }
// 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) } }
// Authorize will decrypt the request, and it's a buildin middleware for skynet. func Authorize(servSeckey string) HandlerFunc { return func(c *Context) error { var ( req pp.EncryptReq rlt *pp.EmptyRes ) c.ServSeckey = servSeckey for { if c.UnmarshalReq(&req) == nil { // validate pubkey. if err := validatePubkey(req.GetPubkey()); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } pubkey, err := cipher.PubKeyFromHex(req.GetPubkey()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongPubkey) break } c.Pubkey = pubkey.Hex() seckey, err := cipher.SecKeyFromHex(servSeckey) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } key := cipher.ECDH(pubkey, seckey) data, err := cipher.Chacha20Decrypt(req.GetEncryptdata(), key, req.GetNonce()) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_UnAuthorized) break } ok, err := regexp.MatchString(`^\{.*\}$`, string(data)) if err != nil || !ok { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_UnAuthorized) break } c.Raw = data return c.Next() } rlt = pp.MakeErrRes(errors.New("bad request")) break } return c.Error(rlt) } }
// CreateOrder create order through exchange server. // mode: POST // url: /api/v1/account/order?coin_pair=[:coin_pair]&type=[:type]&price=[:price]&amt=[:amt] // params: // coin_pair: order coin pair. // type: order type, can be bid or ask. // price: price. // amt: amount. func CreateOrder(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { req, err := makeOrderReq(r) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req.Pubkey = pp.PtrString(a.Pubkey) var res pp.OrderRes if err := sknet.EncryGet(se.GetServAddr(), "/create/order", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, 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) } }
// GetRawTx get raw tx by txid. // mode: GET // url: /api/v1/rawtx?coin_type=[:coin_type]&txid=[:txid] func GetRawTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get coin type cp := r.FormValue("coin_type") if cp == "" { logger.Error("no coin type") rlt = pp.MakeErrRes(errors.New("no coin type")) break } // get txid txid := r.FormValue("txid") if txid == "" { logger.Error("no txid") rlt = pp.MakeErrRes(errors.New("no txid")) break } req := pp.GetRawTxReq{ CoinType: pp.PtrString(cp), Txid: pp.PtrString(txid), } var res pp.GetRawTxRes if err := sknet.EncryGet(se.GetServAddr(), "/get/rawtx", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// GetUtxos get unspent output of specific address. func GetUtxos(egn engine.Exchange) sknet.HandlerFunc { return func(c *sknet.Context) error { var req pp.GetUtxoReq var rlt *pp.EmptyRes for { if err := c.BindJSON(&req); err != nil { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) logger.Error(err.Error()) break } coin, err := egn.GetCoin(req.GetCoinType()) if err != nil { rlt = pp.MakeErrRes(err) logger.Error(err.Error()) break } res, err := coin.GetUtxos(req.GetAddresses()) if err != nil { rlt = pp.MakeErrRes(err) logger.Error(err.Error()) break } return c.SendJSON(&res) } return c.Error(rlt) } }
// GetCoins get supported coins from exchange server. func GetCoins(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req := pp.GetCoinsReq{ Pubkey: pp.PtrString(a.Pubkey), } var res pp.CoinsRes if err := sknet.EncryGet(se.GetServAddr(), "/get/coins", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } 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) } }
// 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) } }
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 }
func getOrders(se Servicer, tp string) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { cp := r.FormValue("coin_pair") st := r.FormValue("start") ed := r.FormValue("end") if cp == "" || st == "" || ed == "" || tp == "" { rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } start, err := strconv.ParseInt(st, 10, 64) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } end, err := strconv.ParseInt(ed, 10, 64) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } req := pp.GetOrderReq{ CoinPair: &cp, Type: pp.PtrString(tp), Start: &start, End: &end, } var res pp.GetOrderRes if err := sknet.EncryGet(se.GetServAddr(), "/get/orders", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } 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) } }
// Withdraw transaction. func Withdraw(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } cp := r.FormValue("coin_type") if cp == "" { err := errors.New("coin_type empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } amount := r.FormValue("amount") if amount == "" { rlt = pp.MakeErrRes(errors.New("amount empty")) break } toAddr := r.FormValue("toaddr") if toAddr == "" { rlt = pp.MakeErrRes(errors.New("toaddr empty")) break } amt, err := strconv.ParseUint(amount, 10, 64) if err != nil { rlt = pp.MakeErrRes(err) break } req := pp.WithdrawalReq{ Pubkey: &a.Pubkey, CoinType: &cp, Coins: &amt, OutputAddress: &toAddr, } var res pp.WithdrawalRes if err := sknet.EncryGet(se.GetServAddr(), "/withdrawl", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, 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) } }
// process handle the incoming connection, will read request from conn, setup the middle, // and dispatch the request. func process(id int, c net.Conn, engine *Engine) { logger.Debug("[%d] working", id) r := &Request{} w := &Response{c: c} defer func() { // catch panic if r := recover(); r != nil { logger.Critical("%s", r) debug.PrintStack() } c.Close() logger.Debug("[%d] worker done", id) }() var err error var context Context for { r.Reset() context.Reset() context.Resp = w if err = Read(c, r); err != nil { if err.Error() != "EOF" { logger.Error("%v", err) context.Error(pp.MakeErrRes(err)) } return } context.Request = r // check if the path belongs to group. hds, find := engine.findGroupHandlers(r.GetPath()) if find { context.handlers = append(engine.handlers, hds...) } else { if h, ok := engine.handlerFunc[r.GetPath()]; ok { context.handlers = append(engine.handlers, h) } else { logger.Error("no handler for path: %s", r.GetPath()) res := pp.MakeErrResWithCode(pp.ErrCode_ServerError) context.Error(res) return } } if err := context.handlers[0](&context); err != nil { logger.Error(err.Error()) return } } }
// IsAdmin middleware for checking if the account is admin. func IsAdmin(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 } if !ee.IsAdmin(req.GetPubkey()) { logger.Error("not admin") rlt = pp.MakeErrResWithCode(pp.ErrCode_UnAuthorized) break } return c.Next() } return c.Error(rlt) } }
// GetWalletBalance get local wallet balance. // mode: GET // url: /api/v1/wallet/balance?id=[:id] // params: // id: wallet id. func GetWalletBalance(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 == "" { err := errors.New("id is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // get addresses in wallet. addrs, err := wallet.GetAddresses(id) if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } if len(addrs) == 0 { res := pp.GetAddrBalanceRes{ Result: pp.MakeResult(pp.ErrCode_NotExits, "wallet have no address"), } sendJSON(w, &res) return } cp := strings.Split(id, "_")[0] // get address balance. req := pp.GetAddrBalanceReq{ CoinType: pp.PtrString(cp), Addrs: pp.PtrString(strings.Join(addrs, ",")), } var res pp.GetAddrBalanceRes if err := sknet.EncryGet(se.GetServAddr(), "/get/address/balance", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, 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)) } } }
// 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) } }
// 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 get utxos through exchange server. func GetUtxos(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { cp := r.FormValue("coin_type") if cp == "" { logger.Error("coin type empty") rlt = pp.MakeErrRes(errors.New("coin type empty")) break } addrs := r.FormValue("addrs") if addrs == "" { logger.Error("addrs empty") rlt = pp.MakeErrRes(errors.New("addrs empty")) break } addrArray := strings.Split(addrs, ",") for i, addr := range addrArray { addrArray[i] = strings.Trim(addr, " ") } req := pp.GetUtxoReq{ CoinType: pp.PtrString(cp), Addresses: addrArray, } var res pp.GetUtxoRes if err := sknet.EncryGet(se.GetServAddr(), "/get/utxos", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// 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) } }
// InjectTx broadcast transaction. // mode: POST // url: /api/v1/inject_rawtx?rawtx=[:rawtx]&coin_type=[:coin_type] // params: // rawtx: raw tx that's going to be injected. // coin_type: skycoin or bitcoin. func InjectTx(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { var rlt *pp.EmptyRes for { // get tx rawtx := r.FormValue("rawtx") if rawtx == "" { err := errors.New("rawtx is empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } // get coin type cp := r.FormValue("coin_type") if cp == "" { logger.Error("empty coin type") rlt = pp.MakeErrRes(errors.New("empty coin type")) break } req := pp.InjectTxnReq{ CoinType: pp.PtrString(cp), Tx: pp.PtrString(rawtx), } var res pp.InjectTxnRes if err := sknet.EncryGet(se.GetServAddr(), "/inject/tx", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// GetDepositAddress get deposit address from exchange server. func GetDepositAddress(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { rlt := &pp.EmptyRes{} for { a, err := account.GetActive() if err != nil { logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } cp := r.FormValue("coin_type") if cp == "" { err := errors.New("coin type empty") logger.Error(err.Error()) rlt = pp.MakeErrRes(err) break } req := pp.GetDepositAddrReq{ Pubkey: pp.PtrString(a.Pubkey), CoinType: pp.PtrString(cp), } var res pp.GetDepositAddrRes if err := sknet.EncryGet(se.GetServAddr(), "/create/deposit_address", req, &res); err != nil { logger.Error(err.Error()) rlt = pp.MakeErrResWithCode(pp.ErrCode_ServerError) break } sendJSON(w, res) return } sendJSON(w, rlt) } }
// CreateAccount handle the request of creating account. func CreateAccount(se Servicer) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { // generate account pubkey/privkey pair, pubkey is the account id. errRlt := &pp.EmptyRes{} for { a := account.New() r := pp.CreateAccountReq{ Pubkey: pp.PtrString(a.Pubkey), } res := pp.CreateAccountRes{} if err := sknet.EncryGet(se.GetServAddr(), "/create/account", r, &res); err != nil { logger.Error(err.Error()) errRlt = pp.MakeErrResWithCode(pp.ErrCode_WrongRequest) break } // acntRes := res.(*pp.CreateAccountRes) if !res.GetResult().GetSuccess() { sendJSON(w, res) } else { ret := struct { Result pp.Result `json:"result"` Pubkey string `json:"pubkey"` CreatedAt int64 `json:"created_at"` }{ Result: *res.Result, Pubkey: a.Pubkey, CreatedAt: res.GetCreatedAt(), } account.Set(a) sendJSON(w, &ret) } return } sendJSON(w, errRlt) } }
// 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) } }
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 }
// 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) } }