Files
gocryptotrader/engine/withdraw_manager.go
Adrian Gallagher 0c00b7e1df 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
2021-10-15 15:55:38 +11:00

151 lines
4.2 KiB
Go

package engine
import (
"context"
"errors"
"fmt"
"time"
dbwithdraw "github.com/thrasher-corp/gocryptotrader/database/repository/withdraw"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/currencystate"
"github.com/thrasher-corp/gocryptotrader/log"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
)
// SetupWithdrawManager creates a new withdraw manager
func SetupWithdrawManager(em iExchangeManager, pm iPortfolioManager, isDryRun bool) (*WithdrawManager, error) {
if em == nil {
return nil, errors.New("nil manager")
}
return &WithdrawManager{
exchangeManager: em,
portfolioManager: pm,
isDryRun: isDryRun,
}, nil
}
// SubmitWithdrawal performs validation and submits a new withdraw request to
// exchange
func (m *WithdrawManager) SubmitWithdrawal(ctx context.Context, req *withdraw.Request) (*withdraw.Response, error) {
if m == nil {
return nil, ErrNilSubsystem
}
if req == nil {
return nil, withdraw.ErrRequestCannotBeNil
}
exch, err := m.exchangeManager.GetExchangeByName(req.Exchange)
if err != nil {
return nil, err
}
resp := &withdraw.Response{
Exchange: withdraw.ExchangeResponse{
Name: req.Exchange,
},
RequestDetails: *req,
}
// Determines if the currency can be withdrawn from the exchange
errF := exch.CanWithdraw(req.Currency, asset.Spot)
if errF != nil && !errors.Is(errF, currencystate.ErrCurrencyStateNotFound) { // Suppress not found error
return nil, errF
}
if m.isDryRun {
log.Warnln(log.Global, "Dry run enabled, no withdrawal request will be submitted or have an event created")
resp.ID = withdraw.DryRunID
resp.Exchange.Status = "dryrun"
resp.Exchange.ID = withdraw.DryRunID.String()
} else {
var ret *withdraw.ExchangeResponse
if req.Type == withdraw.Crypto {
if !m.portfolioManager.IsWhiteListed(req.Crypto.Address) {
return nil, withdraw.ErrStrAddressNotWhiteListed
}
if !m.portfolioManager.IsExchangeSupported(req.Exchange, req.Crypto.Address) {
return nil, withdraw.ErrStrExchangeNotSupportedByAddress
}
}
if req.Type == withdraw.Fiat {
ret, err = exch.WithdrawFiatFunds(ctx, req)
if err != nil {
resp.Exchange.Status = err.Error()
} else {
resp.Exchange.Status = ret.Status
resp.Exchange.ID = ret.ID
}
} else if req.Type == withdraw.Crypto {
ret, err = exch.WithdrawCryptocurrencyFunds(ctx, req)
if err != nil {
resp.Exchange.Status = err.Error()
} else {
resp.Exchange.Status = ret.Status
resp.Exchange.ID = ret.ID
}
}
}
dbwithdraw.Event(resp)
if err == nil {
withdraw.Cache.Add(resp.ID, resp)
}
return resp, err
}
// WithdrawalEventByID returns a withdrawal request by ID
func (m *WithdrawManager) WithdrawalEventByID(id string) (*withdraw.Response, error) {
if m == nil {
return nil, ErrNilSubsystem
}
if v := withdraw.Cache.Get(id); v != nil {
return v.(*withdraw.Response), nil
}
l, err := dbwithdraw.GetEventByUUID(id)
if err != nil {
return nil, fmt.Errorf("%w %v", ErrWithdrawRequestNotFound, id)
}
withdraw.Cache.Add(id, l)
return l, nil
}
// WithdrawalEventByExchange returns a withdrawal request by ID
func (m *WithdrawManager) WithdrawalEventByExchange(exchange string, limit int) ([]*withdraw.Response, error) {
if m == nil {
return nil, ErrNilSubsystem
}
_, err := m.exchangeManager.GetExchangeByName(exchange)
if err != nil {
return nil, err
}
return dbwithdraw.GetEventsByExchange(exchange, limit)
}
// WithdrawEventByDate returns a withdrawal request by ID
func (m *WithdrawManager) WithdrawEventByDate(exchange string, start, end time.Time, limit int) ([]*withdraw.Response, error) {
if m == nil {
return nil, ErrNilSubsystem
}
_, err := m.exchangeManager.GetExchangeByName(exchange)
if err != nil {
return nil, err
}
return dbwithdraw.GetEventsByDate(exchange, start, end, limit)
}
// WithdrawalEventByExchangeID returns a withdrawal request by Exchange ID
func (m *WithdrawManager) WithdrawalEventByExchangeID(exchange, id string) (*withdraw.Response, error) {
if m == nil {
return nil, ErrNilSubsystem
}
_, err := m.exchangeManager.GetExchangeByName(exchange)
if err != nil {
return nil, err
}
return dbwithdraw.GetEventByExchangeID(exchange, id)
}