From 59b98a338b487470350d39ca71905db33d9e14e5 Mon Sep 17 00:00:00 2001 From: Gareth Kirwan Date: Thu, 15 Aug 2024 09:41:18 +0700 Subject: [PATCH] Kraken: Handle Errors field in futures response --- common/common.go | 1 + exchanges/binance/binance_test.go | 2 +- exchanges/binance/binance_websocket.go | 3 +- exchanges/bitfinex/bitfinex_test.go | 2 +- exchanges/bitfinex/bitfinex_types.go | 1 - exchanges/bitfinex/bitfinex_websocket.go | 4 +-- exchanges/kraken/kraken.go | 7 +--- exchanges/kraken/kraken_futures.go | 41 +++++++++++++++++++----- exchanges/kraken/kraken_types.go | 1 + exchanges/kraken/kraken_websocket.go | 3 +- 10 files changed, 42 insertions(+), 23 deletions(-) diff --git a/common/common.go b/common/common.go index 2aec8fc8741..a01fd97f8cd 100644 --- a/common/common.go +++ b/common/common.go @@ -67,6 +67,7 @@ var ( ErrCannotCalculateOffline = errors.New("cannot calculate offline, unsupported") ErrNoResponse = errors.New("no response") ErrTypeAssertFailure = errors.New("type assert failure") + ErrUnknownError = errors.New("unknown error") ) var ( diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index b4b95e1d5da..66302132767 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -2016,7 +2016,7 @@ func TestSubscribeBadResp(t *testing.T) { } b := testexch.MockWsInstance[Binance](t, testexch.CurryWsMockUpgrader(t, mock)) //nolint:govet // Intentional shadow to avoid future copy/paste mistakes err := b.Subscribe(channels) - assert.ErrorIs(t, err, errUnknownError, "Subscribe should error errUnknownError") + assert.ErrorIs(t, err, common.ErrUnknownError, "Subscribe should error correctly") assert.ErrorContains(t, err, "carrots", "Subscribe should error containing the carrots") } diff --git a/exchanges/binance/binance_websocket.go b/exchanges/binance/binance_websocket.go index 1168dc664a3..51b4c77419c 100644 --- a/exchanges/binance/binance_websocket.go +++ b/exchanges/binance/binance_websocket.go @@ -46,7 +46,6 @@ var ( // maxWSOrderbookWorkers defines a max amount of workers allowed to execute // jobs from the job channel maxWSOrderbookWorkers = 10 - errUnknownError = errors.New("unknown error") ) // WsConnect initiates a websocket connection @@ -584,7 +583,7 @@ func (b *Binance) manageSubs(op string, subs subscription.List) error { if v, d, _, rErr := jsonparser.Get(respRaw, "result"); rErr != nil { err = rErr } else if d != jsonparser.Null { // null is the only expected and acceptable response - err = fmt.Errorf("%w: %s", errUnknownError, v) + err = fmt.Errorf("%w: %s", common.ErrUnknownError, v) } } diff --git a/exchanges/bitfinex/bitfinex_test.go b/exchanges/bitfinex/bitfinex_test.go index 30a2c85b35f..2eaad7911bb 100644 --- a/exchanges/bitfinex/bitfinex_test.go +++ b/exchanges/bitfinex/bitfinex_test.go @@ -1979,7 +1979,7 @@ func TestGetErrResp(t *testing.T) { case 3: // event != 'error' assert.NoError(t, testErr, "Message with non-'error' event field should not error") case 4: // event="error" - assert.ErrorIs(t, testErr, errUnknownError, "error without a message should throw unknown error") + assert.ErrorIs(t, testErr, common.ErrUnknownError, "error without a message should throw unknown error") assert.ErrorContains(t, testErr, "code: 0", "error without a code should throw code 0") case 5: // Fully formatted assert.ErrorContains(t, testErr, "redcoats", "message field should be in the error") diff --git a/exchanges/bitfinex/bitfinex_types.go b/exchanges/bitfinex/bitfinex_types.go index 5fea5f65653..4ddca9bc3de 100644 --- a/exchanges/bitfinex/bitfinex_types.go +++ b/exchanges/bitfinex/bitfinex_types.go @@ -13,7 +13,6 @@ import ( var ( errSetCannotBeEmpty = errors.New("set cannot be empty") errNoSeqNo = errors.New("no sequence number") - errUnknownError = errors.New("unknown error") errParamNotAllowed = errors.New("param not allowed") errParsingWSField = errors.New("error parsing WS field") errTickerInvalidSymbol = errors.New("invalid ticker symbol") diff --git a/exchanges/bitfinex/bitfinex_websocket.go b/exchanges/bitfinex/bitfinex_websocket.go index ed04da9988f..70db0f2af0b 100644 --- a/exchanges/bitfinex/bitfinex_websocket.go +++ b/exchanges/bitfinex/bitfinex_websocket.go @@ -1866,7 +1866,7 @@ func (b *Bitfinex) unsubscribeFromChan(chans subscription.List) error { // getErrResp takes a json response string and looks for an error event type // If found it parses the error code and message as a wrapped error and returns it // It might log parsing errors about the nature of the error -// If the error message is not defined it will return a wrapped errUnknownError +// If the error message is not defined it will return a wrapped common.ErrUnknownError func (b *Bitfinex) getErrResp(resp []byte) error { event, err := jsonparser.GetUnsafeString(resp, "event") if err != nil { @@ -1883,7 +1883,7 @@ func (b *Bitfinex) getErrResp(resp []byte) error { var apiErr error if msg, e2 := jsonparser.GetString(resp, "msg"); e2 != nil { log.Errorf(log.ExchangeSys, "%s %s 'msg': %s from message: %s", b.Name, errParsingWSField, e2, resp) - apiErr = errUnknownError + apiErr = common.ErrUnknownError } else { apiErr = errors.New(msg) } diff --git a/exchanges/kraken/kraken.go b/exchanges/kraken/kraken.go index af854208d41..28b1f405428 100644 --- a/exchanges/kraken/kraken.go +++ b/exchanges/kraken/kraken.go @@ -848,15 +848,10 @@ func (k *Kraken) SendHTTPRequest(ctx context.Context, ep exchange.URL, path stri return genResponse.Error.Errors() } - var genResp genericFuturesResponse - if err := json.Unmarshal(rawMessage, &genResp); err != nil { + if err := getFuturesErr(rawMessage); err != nil { return err } - if genResp.Error != "" && genResp.Result != "success" { - return errors.New(genResp.Error) - } - return json.Unmarshal(rawMessage, result) } diff --git a/exchanges/kraken/kraken_futures.go b/exchanges/kraken/kraken_futures.go index 2965c9374c9..28c7e79ab56 100644 --- a/exchanges/kraken/kraken_futures.go +++ b/exchanges/kraken/kraken_futures.go @@ -377,20 +377,45 @@ func (k *Kraken) SendFuturesAuthRequest(ctx context.Context, method, path string }, nil } - if err := k.SendPayload(ctx, request.Unset, newRequest, request.AuthenticatedRequest); err != nil { - return err + err = k.SendPayload(ctx, request.Unset, newRequest, request.AuthenticatedRequest) + + if err == nil { + err = getFuturesErr(interim) } - var resp genericFuturesResponse - if err := json.Unmarshal(interim, &resp); err != nil { - return fmt.Errorf("%w %w", request.ErrAuthRequestFailed, err) - } else if resp.Error != "" && resp.Result != "success" { - return fmt.Errorf("%w %v", request.ErrAuthRequestFailed, resp.Error) + if err == nil { + err = json.Unmarshal(interim, result) } - if err := json.Unmarshal(interim, result); err != nil { + if err != nil { return fmt.Errorf("%w %w", request.ErrAuthRequestFailed, err) } return nil } + +func getFuturesErr(msg json.RawMessage) error { + var resp genericFuturesResponse + if err := json.Unmarshal(msg, &resp); err != nil { + return err + } + + if resp.Result == "success" { + return nil + } + + var errs error + if resp.Error != "" { + errs = errors.New(resp.Error) + } + + for _, err := range resp.Errors { + errs = common.AppendError(errs, errors.New(err)) + } + + if errs == nil { + return fmt.Errorf("%w from message: %s", common.ErrUnknownError, m) + } + + return errs +} diff --git a/exchanges/kraken/kraken_types.go b/exchanges/kraken/kraken_types.go index 54c547ee7b7..595f71ddc27 100644 --- a/exchanges/kraken/kraken_types.go +++ b/exchanges/kraken/kraken_types.go @@ -93,6 +93,7 @@ type genericFuturesResponse struct { Result string `json:"result"` ServerTime time.Time `json:"serverTime"` Error string `json:"error"` + Errors []string `json:"errors"` } // Asset holds asset information diff --git a/exchanges/kraken/kraken_websocket.go b/exchanges/kraken/kraken_websocket.go index eedccc8ff49..9258a57351f 100644 --- a/exchanges/kraken/kraken_websocket.go +++ b/exchanges/kraken/kraken_websocket.go @@ -66,7 +66,6 @@ var ( m sync.Mutex errNoWebsocketOrderbookData = errors.New("no websocket orderbook data") errParsingWSField = errors.New("error parsing WS field") - errUnknownError = errors.New("unknown error") errCancellingOrder = errors.New("error cancelling order") ) @@ -1360,7 +1359,7 @@ func (k *Kraken) wsCancelOrder(orderID string) error { return nil } - err = errUnknownError + err = common.ErrUnknownError if msg, pErr := jsonparser.GetUnsafeString(resp, "errorMessage"); pErr == nil && msg != "" { err = errors.New(msg) }