Ejemplo n.º 1
0
// New create sknet engine and register handlers.
func New(ee engine.Exchange, quit chan bool) *sknet.Engine {
	engine := sknet.New(ee.GetSecKey(), quit)
	engine.Use(sknet.Logger())

	engine.Register("/create/account", api.CreateAccount(ee))
	engine.Register("/create/deposit_address", api.GetNewAddress(ee))
	engine.Register("/get/account/balance", api.GetAccountBalance(ee))
	engine.Register("/get/address/balance", api.GetAddrBalance(ee))
	engine.Register("/withdrawl", api.Withdraw(ee))
	engine.Register("/create/order", api.CreateOrder(ee))
	engine.Register("/get/coins", api.GetCoins(ee))
	engine.Register("/get/orders", api.GetOrders(ee))

	// utxos handler
	engine.Register("/get/utxos", api.GetUtxos(ee))

	// output history handler
	engine.Register("/get/output", api.GetOutput(ee))

	// transaction handler
	engine.Register("/inject/tx", api.InjectTx(ee))
	engine.Register("/get/tx", api.GetTx(ee))
	engine.Register("/get/rawtx", api.GetRawTx(ee))

	engine.Register("/admin/update/credit", api.UpdateCredit(ee))

	return engine
}
Ejemplo n.º 2
0
// 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)
	}
}
Ejemplo n.º 3
0
// 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)
	}
}
Ejemplo n.º 4
0
// 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)
	}
}
Ejemplo n.º 5
0
// 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)
	}
}
Ejemplo n.º 6
0
// 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)
	}
}
Ejemplo n.º 7
0
// createBtcWithdrawTx create withdraw transaction.
// amount is the number of coins that want to withdraw.
// toAddr is the address that the coins will be sent to.
func createBtcWithdrawTx(egn engine.Exchange, amount uint64, toAddr string) (*BtcTxResult, error) {
	uxs, err := egn.ChooseUtxos(bitcoin.Type, amount+egn.GetBtcFee(), ChooseUtxoTm)
	if err != nil {
		return nil, err
	}
	utxos := uxs.([]bitcoin.Utxo)

	for _, u := range utxos {
		logger.Debug("using utxos: txid:%s vout:%d addr:%s", u.GetTxid(), u.GetVout(), u.GetAddress())
	}

	var success bool
	defer func() {
		if !success {
			// put utxos back to pool if withdraw failed.
			go func() { egn.PutUtxos(bitcoin.Type, utxos) }()
		}
	}()

	var totalAmounts uint64
	for _, u := range utxos {
		totalAmounts += u.GetAmount()
	}
	fee := egn.GetBtcFee()
	outAddrs := []bitcoin.TxOut{}
	chgAmt := totalAmounts - fee - amount
	chgAddr := ""
	if chgAmt > 0 {
		// generate a change address
		chgAddr = egn.GetNewAddress(bitcoin.Type)
		outAddrs = append(outAddrs,
			bitcoin.TxOut{Addr: toAddr, Value: amount},
			bitcoin.TxOut{Addr: chgAddr, Value: chgAmt})
	} else {
		outAddrs = append(outAddrs, bitcoin.TxOut{Addr: toAddr, Value: amount})
	}
	// change utxo to UtxoWithkey
	utxoKeys, err := makeBtcUtxoWithkeys(utxos, egn)
	if err != nil {
		return nil, err
	}

	logger.Debug("creating transaction...")
	tx, err := bitcoin.NewTransaction(utxoKeys, outAddrs)
	if err != nil {
		logger.Error(err.Error())
		return nil, err
	}
	success = true
	rlt := BtcTxResult{
		Tx:         tx,
		UsingUtxos: utxos[:],
		ChangeAddr: chgAddr,
	}
	return &rlt, nil
}
Ejemplo n.º 8
0
func makeBtcUtxoWithkeys(utxos []bitcoin.Utxo, egn engine.Exchange) ([]bitcoin.UtxoWithkey, error) {
	utxoks := make([]bitcoin.UtxoWithkey, len(utxos))
	for i, u := range utxos {
		key, err := egn.GetAddrPrivKey(bitcoin.Type, u.GetAddress())
		if err != nil {
			return []bitcoin.UtxoWithkey{}, err
		}
		utxoks[i] = bitcoin.NewUtxoWithKey(u, key)
	}
	return utxoks, nil
}
Ejemplo n.º 9
0
// 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)
	}
}
Ejemplo n.º 10
0
// 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)
	}
}
Ejemplo n.º 11
0
// 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)
	}
}
Ejemplo n.º 12
0
// 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)
	}
}
Ejemplo n.º 13
0
// 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)
	}
}
Ejemplo n.º 14
0
func getWithdrawReqParams(c *sknet.Context, ee engine.Exchange) (*ReqParams, error) {
	rp := NewReqParams()
	req := pp.WithdrawalReq{}
	if err := c.BindJSON(&req); err != nil {
		return nil, err
	}

	// validate pubkey
	pubkey := req.GetPubkey()
	if err := validatePubkey(pubkey); err != nil {
		return nil, err
	}

	a, err := ee.GetAccount(pubkey)
	if err != nil {
		return nil, err
	}

	rp.Values["account"] = a
	rp.Values["cointype"] = req.GetCoinType()
	rp.Values["amt"] = req.GetCoins()
	rp.Values["outAddr"] = req.GetOutputAddress()
	return rp, nil
}
Ejemplo n.º 15
0
// 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)
	}
}
Ejemplo n.º 16
0
// 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)
	}
}
Ejemplo n.º 17
0
// 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)
	}
}
Ejemplo n.º 18
0
func createSkyWithdrawTx(egn engine.Exchange, amount uint64, toAddr string) (*SkyTxResult, error) {
	uxs, err := egn.ChooseUtxos(skycoin.Type, amount, ChooseUtxoTm)
	if err != nil {
		return nil, err
	}
	utxos := uxs.([]skycoin.Utxo)

	for _, u := range utxos {
		logger.Debug("using skycoin utxos:%s", u.GetHash())
	}

	var success bool
	defer func() {
		if !success {
			go func() { egn.PutUtxos(skycoin.Type, utxos) }()
		}
	}()

	var totalAmounts uint64
	var totalHours uint64
	for _, u := range utxos {
		totalAmounts += u.GetCoins()
		totalHours += u.GetHours()
	}

	outAddrs := []skycoin.TxOut{}
	chgAmt := totalAmounts - amount
	chgHours := totalHours / 4
	chgAddr := ""
	if chgAmt > 0 {
		// generate a change address
		chgAddr = egn.GetNewAddress(skycoin.Type)
		outAddrs = append(outAddrs,
			skycoin.MakeUtxoOutput(toAddr, amount, chgHours/2),
			skycoin.MakeUtxoOutput(chgAddr, chgAmt, chgHours/2))
	} else {
		outAddrs = append(outAddrs, skycoin.MakeUtxoOutput(toAddr, amount, chgHours/2))
	}

	keys := make([]cipher.SecKey, len(utxos))
	for i, u := range utxos {
		k, err := egn.GetAddrPrivKey(skycoin.Type, u.GetAddress())
		if err != nil {
			panic(err)
		}
		keys[i] = cipher.MustSecKeyFromHex(k)
	}

	logger.Debug("creating skycoin transaction...")
	tx := skycoin.NewTransaction(utxos, keys, outAddrs)
	if err := tx.Verify(); err != nil {
		return nil, err
	}

	success = true
	rlt := SkyTxResult{
		Tx:         tx,
		UsingUtxos: utxos[:],
		ChangeAddr: chgAddr,
	}
	return &rlt, nil
}
Ejemplo n.º 19
0
func createBtcTxInOut(ee engine.Exchange, a account.Accounter, amount uint64, outAddr string) (*txInOutResult, error) {
	var rlt txInOutResult
	// verify the outAddr
	if _, err := cipher.BitcoinDecodeBase58Address(outAddr); err != nil {
		return nil, errors.New("invalid bitcoin address")
	}

	var err error
	// decrease balance and check if the balance is sufficient.
	if err := a.DecreaseBalance("bitcoin", amount+ee.GetBtcFee()); err != nil {
		return nil, err
	}

	var utxos []bitcoin.Utxo

	// choose sufficient utxos.
	uxs, err := ee.ChooseUtxos("bitcoin", amount+ee.GetBtcFee(), ChooseUtxoTm)
	if err != nil {
		return nil, err
	}
	utxos = uxs.([]bitcoin.Utxo)

	for _, u := range utxos {
		logger.Debug("using utxos: txid:%s vout:%d addr:%s", u.GetTxid(), u.GetVout(), u.GetAddress())
		rlt.TxIns = append(rlt.TxIns, coin.TxIn{
			Txid: u.GetTxid(),
			Vout: u.GetVout(),
		})
	}

	var totalAmounts uint64
	for _, u := range utxos {
		totalAmounts += u.GetAmount()
	}
	fee := ee.GetBtcFee()
	txOuts := []bitcoin.TxOut{}
	chgAmt := totalAmounts - fee - amount
	chgAddr := ""
	if chgAmt > 0 {
		// generate a change address
		chgAddr = ee.GetNewAddress(bitcoin.Type)
		txOuts = append(txOuts,
			bitcoin.TxOut{Addr: outAddr, Value: amount},
			bitcoin.TxOut{Addr: chgAddr, Value: chgAmt})
	} else {
		txOuts = append(txOuts, bitcoin.TxOut{Addr: outAddr, Value: amount})
	}

	rlt.TxOuts = txOuts
	rlt.Teardown = func() {
		a.IncreaseBalance(bitcoin.Type, amount+ee.GetBtcFee())
		ee.PutUtxos(bitcoin.Type, utxos)
	}

	return &rlt, nil
}
Ejemplo n.º 20
0
func getAddrPrivKey(ee engine.Exchange, cp string) coin.GetPrivKey {
	return func(addr string) (string, error) {
		return ee.GetAddrPrivKey(cp, addr)
	}
}