mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-20 23:16:49 +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:
@@ -59,10 +59,6 @@ const (
|
||||
marginAccountInfo = "/sapi/v1/margin/account"
|
||||
|
||||
// Withdraw API endpoints
|
||||
withdrawEndpoint = "/wapi/v3/withdraw.html"
|
||||
depositHistory = "/wapi/v3/depositHistory.html"
|
||||
withdrawalHistory = "/wapi/v3/withdrawHistory.html"
|
||||
depositAddress = "/wapi/v3/depositAddress.html"
|
||||
accountStatus = "/wapi/v3/accountStatus.html"
|
||||
systemStatus = "/wapi/v3/systemStatus.html"
|
||||
dustLog = "/wapi/v3/userAssetDribbletLog.html"
|
||||
@@ -71,7 +67,15 @@ const (
|
||||
undocumentedInterestHistory = "/gateway-api/v1/public/isolated-margin/pair/vip-level"
|
||||
undocumentedCrossMarginInterestHistory = "/gateway-api/v1/friendly/margin/vip/spec/list-all"
|
||||
|
||||
defaultRecvWindow = 5 * time.Second
|
||||
// Wallet endpoints
|
||||
allCoinsInfo = "/sapi/v1/capital/config/getall"
|
||||
withdrawEndpoint = "/sapi/v1/capital/withdraw/apply"
|
||||
depositHistory = "/sapi/v1/capital/deposit/hisrec"
|
||||
withdrawHistory = "/sapi/v1/capital/withdraw/history"
|
||||
depositAddress = "/sapi/v1/capital/deposit/address"
|
||||
|
||||
defaultRecvWindow = 5 * time.Second
|
||||
binanceSAPITimeLayout = "2006-01-02 15:04:05"
|
||||
)
|
||||
|
||||
// GetInterestHistory gets interest history for currency/currencies provided
|
||||
@@ -906,98 +910,185 @@ func getCryptocurrencyWithdrawalFee(c currency.Code) float64 {
|
||||
return WithdrawalFees[c]
|
||||
}
|
||||
|
||||
// WithdrawCrypto sends cryptocurrency to the address of your choosing
|
||||
func (b *Binance) WithdrawCrypto(ctx context.Context, asset, address, addressTag, name, amount string) (string, error) {
|
||||
var resp WithdrawResponse
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("asset", asset)
|
||||
params.Set("address", address)
|
||||
params.Set("amount", amount)
|
||||
if len(name) > 0 {
|
||||
params.Set("name", name)
|
||||
}
|
||||
if len(addressTag) > 0 {
|
||||
params.Set("addressTag", addressTag)
|
||||
}
|
||||
|
||||
// GetAllCoinsInfo returns details about all supported coins
|
||||
func (b *Binance) GetAllCoinsInfo(ctx context.Context) ([]CoinInfo, error) {
|
||||
var resp []CoinInfo
|
||||
if err := b.SendAuthHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
http.MethodPost, withdrawEndpoint,
|
||||
params, spotDefaultRate, &resp); err != nil {
|
||||
http.MethodGet,
|
||||
allCoinsInfo,
|
||||
nil,
|
||||
spotDefaultRate,
|
||||
&resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// WithdrawCrypto sends cryptocurrency to the address of your choosing
|
||||
func (b *Binance) WithdrawCrypto(ctx context.Context, cryptoAsset, withdrawOrderID, network, address, addressTag, name, amount string, transactionFeeFlag bool) (string, error) {
|
||||
if cryptoAsset == "" || address == "" || amount == "" {
|
||||
return "", errors.New("asset, address and amount must not be empty")
|
||||
}
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("coin", cryptoAsset)
|
||||
params.Set("address", address)
|
||||
params.Set("amount", amount)
|
||||
|
||||
// optional params
|
||||
if withdrawOrderID != "" {
|
||||
params.Set("withdrawOrderId", withdrawOrderID)
|
||||
}
|
||||
if network != "" {
|
||||
params.Set("network", network)
|
||||
}
|
||||
if addressTag != "" {
|
||||
params.Set("addressTag", addressTag)
|
||||
}
|
||||
if transactionFeeFlag {
|
||||
params.Set("transactionFeeFlag", "true")
|
||||
}
|
||||
if name != "" {
|
||||
params.Set("name", url.QueryEscape(name))
|
||||
}
|
||||
|
||||
var resp WithdrawResponse
|
||||
if err := b.SendAuthHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
http.MethodPost,
|
||||
withdrawEndpoint,
|
||||
params,
|
||||
spotDefaultRate,
|
||||
&resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if !resp.Success {
|
||||
return resp.ID, errors.New(resp.Msg)
|
||||
if resp.ID == "" {
|
||||
return "", errors.New("ID is nil")
|
||||
}
|
||||
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
// WithdrawStatus gets the status of recent withdrawals
|
||||
// DepositHistory returns the deposit history based on the supplied params
|
||||
// status `param` used as string to prevent default value 0 (for int) interpreting as EmailSent status
|
||||
func (b *Binance) WithdrawStatus(ctx context.Context, c currency.Code, status string, startTime, endTime int64) ([]WithdrawStatusResponse, error) {
|
||||
var response struct {
|
||||
Success bool `json:"success"`
|
||||
WithdrawList []WithdrawStatusResponse `json:"withdrawList"`
|
||||
}
|
||||
func (b *Binance) DepositHistory(ctx context.Context, c currency.Code, status string, startTime, endTime time.Time, offset, limit int) ([]DepositHistory, error) {
|
||||
var response []DepositHistory
|
||||
|
||||
params := url.Values{}
|
||||
params.Set("asset", c.String())
|
||||
if !c.IsEmpty() {
|
||||
params.Set("coin", c.String())
|
||||
}
|
||||
|
||||
if status != "" {
|
||||
i, err := strconv.Atoi(status)
|
||||
if err != nil {
|
||||
return response.WithdrawList, fmt.Errorf("wrong param (status): %s. Error: %v", status, err)
|
||||
return nil, fmt.Errorf("wrong param (status): %s. Error: %v", status, err)
|
||||
}
|
||||
|
||||
switch i {
|
||||
case EmailSent, Cancelled, AwaitingApproval, Rejected, Processing, Failure, Completed:
|
||||
default:
|
||||
return response.WithdrawList, fmt.Errorf("wrong param (status): %s", status)
|
||||
return nil, fmt.Errorf("wrong param (status): %s", status)
|
||||
}
|
||||
|
||||
params.Set("status", status)
|
||||
}
|
||||
|
||||
if startTime > 0 {
|
||||
params.Set("startTime", strconv.FormatInt(startTime, 10))
|
||||
if !startTime.IsZero() {
|
||||
params.Set("startTime", strconv.FormatInt(startTime.UTC().Unix(), 10))
|
||||
}
|
||||
|
||||
if endTime > 0 {
|
||||
params.Set("endTime", strconv.FormatInt(endTime, 10))
|
||||
if !endTime.IsZero() {
|
||||
params.Set("endTime", strconv.FormatInt(endTime.UTC().Unix(), 10))
|
||||
}
|
||||
|
||||
if offset != 0 {
|
||||
params.Set("offset", strconv.Itoa(offset))
|
||||
}
|
||||
|
||||
if limit != 0 {
|
||||
params.Set("limit", strconv.Itoa(limit))
|
||||
}
|
||||
|
||||
if err := b.SendAuthHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
http.MethodGet, withdrawalHistory,
|
||||
params, spotDefaultRate,
|
||||
http.MethodGet,
|
||||
depositHistory,
|
||||
params,
|
||||
spotDefaultRate,
|
||||
&response); err != nil {
|
||||
return response.WithdrawList, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return response.WithdrawList, nil
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// WithdrawHistory gets the status of recent withdrawals
|
||||
// status `param` used as string to prevent default value 0 (for int) interpreting as EmailSent status
|
||||
func (b *Binance) WithdrawHistory(ctx context.Context, c currency.Code, status string, startTime, endTime time.Time, offset, limit int) ([]WithdrawStatusResponse, error) {
|
||||
params := url.Values{}
|
||||
if !c.IsEmpty() {
|
||||
params.Set("coin", c.String())
|
||||
}
|
||||
|
||||
if status != "" {
|
||||
i, err := strconv.Atoi(status)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wrong param (status): %s. Error: %v", status, err)
|
||||
}
|
||||
|
||||
switch i {
|
||||
case EmailSent, Cancelled, AwaitingApproval, Rejected, Processing, Failure, Completed:
|
||||
default:
|
||||
return nil, fmt.Errorf("wrong param (status): %s", status)
|
||||
}
|
||||
|
||||
params.Set("status", status)
|
||||
}
|
||||
|
||||
if !startTime.IsZero() {
|
||||
params.Set("startTime", strconv.FormatInt(startTime.UTC().Unix(), 10))
|
||||
}
|
||||
|
||||
if !endTime.IsZero() {
|
||||
params.Set("endTime", strconv.FormatInt(endTime.UTC().Unix(), 10))
|
||||
}
|
||||
|
||||
if offset != 0 {
|
||||
params.Set("offset", strconv.Itoa(offset))
|
||||
}
|
||||
|
||||
if limit != 0 {
|
||||
params.Set("limit", strconv.Itoa(limit))
|
||||
}
|
||||
|
||||
var withdrawStatus []WithdrawStatusResponse
|
||||
if err := b.SendAuthHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
http.MethodGet,
|
||||
withdrawHistory,
|
||||
params,
|
||||
spotDefaultRate,
|
||||
&withdrawStatus); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return withdrawStatus, nil
|
||||
}
|
||||
|
||||
// GetDepositAddressForCurrency retrieves the wallet address for a given currency
|
||||
func (b *Binance) GetDepositAddressForCurrency(ctx context.Context, currency string) (string, error) {
|
||||
resp := struct {
|
||||
Address string `json:"address"`
|
||||
Success bool `json:"success"`
|
||||
AddressTag string `json:"addressTag"`
|
||||
}{}
|
||||
|
||||
func (b *Binance) GetDepositAddressForCurrency(ctx context.Context, currency, chain string) (*DepositAddress, error) {
|
||||
params := url.Values{}
|
||||
params.Set("asset", currency)
|
||||
params.Set("status", "true")
|
||||
params.Set("coin", currency)
|
||||
if chain != "" {
|
||||
params.Set("network", chain)
|
||||
}
|
||||
params.Set("recvWindow", "10000")
|
||||
|
||||
return resp.Address,
|
||||
b.SendAuthHTTPRequest(ctx,
|
||||
exchange.RestSpotSupplementary,
|
||||
http.MethodGet, depositAddress,
|
||||
params, spotDefaultRate, &resp)
|
||||
var d DepositAddress
|
||||
return &d,
|
||||
b.SendAuthHTTPRequest(ctx, exchange.RestSpotSupplementary, http.MethodGet, depositAddress, params, spotDefaultRate, &d)
|
||||
}
|
||||
|
||||
// GetWsAuthStreamKey will retrieve a key to use for authorised WS streaming
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//+build mock_test_off
|
||||
//go:build mock_test_off
|
||||
// +build mock_test_off
|
||||
|
||||
// This will build if build tag mock_test_off is parsed and will do live testing
|
||||
// using all tests in (exchange)_test.go
|
||||
|
||||
@@ -27,10 +27,13 @@ const (
|
||||
canManipulateRealOrders = false
|
||||
)
|
||||
|
||||
var b Binance
|
||||
|
||||
// this lock guards against orderbook tests race
|
||||
var binanceOrderBookLock = &sync.Mutex{}
|
||||
var (
|
||||
b Binance
|
||||
// this lock guards against orderbook tests race
|
||||
binanceOrderBookLock = &sync.Mutex{}
|
||||
// this pair is used to ensure that endpoints match it correctly
|
||||
testPairMapping = currency.NewPair(currency.DOGE, currency.USDT)
|
||||
)
|
||||
|
||||
func areTestAPIKeysSet() bool {
|
||||
return b.ValidateAPICredentials()
|
||||
@@ -53,22 +56,31 @@ func TestUServerTime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseSAPITime(t *testing.T) {
|
||||
t.Parallel()
|
||||
tm, err := time.Parse(binanceSAPITimeLayout, "2021-05-27 03:56:46")
|
||||
if err != nil {
|
||||
t.Fatal(tm)
|
||||
}
|
||||
tm = tm.UTC()
|
||||
if tm.Year() != 2021 ||
|
||||
tm.Month() != 5 ||
|
||||
tm.Day() != 27 ||
|
||||
tm.Hour() != 3 ||
|
||||
tm.Minute() != 56 ||
|
||||
tm.Second() != 46 {
|
||||
t.Fatal("incorrect values")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateTicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
spotPairs, err := b.FetchTradablePairs(context.Background(), asset.Spot)
|
||||
r, err := b.UpdateTicker(context.Background(), testPairMapping, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if len(spotPairs) == 0 {
|
||||
t.Error("no tradable pairs")
|
||||
}
|
||||
spotCP, err := currency.NewPairFromString(spotPairs[0])
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = b.UpdateTicker(context.Background(), spotCP, asset.Spot)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
if r.Pair.Base != currency.DOGE && r.Pair.Quote != currency.USDT {
|
||||
t.Error("invalid pair values")
|
||||
}
|
||||
tradablePairs, err := b.FetchTradablePairs(context.Background(), asset.CoinMarginedFutures)
|
||||
if err != nil {
|
||||
@@ -1945,6 +1957,17 @@ func TestModifyOrder(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAllCoinsInfo(t *testing.T) {
|
||||
t.Parallel()
|
||||
if !areTestAPIKeysSet() && !mockTests {
|
||||
t.Skip("API keys not set")
|
||||
}
|
||||
_, err := b.GetAllCoinsInfo(context.Background())
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithdraw(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
@@ -1953,7 +1976,7 @@ func TestWithdraw(t *testing.T) {
|
||||
|
||||
withdrawCryptoRequest := withdraw.Request{
|
||||
Exchange: b.Name,
|
||||
Amount: 0.00001337,
|
||||
Amount: -1,
|
||||
Currency: currency.BTC,
|
||||
Description: "WITHDRAW IT ALL",
|
||||
Crypto: withdraw.CryptoRequest{
|
||||
@@ -1968,8 +1991,20 @@ func TestWithdraw(t *testing.T) {
|
||||
t.Error("Withdraw() error", err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("Withdraw() expecting an error when no keys are set")
|
||||
case mockTests && err != nil:
|
||||
}
|
||||
}
|
||||
|
||||
func TestDepositHistory(t *testing.T) {
|
||||
t.Parallel()
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
_, err := b.DepositHistory(context.Background(), currency.ETH, "", time.Time{}, time.Time{}, 0, 10000)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error(err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("expecting an error when no keys are set")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1978,7 +2013,7 @@ func TestWithdrawHistory(t *testing.T) {
|
||||
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
|
||||
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
|
||||
}
|
||||
_, err := b.GetWithdrawalsHistory(context.Background(), currency.XBT)
|
||||
_, err := b.GetWithdrawalsHistory(context.Background(), currency.ETH)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("GetWithdrawalsHistory() error", err)
|
||||
@@ -2007,7 +2042,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.USDT, "", currency.BNB.String())
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error("GetDepositAddress() error", err)
|
||||
@@ -2414,6 +2449,19 @@ func TestGetRecentTrades(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetAvailableTransferChains(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := b.GetAvailableTransferChains(context.Background(), currency.BTC)
|
||||
switch {
|
||||
case areTestAPIKeysSet() && err != nil:
|
||||
t.Error(err)
|
||||
case !areTestAPIKeysSet() && err == nil && !mockTests:
|
||||
t.Error("error cannot be nil")
|
||||
case mockTests && err != nil:
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeedLocalCache(t *testing.T) {
|
||||
t.Parallel()
|
||||
err := b.SeedLocalCache(context.Background(), currency.NewPair(currency.BTC, currency.USDT))
|
||||
@@ -2428,7 +2476,7 @@ func TestGenerateSubscriptions(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(subs) != 4 {
|
||||
if len(subs) != 8 {
|
||||
t.Fatal("unexpected subscription length")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,42 @@ type ExchangeInfo struct {
|
||||
} `json:"symbols"`
|
||||
}
|
||||
|
||||
// CoinInfo stores information about all supported coins
|
||||
type CoinInfo struct {
|
||||
Coin string `json:"coin"`
|
||||
DepositAllEnable bool `json:"depositAllEnable"`
|
||||
WithdrawAllEnable bool `json:"withdrawAllEnable"`
|
||||
Free float64 `json:"free,string"`
|
||||
Freeze float64 `json:"freeze,string"`
|
||||
IPOAble float64 `json:"ipoable,string"`
|
||||
IPOing float64 `json:"ipoing,string"`
|
||||
IsLegalMoney bool `json:"isLegalMoney"`
|
||||
Locked float64 `json:"locked,string"`
|
||||
Name string `json:"name"`
|
||||
NetworkList []struct {
|
||||
AddressRegex string `json:"addressRegex"`
|
||||
Coin string `json:"coin"`
|
||||
DepositDescription string `json:"depositDesc"` // shown only when "depositEnable" is false
|
||||
DepositEnable bool `json:"depositEnable"`
|
||||
IsDefault bool `json:"isDefault"`
|
||||
MemoRegex string `json:"memoRegex"`
|
||||
MinimumConfirmation uint16 `json:"minConfirm"`
|
||||
Name string `json:"name"`
|
||||
Network string `json:"network"`
|
||||
ResetAddressStatus bool `json:"resetAddressStatus"`
|
||||
SpecialTips string `json:"specialTips"`
|
||||
UnlockConfirm uint16 `json:"unLockConfirm"`
|
||||
WithdrawDescription string `json:"withdrawDesc"` // shown only when "withdrawEnable" is false
|
||||
WithdrawEnable bool `json:"withdrawEnable"`
|
||||
WithdrawFee float64 `json:"withdrawFee,string"`
|
||||
WithdrawMinimum float64 `json:"withdrawMin,string"`
|
||||
WithdrawMaximum float64 `json:"withdrawMax,string"`
|
||||
} `json:"networkList"`
|
||||
Storage float64 `json:"storage,string"`
|
||||
Trading bool `json:"trading"`
|
||||
Withdrawing float64 `json:"withdrawing,string"`
|
||||
}
|
||||
|
||||
// OrderBookDataRequestParams represents Klines request data.
|
||||
type OrderBookDataRequestParams struct {
|
||||
Symbol currency.Pair `json:"symbol"` // Required field; example LTCBTC,BTCUSDT
|
||||
@@ -648,24 +684,47 @@ var WithdrawalFees = map[currency.Code]float64{
|
||||
currency.PIVX: 0.02,
|
||||
}
|
||||
|
||||
// DepositHistory stores deposit history info
|
||||
type DepositHistory struct {
|
||||
Amount float64 `json:"amount,string"`
|
||||
Coin string `json:"coin"`
|
||||
Network string `json:"network"`
|
||||
Status uint8 `json:"status"`
|
||||
Address string `json:"address"`
|
||||
AddressTag string `json:"adressTag"`
|
||||
TransactionID string `json:"txId"`
|
||||
InsertTime float64 `json:"insertTime"`
|
||||
TransferType uint8 `json:"transferType"`
|
||||
ConfirmTimes string `json:"confirmTimes"`
|
||||
}
|
||||
|
||||
// WithdrawResponse contains status of withdrawal request
|
||||
type WithdrawResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Msg string `json:"msg"`
|
||||
ID string `json:"id"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// WithdrawStatusResponse defines a withdrawal status response
|
||||
type WithdrawStatusResponse struct {
|
||||
Amount float64 `json:"amount"`
|
||||
TransactionFee float64 `json:"transactionFee"`
|
||||
Address string `json:"address"`
|
||||
TxID string `json:"txId"`
|
||||
ID string `json:"id"`
|
||||
Asset string `json:"asset"`
|
||||
ApplyTime int64 `json:"applyTime"`
|
||||
Status int64 `json:"status"`
|
||||
Network string `json:"network"`
|
||||
Address string `json:"address"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
ApplyTime string `json:"applyTime"`
|
||||
Coin string `json:"coin"`
|
||||
ID string `json:"id"`
|
||||
WithdrawOrderID string `json:"withdrawOrderId"`
|
||||
Network string `json:"network"`
|
||||
TransferType uint8 `json:"transferType"`
|
||||
Status int64 `json:"status"`
|
||||
TransactionFee float64 `json:"transactionFee,string"`
|
||||
TransactionID string `json:"txId"`
|
||||
ConfirmNumber int64 `json:"confirmNo"`
|
||||
}
|
||||
|
||||
// DepositAddress stores the deposit address info
|
||||
type DepositAddress struct {
|
||||
Address string `json:"address"`
|
||||
Coin string `json:"coin"`
|
||||
Tag string `json:"tag"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
// UserAccountStream contains a key to maintain an authorised
|
||||
|
||||
@@ -16,6 +16,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"
|
||||
@@ -118,25 +119,27 @@ func (b *Binance) SetDefaults() {
|
||||
REST: true,
|
||||
Websocket: true,
|
||||
RESTCapabilities: protocol.Features{
|
||||
TickerBatching: true,
|
||||
TickerFetching: true,
|
||||
KlineFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrders: true,
|
||||
CancelOrder: true,
|
||||
SubmitOrder: true,
|
||||
DepositHistory: true,
|
||||
WithdrawalHistory: true,
|
||||
TradeFetching: true,
|
||||
UserTradeHistory: true,
|
||||
TradeFee: true,
|
||||
CryptoWithdrawalFee: true,
|
||||
TickerBatching: true,
|
||||
TickerFetching: true,
|
||||
KlineFetching: true,
|
||||
OrderbookFetching: true,
|
||||
AutoPairUpdates: true,
|
||||
AccountInfo: true,
|
||||
CryptoDeposit: true,
|
||||
CryptoWithdrawal: true,
|
||||
GetOrder: true,
|
||||
GetOrders: true,
|
||||
CancelOrders: true,
|
||||
CancelOrder: true,
|
||||
SubmitOrder: true,
|
||||
DepositHistory: true,
|
||||
WithdrawalHistory: true,
|
||||
TradeFetching: true,
|
||||
UserTradeHistory: true,
|
||||
TradeFee: true,
|
||||
CryptoWithdrawalFee: true,
|
||||
MultiChainDeposits: true,
|
||||
MultiChainWithdrawals: true,
|
||||
},
|
||||
WebsocketCapabilities: protocol.Features{
|
||||
TradeFetching: true,
|
||||
@@ -431,27 +434,40 @@ func (b *Binance) UpdateTickers(ctx context.Context, a asset.Item) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for y := range tick {
|
||||
cp, err := currency.NewPairFromString(tick[y].Symbol)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[y].LastPrice,
|
||||
High: tick[y].HighPrice,
|
||||
Low: tick[y].LowPrice,
|
||||
Bid: tick[y].BidPrice,
|
||||
Ask: tick[y].AskPrice,
|
||||
Volume: tick[y].Volume,
|
||||
QuoteVolume: tick[y].QuoteVolume,
|
||||
Open: tick[y].OpenPrice,
|
||||
Close: tick[y].PrevClosePrice,
|
||||
Pair: cp,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
pairs, err := b.GetEnabledPairs(a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range pairs {
|
||||
for y := range tick {
|
||||
pairFmt, err := b.FormatExchangeCurrency(pairs[i], a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tick[y].Symbol != pairFmt.String() {
|
||||
continue
|
||||
}
|
||||
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[y].LastPrice,
|
||||
High: tick[y].HighPrice,
|
||||
Low: tick[y].LowPrice,
|
||||
Bid: tick[y].BidPrice,
|
||||
Ask: tick[y].AskPrice,
|
||||
Volume: tick[y].Volume,
|
||||
QuoteVolume: tick[y].QuoteVolume,
|
||||
Open: tick[y].OpenPrice,
|
||||
Close: tick[y].PrevClosePrice,
|
||||
Pair: pairFmt,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case asset.USDTMarginedFutures:
|
||||
@@ -522,10 +538,6 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cp, err := currency.NewPairFromString(tick.Symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick.LastPrice,
|
||||
High: tick.HighPrice,
|
||||
@@ -536,7 +548,7 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
QuoteVolume: tick.QuoteVolume,
|
||||
Open: tick.OpenPrice,
|
||||
Close: tick.PrevClosePrice,
|
||||
Pair: cp,
|
||||
Pair: p,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
@@ -548,10 +560,6 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cp, err := currency.NewPairFromString(tick[0].Symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[0].LastPrice,
|
||||
High: tick[0].HighPrice,
|
||||
@@ -560,7 +568,7 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
QuoteVolume: tick[0].QuoteVolume,
|
||||
Open: tick[0].OpenPrice,
|
||||
Close: tick[0].PrevClosePrice,
|
||||
Pair: cp,
|
||||
Pair: p,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
@@ -572,10 +580,6 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cp, err := currency.NewPairFromString(tick[0].Symbol)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = ticker.ProcessTicker(&ticker.Price{
|
||||
Last: tick[0].LastPrice,
|
||||
High: tick[0].HighPrice,
|
||||
@@ -584,7 +588,7 @@ func (b *Binance) UpdateTicker(ctx context.Context, p currency.Pair, a asset.Ite
|
||||
QuoteVolume: tick[0].QuoteVolume,
|
||||
Open: tick[0].OpenPrice,
|
||||
Close: tick[0].PrevClosePrice,
|
||||
Pair: cp,
|
||||
Pair: p,
|
||||
ExchangeName: b.Name,
|
||||
AssetType: a,
|
||||
})
|
||||
@@ -763,7 +767,6 @@ func (b *Binance) FetchAccountInfo(ctx context.Context, assetType asset.Item) (a
|
||||
if err != nil {
|
||||
return b.UpdateAccountInfo(ctx, assetType)
|
||||
}
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
@@ -775,21 +778,26 @@ func (b *Binance) GetFundingHistory(ctx context.Context) ([]exchange.FundHistory
|
||||
|
||||
// GetWithdrawalsHistory returns previous withdrawals data
|
||||
func (b *Binance) GetWithdrawalsHistory(ctx context.Context, c currency.Code) (resp []exchange.WithdrawalHistory, err error) {
|
||||
w, err := b.WithdrawStatus(ctx, c, "", 0, 0)
|
||||
w, err := b.WithdrawHistory(ctx, c, "", time.Time{}, time.Time{}, 0, 10000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range w {
|
||||
tm, err := time.Parse(binanceSAPITimeLayout, w[i].ApplyTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp = append(resp, exchange.WithdrawalHistory{
|
||||
Status: strconv.FormatInt(w[i].Status, 10),
|
||||
TransferID: w[i].ID,
|
||||
Currency: w[i].Asset,
|
||||
Currency: w[i].Coin,
|
||||
Amount: w[i].Amount,
|
||||
Fee: w[i].TransactionFee,
|
||||
CryptoToAddress: w[i].Address,
|
||||
CryptoTxID: w[i].TxID,
|
||||
Timestamp: time.Unix(w[i].ApplyTime/1000, 0),
|
||||
CryptoTxID: w[i].TransactionID,
|
||||
CryptoChain: w[i].Network,
|
||||
Timestamp: tm,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1216,8 +1224,16 @@ func (b *Binance) GetOrderInfo(ctx context.Context, orderID string, pair currenc
|
||||
}
|
||||
|
||||
// GetDepositAddress returns a deposit address for a specified currency
|
||||
func (b *Binance) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _ string) (string, error) {
|
||||
return b.GetDepositAddressForCurrency(ctx, cryptocurrency.String())
|
||||
func (b *Binance) GetDepositAddress(ctx context.Context, cryptocurrency currency.Code, _, chain string) (*deposit.Address, error) {
|
||||
addr, err := b.GetDepositAddressForCurrency(ctx, cryptocurrency.String(), chain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &deposit.Address{
|
||||
Address: addr.Address,
|
||||
Tag: addr.Tag,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// WithdrawCryptocurrencyFunds returns a withdrawal ID when a withdrawal is
|
||||
@@ -1229,9 +1245,13 @@ func (b *Binance) WithdrawCryptocurrencyFunds(ctx context.Context, withdrawReque
|
||||
amountStr := strconv.FormatFloat(withdrawRequest.Amount, 'f', -1, 64)
|
||||
v, err := b.WithdrawCrypto(ctx,
|
||||
withdrawRequest.Currency.String(),
|
||||
"", // withdrawal order ID
|
||||
withdrawRequest.Crypto.Chain,
|
||||
withdrawRequest.Crypto.Address,
|
||||
withdrawRequest.Crypto.AddressTag,
|
||||
withdrawRequest.Description, amountStr)
|
||||
withdrawRequest.Description,
|
||||
amountStr,
|
||||
false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1730,3 +1750,22 @@ func (b *Binance) UpdateOrderExecutionLimits(ctx context.Context, a asset.Item)
|
||||
}
|
||||
return b.LoadLimits(limits)
|
||||
}
|
||||
|
||||
// GetAvailableTransferChains returns the available transfer blockchains for the specific
|
||||
// cryptocurrency
|
||||
func (b *Binance) GetAvailableTransferChains(ctx context.Context, cryptocurrency currency.Code) ([]string, error) {
|
||||
coinInfo, err := b.GetAllCoinsInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var availableChains []string
|
||||
for x := range coinInfo {
|
||||
if strings.EqualFold(coinInfo[x].Coin, cryptocurrency.String()) {
|
||||
for y := range coinInfo[x].NetworkList {
|
||||
availableChains = append(availableChains, coinInfo[x].NetworkList[y].Network)
|
||||
}
|
||||
}
|
||||
}
|
||||
return availableChains, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user