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:
Adrian Gallagher
2021-10-15 15:55:38 +11:00
committed by GitHub
parent b093a7df19
commit 0c00b7e1df
145 changed files with 46329 additions and 5507 deletions

View File

@@ -17,6 +17,7 @@ import (
"github.com/gofrs/uuid"
grpcauth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/pquerna/otp/totp"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/common/file"
@@ -62,6 +63,7 @@ var (
errAssetTypeUnset = errors.New("asset type unset")
errDispatchSystem = errors.New("dispatch system offline")
errCurrencyNotEnabled = errors.New("currency not enabled")
errCurrencyNotSpecified = errors.New("a currency must be specified")
errCurrencyPairInvalid = errors.New("currency provided is not found in the available pairs list")
errNoTrades = errors.New("no trades returned from supplied params")
errNilRequestData = errors.New("nil request data received, cannot continue")
@@ -1439,6 +1441,7 @@ func (s *RPCServer) CancelAllOrders(ctx context.Context, r *gctrpc.CancelAllOrde
}, nil
}
// ModifyOrder modifies an existing order if it exists
func (s *RPCServer) ModifyOrder(ctx context.Context, r *gctrpc.ModifyOrderRequest) (*gctrpc.ModifyOrderResponse, error) {
assetType, err := asset.New(r.Asset)
if err != nil {
@@ -1531,28 +1534,90 @@ func (s *RPCServer) RemoveEvent(ctx context.Context, r *gctrpc.RemoveEventReques
// GetCryptocurrencyDepositAddresses returns a list of cryptocurrency deposit
// addresses specified by an exchange
func (s *RPCServer) GetCryptocurrencyDepositAddresses(ctx context.Context, r *gctrpc.GetCryptocurrencyDepositAddressesRequest) (*gctrpc.GetCryptocurrencyDepositAddressesResponse, error) {
_, err := s.GetExchangeByName(r.Exchange)
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
if !exch.GetAuthenticatedAPISupport(exchange.RestAuthentication) {
return nil, exchange.ErrAuthenticatedRequestWithoutCredentialsSet
}
result, err := s.GetCryptocurrencyDepositAddressesByExchange(r.Exchange)
return &gctrpc.GetCryptocurrencyDepositAddressesResponse{Addresses: result}, err
if err != nil {
return nil, err
}
var resp gctrpc.GetCryptocurrencyDepositAddressesResponse
resp.Addresses = make(map[string]*gctrpc.DepositAddresses)
for k, v := range result {
var depositAddrs []*gctrpc.DepositAddress
for a := range v {
depositAddrs = append(depositAddrs, &gctrpc.DepositAddress{
Address: v[a].Address,
Tag: v[a].Tag,
Chain: v[a].Chain,
})
}
resp.Addresses[k] = &gctrpc.DepositAddresses{Addresses: depositAddrs}
}
return &resp, nil
}
// GetCryptocurrencyDepositAddress returns a cryptocurrency deposit address
// specified by exchange and cryptocurrency
func (s *RPCServer) GetCryptocurrencyDepositAddress(ctx context.Context, r *gctrpc.GetCryptocurrencyDepositAddressRequest) (*gctrpc.GetCryptocurrencyDepositAddressResponse, error) {
_, err := s.GetExchangeByName(r.Exchange)
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
if !exch.GetAuthenticatedAPISupport(exchange.RestAuthentication) {
return nil, exchange.ErrAuthenticatedRequestWithoutCredentialsSet
}
addr, err := s.GetExchangeCryptocurrencyDepositAddress(ctx,
r.Exchange,
"",
currency.NewCode(r.Cryptocurrency))
return &gctrpc.GetCryptocurrencyDepositAddressResponse{Address: addr}, err
r.Chain,
currency.NewCode(r.Cryptocurrency),
r.Bypass,
)
if err != nil {
return nil, err
}
return &gctrpc.GetCryptocurrencyDepositAddressResponse{
Address: addr.Address,
Tag: addr.Tag,
}, nil
}
// GetAvailableTransferChains returns the supported transfer chains specified by
// exchange and cryptocurrency
func (s *RPCServer) GetAvailableTransferChains(ctx context.Context, r *gctrpc.GetAvailableTransferChainsRequest) (*gctrpc.GetAvailableTransferChainsResponse, error) {
exch, err := s.GetExchangeByName(r.Exchange)
if err != nil {
return nil, err
}
curr := currency.NewCode(r.Cryptocurrency)
if curr.IsEmpty() {
return nil, errCurrencyNotSpecified
}
resp, err := exch.GetAvailableTransferChains(ctx, curr)
if err != nil {
return nil, err
}
if len(resp) == 0 {
return nil, errors.New("no available transfer chains found")
}
return &gctrpc.GetAvailableTransferChainsResponse{
Chains: resp,
}, nil
}
// WithdrawCryptocurrencyFunds withdraws cryptocurrency funds specified by
@@ -1573,9 +1638,38 @@ func (s *RPCServer) WithdrawCryptocurrencyFunds(ctx context.Context, r *gctrpc.W
Address: r.Address,
AddressTag: r.AddressTag,
FeeAmount: r.Fee,
Chain: r.Chain,
},
}
exchCfg, err := s.Config.GetExchangeConfig(r.Exchange)
if err != nil {
return nil, err
}
if exchCfg.API.Credentials.OTPSecret != "" {
code, errOTP := totp.GenerateCode(exchCfg.API.Credentials.OTPSecret, time.Now())
if errOTP != nil {
return nil, errOTP
}
codeNum, errOTP := strconv.ParseInt(code, 10, 64)
if errOTP != nil {
return nil, errOTP
}
request.OneTimePassword = codeNum
}
if exchCfg.API.Credentials.PIN != "" {
pinCode, errPin := strconv.ParseInt(exchCfg.API.Credentials.PIN, 10, 64)
if err != nil {
return nil, errPin
}
request.PIN = pinCode
}
request.TradePassword = exchCfg.API.Credentials.TradePassword
resp, err := s.Engine.WithdrawManager.SubmitWithdrawal(ctx, request)
if err != nil {
return nil, err
@@ -1618,6 +1712,34 @@ func (s *RPCServer) WithdrawFiatFunds(ctx context.Context, r *gctrpc.WithdrawFia
},
}
exchCfg, err := s.Config.GetExchangeConfig(r.Exchange)
if err != nil {
return nil, err
}
if exchCfg.API.Credentials.OTPSecret != "" {
code, errOTP := totp.GenerateCode(exchCfg.API.Credentials.OTPSecret, time.Now())
if err != nil {
return nil, errOTP
}
codeNum, errOTP := strconv.ParseInt(code, 10, 64)
if err != nil {
return nil, errOTP
}
request.OneTimePassword = codeNum
}
if exchCfg.API.Credentials.PIN != "" {
pinCode, errPIN := strconv.ParseInt(exchCfg.API.Credentials.PIN, 10, 64)
if err != nil {
return nil, errPIN
}
request.PIN = pinCode
}
request.TradePassword = exchCfg.API.Credentials.TradePassword
resp, err := s.Engine.WithdrawManager.SubmitWithdrawal(ctx, request)
if err != nil {
return nil, err