mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-21 15:10:12 +00:00
exchanges/engine: Add multichain deposit/withdrawal support (#794)
* Add exchange multichain support * Start tidying up * Add multichain transfer support for Bitfinex and fix poloniex bug * Add Coinbene multichain support * Start adjusting the deposit address manager * Fix deposit tests and further enhancements * Cleanup * Add bypass flag, expand tests plus error coverage for Huobi Adjust helpers * Address nitterinos * BFX wd changes * Address nitterinos * Minor fixes rebasing on master * Fix BFX acceptableMethods test * Add some TO-DOs for 2 tests WRT races * Fix acceptableMethods test round 2 * Address nitterinos
This commit is contained in:
@@ -38,19 +38,9 @@ const (
|
||||
bitstampAPIMarket = "market"
|
||||
bitstampAPIWithdrawalRequests = "withdrawal_requests"
|
||||
bitstampAPIOpenWithdrawal = "withdrawal/open"
|
||||
bitstampAPIBitcoinWithdrawal = "bitcoin_withdrawal"
|
||||
bitstampAPILTCWithdrawal = "ltc_withdrawal"
|
||||
bitstampAPIETHWithdrawal = "eth_withdrawal"
|
||||
bitstampAPIBCHWithdrawal = "bch_withdrawal"
|
||||
bitstampAPIBitcoinDeposit = "bitcoin_deposit_address"
|
||||
bitstampAPILitecoinDeposit = "ltc_address"
|
||||
bitstampAPIEthereumDeposit = "eth_address"
|
||||
bitstampAPIBitcoinCashDeposit = "bch_address"
|
||||
bitstampAPIUnconfirmedBitcoin = "unconfirmed_btc"
|
||||
bitstampAPITransferToMain = "transfer-to-main"
|
||||
bitstampAPITransferFromMain = "transfer-from-main"
|
||||
bitstampAPIXrpWithdrawal = "xrp_withdrawal"
|
||||
bitstampAPIXrpDeposit = "xrp_address"
|
||||
bitstampAPIReturnType = "string"
|
||||
bitstampAPITradingPairsInfo = "trading-pairs-info"
|
||||
bitstampOHLC = "ohlc"
|
||||
@@ -421,38 +411,26 @@ func (b *Bitstamp) GetWithdrawalRequests(ctx context.Context, timedelta int64) (
|
||||
// address - The wallet address of the cryptocurrency
|
||||
// symbol - the type of crypto ie "ltc", "btc", "eth"
|
||||
// destTag - only for XRP default to ""
|
||||
// instant - only for bitcoins
|
||||
func (b *Bitstamp) CryptoWithdrawal(ctx context.Context, amount float64, address, symbol, destTag string, instant bool) (CryptoWithdrawalResponse, error) {
|
||||
func (b *Bitstamp) CryptoWithdrawal(ctx context.Context, amount float64, address, symbol, destTag string) (*CryptoWithdrawalResponse, error) {
|
||||
var req = url.Values{}
|
||||
req.Add("amount", strconv.FormatFloat(amount, 'f', -1, 64))
|
||||
req.Add("address", address)
|
||||
resp := CryptoWithdrawalResponse{}
|
||||
var endpoint string
|
||||
|
||||
switch strings.ToLower(symbol) {
|
||||
case currency.BTC.Lower().String():
|
||||
if instant {
|
||||
req.Add("instant", "1")
|
||||
} else {
|
||||
req.Add("instant", "0")
|
||||
var endpoint string
|
||||
switch strings.ToUpper(symbol) {
|
||||
case currency.XLM.String():
|
||||
if destTag != "" {
|
||||
req.Add("memo_id", destTag)
|
||||
}
|
||||
endpoint = bitstampAPIBitcoinWithdrawal
|
||||
case currency.LTC.Lower().String():
|
||||
endpoint = bitstampAPILTCWithdrawal
|
||||
case currency.ETH.Lower().String():
|
||||
endpoint = bitstampAPIETHWithdrawal
|
||||
case currency.XRP.Lower().String():
|
||||
case currency.XRP.String():
|
||||
if destTag != "" {
|
||||
req.Add("destination_tag", destTag)
|
||||
}
|
||||
endpoint = bitstampAPIXrpWithdrawal
|
||||
case currency.BCH.Lower().String():
|
||||
endpoint = bitstampAPIBCHWithdrawal
|
||||
default:
|
||||
return resp, errors.New("incorrect symbol")
|
||||
}
|
||||
|
||||
return resp, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, endpoint, false, req, &resp)
|
||||
var resp CryptoWithdrawalResponse
|
||||
endpoint = strings.ToLower(symbol) + "_withdrawal"
|
||||
return &resp, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, endpoint, true, req, &resp)
|
||||
}
|
||||
|
||||
// OpenBankWithdrawal Opens a bank withdrawal request (SEPA or international)
|
||||
@@ -506,36 +484,10 @@ func (b *Bitstamp) OpenInternationalBankWithdrawal(ctx context.Context, amount f
|
||||
|
||||
// GetCryptoDepositAddress returns a depositing address by crypto
|
||||
// crypto - example "btc", "ltc", "eth", "xrp" or "bch"
|
||||
func (b *Bitstamp) GetCryptoDepositAddress(ctx context.Context, crypto currency.Code) (string, error) {
|
||||
var resp string
|
||||
v2Resp := struct {
|
||||
Address string `json:"address"`
|
||||
}{}
|
||||
|
||||
switch crypto {
|
||||
case currency.BTC:
|
||||
return resp,
|
||||
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIBitcoinDeposit, false, nil, &resp)
|
||||
|
||||
case currency.LTC:
|
||||
return v2Resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPILitecoinDeposit, true, nil, &v2Resp)
|
||||
|
||||
case currency.ETH:
|
||||
return v2Resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIEthereumDeposit, true, nil, &v2Resp)
|
||||
|
||||
case currency.XRP:
|
||||
return v2Resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIXrpDeposit, true, nil, &v2Resp)
|
||||
|
||||
case currency.BCH:
|
||||
return v2Resp.Address,
|
||||
b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, bitstampAPIBitcoinCashDeposit, true, nil, &v2Resp)
|
||||
|
||||
default:
|
||||
return resp, fmt.Errorf("unsupported cryptocurrency string %s", crypto)
|
||||
}
|
||||
func (b *Bitstamp) GetCryptoDepositAddress(ctx context.Context, crypto currency.Code) (*DepositAddress, error) {
|
||||
path := crypto.Lower().String() + "_address"
|
||||
var resp DepositAddress
|
||||
return &resp, b.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, path, true, nil, &resp)
|
||||
}
|
||||
|
||||
// GetUnconfirmedBitcoinDeposits returns unconfirmed transactions
|
||||
@@ -673,31 +625,29 @@ func (b *Bitstamp) SendAuthenticatedHTTPRequest(ctx context.Context, ep exchange
|
||||
}
|
||||
|
||||
errCap := struct {
|
||||
Error string `json:"error"`
|
||||
Status string `json:"status"`
|
||||
Reason interface{} `json:"reason"`
|
||||
Error string `json:"error"` // v1 errors
|
||||
Status string `json:"status"` // v2 errors
|
||||
Reason interface{} `json:"reason"` // v2 errors
|
||||
}{}
|
||||
if err := json.Unmarshal(interim, &errCap); err == nil {
|
||||
if errCap.Error != "" {
|
||||
return errors.New(errCap.Error)
|
||||
}
|
||||
if data, ok := errCap.Reason.(map[string][]string); ok {
|
||||
var details strings.Builder
|
||||
for x := range data {
|
||||
details.WriteString(strings.Join(data[x], ""))
|
||||
if errCap.Error != "" || errCap.Status == errStr {
|
||||
if errCap.Error != "" { // v1 errors
|
||||
return errors.New(errCap.Error)
|
||||
}
|
||||
switch data := errCap.Reason.(type) { // v2 errors
|
||||
case map[string]interface{}:
|
||||
var details strings.Builder
|
||||
for k, v := range data {
|
||||
details.WriteString(fmt.Sprintf("%s: %v", k, v))
|
||||
}
|
||||
return errors.New(details.String())
|
||||
case string:
|
||||
return errors.New(data)
|
||||
default:
|
||||
return errors.New(errCap.Status)
|
||||
}
|
||||
return errors.New(details.String())
|
||||
}
|
||||
|
||||
if data, ok := errCap.Reason.(string); ok {
|
||||
return errors.New(data)
|
||||
}
|
||||
|
||||
if errCap.Status != "" {
|
||||
return errors.New(errCap.Status)
|
||||
}
|
||||
}
|
||||
|
||||
return json.Unmarshal(interim, result)
|
||||
}
|
||||
|
||||
|
||||
@@ -466,6 +466,7 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
|
||||
withdrawCryptoRequest := withdraw.Request{
|
||||
Exchange: b.Name,
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
@@ -575,7 +576,7 @@ func TestWithdrawInternationalBank(t *testing.T) {
|
||||
func TestGetDepositAddress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := b.GetDepositAddress(context.Background(), currency.BTC, "")
|
||||
_, err := b.GetDepositAddress(context.Background(), currency.XRP, "", "")
|
||||
switch {
|
||||
case areTestAPIKeysSet() && customerID != "" && err != nil && !mockTests:
|
||||
t.Error("GetDepositAddress error", err)
|
||||
|
||||
@@ -133,6 +133,12 @@ type CancelOrder struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// DepositAddress holds the deposit info
|
||||
type DepositAddress struct {
|
||||
Address string `json:"address"`
|
||||
DestinationTag int64 `json:"destination_tag"`
|
||||
}
|
||||
|
||||
// WithdrawalRequests holds request information on withdrawals
|
||||
type WithdrawalRequests struct {
|
||||
OrderID int64 `json:"id"`
|
||||
@@ -147,15 +153,12 @@ type WithdrawalRequests struct {
|
||||
|
||||
// CryptoWithdrawalResponse response from a crypto withdrawal request
|
||||
type CryptoWithdrawalResponse struct {
|
||||
ID string `json:"id"`
|
||||
Error map[string][]string `json:"error"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// FIATWithdrawalResponse response from a fiat withdrawal request
|
||||
type FIATWithdrawalResponse struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Reason map[string][]string `json:"reason"`
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// UnconfirmedBTCTransactions holds address information about unconfirmed
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"errors"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -15,6 +14,7 @@ import (
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/deposit"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
||||
@@ -590,8 +590,21 @@ func (b *Bitstamp) GetOrderInfo(ctx context.Context, orderID string, pair curren
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (b *Bitstamp) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _ string) (string, error) {
|
||||
return b.GetCryptoDepositAddress(ctx, cryptocurrency)
|
||||
func (b *Bitstamp) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, _ string) (*deposit.Address, error) {
|
||||
addr, err := b.GetCryptoDepositAddress(ctx, cryptocurrency)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var tag string
|
||||
if addr.DestinationTag != 0 {
|
||||
tag = strconv.FormatInt(addr.DestinationTag, 10)
|
||||
}
|
||||
|
||||
return &deposit.Address{
|
||||
Address: addr.Address,
|
||||
Tag: tag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
@@ -604,21 +617,13 @@ func (b *Bitstamp) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawRequ
|
||||
withdrawRequest.Amount,
|
||||
withdrawRequest.Crypto.Address,
|
||||
withdrawRequest.Currency.String(),
|
||||
withdrawRequest.Crypto.AddressTag,
|
||||
true)
|
||||
withdrawRequest.Crypto.AddressTag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(resp.Error) != 0 {
|
||||
var details strings.Builder
|
||||
for x := range resp.Error {
|
||||
details.WriteString(strings.Join(resp.Error[x], ""))
|
||||
}
|
||||
return nil, errors.New(details.String())
|
||||
}
|
||||
|
||||
return &withdraw.ExchangeResponse{
|
||||
ID: resp.ID,
|
||||
ID: strconv.FormatInt(resp.ID, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -643,17 +648,9 @@ func (b *Bitstamp) WithdrawFiatFunds(ctx context.Context, withdrawRequest *withd
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Status == errStr {
|
||||
var details strings.Builder
|
||||
for x := range resp.Reason {
|
||||
details.WriteString(strings.Join(resp.Reason[x], ""))
|
||||
}
|
||||
return nil, errors.New(details.String())
|
||||
}
|
||||
|
||||
return &withdraw.ExchangeResponse{
|
||||
ID: resp.ID,
|
||||
Status: resp.Status,
|
||||
ID: strconv.FormatInt(resp.ID, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -684,17 +681,9 @@ func (b *Bitstamp) WithdrawFiatFundsToInternationalBank(ctx context.Context, wit
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Status == errStr {
|
||||
var details strings.Builder
|
||||
for x := range resp.Reason {
|
||||
details.WriteString(strings.Join(resp.Reason[x], ""))
|
||||
}
|
||||
return nil, errors.New(details.String())
|
||||
}
|
||||
|
||||
return &withdraw.ExchangeResponse{
|
||||
ID: resp.ID,
|
||||
Status: resp.Status,
|
||||
ID: strconv.FormatInt(resp.ID, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user