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 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 }
func getBalanceExplr(addrs []string) (uint64, error) { var wg sync.WaitGroup valueChan := make(chan balanceResult, len(addrs)) for _, addr := range addrs { // verify the address. _, err := cipher.BitcoinDecodeBase58Address(addr) if err != nil { return 0, err } wg.Add(1) go func(addr string, wg *sync.WaitGroup, vc chan balanceResult) { defer wg.Done() d, err := getDataOfUrl(fmt.Sprintf("https://blockexplorer.com/api/addr/%s/balance", addr)) if err != nil { vc <- balanceResult{0, err} return } v, err := strconv.ParseUint(string(d), 10, 64) if err != nil { vc <- balanceResult{0, err} } vc <- balanceResult{v, nil} }(addr, &wg, valueChan) } wg.Wait() close(valueChan) var totalBal uint64 for v := range valueChan { if v.err != nil { return 0, v.err } totalBal += v.balance } return totalBal, nil }
func (bn bitcoinCli) ValidateAddr(address string) error { _, err := cipher.BitcoinDecodeBase58Address(address) return err }
func validateAddress(addr string) bool { _, err := cipher.BitcoinDecodeBase58Address(addr) return err == nil }