Skip to content

Commit

Permalink
CB websocket tidying up
Browse files Browse the repository at this point in the history
  • Loading branch information
cranktakular committed Jan 31, 2024
1 parent 35eda67 commit 6ac86cd
Show file tree
Hide file tree
Showing 6 changed files with 291 additions and 186 deletions.
51 changes: 5 additions & 46 deletions exchanges/coinbasepro/coinbasepro.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ const (
errUnknownEndpointLimit = "unknown endpoint limit %v"
errUnknownL2DataType = "unknown l2update data type %v"
errUnknownSide = "unknown side %v"
warnSequenceIssue = "Out of order sequence number. Received %v, expected %v"
)

var (
Expand Down Expand Up @@ -119,8 +120,8 @@ var (
errNameEmpty = errors.New("name cannot be empty")
errPortfolioIDEmpty = errors.New("portfolio id cannot be empty")
errFeeTypeNotSupported = errors.New("fee type not supported")
errNoEventsWS = errors.New("no events returned from websocket")
errCantDecodePrivKey = errors.New("cannot decode private key")
errNoWalletForCurrency = errors.New("no wallet found for currency, address creation impossible")
)

// GetAllAccounts returns information on all trading accounts associated with the API key
Expand Down Expand Up @@ -474,7 +475,7 @@ func (c *CoinbasePro) GetAllOrders(ctx context.Context, productID, userNativeCur
pathParams, nil, true, &resp, nil)
}

// GetFills returns information of recent fills on the specified profile
// GetFills returns information of recent fills on the specified order
func (c *CoinbasePro) GetFills(ctx context.Context, orderID, productID, cursor string, startDate, endDate time.Time, limit uint16) (FillResponse, error) {
var resp FillResponse
var params Params
Expand Down Expand Up @@ -503,14 +504,14 @@ func (c *CoinbasePro) GetFills(ctx context.Context, orderID, productID, cursor s
}

// GetOrderByID returns a single order by order id.
func (c *CoinbasePro) GetOrderByID(ctx context.Context, orderID, clientID, userNativeCurrency string) (*GetOrderResponse, error) {
func (c *CoinbasePro) GetOrderByID(ctx context.Context, orderID, clientOID, userNativeCurrency string) (*GetOrderResponse, error) {
if orderID == "" {
return nil, errOrderIDEmpty
}
var resp GetOrderResponse
var params Params
params.urlVals = url.Values{}
params.urlVals.Set("client_order_id", clientID)
params.urlVals.Set("client_order_id", clientOID)
params.urlVals.Set("user_native_currency", userNativeCurrency)

path := fmt.Sprintf("%s%s/%s/%s", coinbaseV3, coinbaseOrders, coinbaseHistorical, orderID)
Expand Down Expand Up @@ -854,20 +855,6 @@ func (c *CoinbasePro) UpdateUser(ctx context.Context, name, timeZone, nativeCurr
coinbaseV2+coinbaseUser, "", req, false, &resp, nil)
}

// CreateWallet creates a new wallet for the specified currency
func (c *CoinbasePro) CreateWallet(ctx context.Context, currency string) (*GenWalletResponse, error) {
if currency == "" {
return nil, errCurrencyEmpty
}

path := fmt.Sprintf("%s%s/%s", coinbaseV2, coinbaseAccounts, currency)

var resp *GenWalletResponse

return resp, c.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodGet,
path, "", nil, false, &resp, nil)
}

// GetAllWallets lists all accounts associated with the API key
func (c *CoinbasePro) GetAllWallets(ctx context.Context, pag PaginationInp) (GetAllWalletsResponse, error) {
var resp GetAllWalletsResponse
Expand Down Expand Up @@ -904,34 +891,6 @@ func (c *CoinbasePro) GetWalletByID(ctx context.Context, walletID, currency stri
path, "", nil, false, &resp, nil)
}

// UpdateWalletName updates the name of a wallet
func (c *CoinbasePro) UpdateWalletName(ctx context.Context, walletID, newName string) (*GenWalletResponse, error) {
if walletID == "" {
return nil, errWalletIDEmpty
}

path := fmt.Sprintf("%s%s/%s", coinbaseV2, coinbaseAccounts, walletID)

req := map[string]interface{}{"name": newName}

var resp *GenWalletResponse

return resp, c.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodPut,
path, "", req, false, &resp, nil)
}

// DeleteWallet deletes a wallet
func (c *CoinbasePro) DeleteWallet(ctx context.Context, walletID string) error {
if walletID == "" {
return errWalletIDEmpty
}

path := fmt.Sprintf("%s%s/%s", coinbaseV2, coinbaseAccounts, walletID)

return c.SendAuthenticatedHTTPRequest(ctx, exchange.RestSpot, http.MethodDelete, path, "", nil,
false, nil, nil)
}

// CreateAddress generates a crypto address for depositing to the specified wallet
func (c *CoinbasePro) CreateAddress(ctx context.Context, walletID, name string) (*GenAddrResponse, error) {
if walletID == "" {
Expand Down
129 changes: 73 additions & 56 deletions exchanges/coinbasepro/coinbasepro_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"testing"
"time"

"github.com/buger/jsonparser"
"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/common"
Expand All @@ -25,6 +26,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
gctlog "github.com/thrasher-corp/gocryptotrader/log"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
)
Expand Down Expand Up @@ -76,6 +78,8 @@ const (
errExpectedFeeRange = "expected fee range of %v and %v, received %v"
errJsonNumberIntoString = "json: cannot unmarshal number into Go value of type string"
errParseIntValueOutOfRange = `strconv.ParseInt: parsing "922337203685477580700": value out of range`
errParseUintInvalidSyntax = `strconv.ParseUint: parsing "l": invalid syntax`
errJsonInvalidCharacter = `invalid character ':' after array element`

expectedTimestamp = "1970-01-01 00:20:34 +0000 UTC"

Expand Down Expand Up @@ -822,19 +826,6 @@ func TestUpdateUser(t *testing.T) {
assert.NotEmpty(t, resp, errExpectedNonEmpty)
}

func TestCreateWallet(t *testing.T) {
_, err := c.CreateWallet(context.Background(), "")
if !errors.Is(err, errCurrencyEmpty) {
t.Errorf(errExpectMismatch, err, errCurrencyEmpty)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, c, canManipulateRealOrders)
resp, err := c.CreateWallet(context.Background(), testCrypto.String())
if err != nil {
t.Error(err)
}
assert.NotEmpty(t, resp, errExpectedNonEmpty)
}

func TestGetAllWallets(t *testing.T) {
sharedtestvalues.SkipTestIfCredentialsUnset(t, c)
pagIn := PaginationInp{Limit: 2}
Expand Down Expand Up @@ -872,46 +863,6 @@ func TestGetWalletByID(t *testing.T) {
assert.NotEmpty(t, resp, errExpectedNonEmpty)
}

func TestUpdateWalletName(t *testing.T) {
_, err := c.UpdateWalletName(context.Background(), "", "")
if !errors.Is(err, errWalletIDEmpty) {
t.Errorf(errExpectMismatch, err, errWalletIDEmpty)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, c, canManipulateRealOrders)
wID, err := c.GetAllWallets(context.Background(), PaginationInp{})
if err != nil {
t.Error(err)
}
if len(wID.Data) == 0 {
t.Fatal(errExpectedNonEmpty)
}
resp, err := c.UpdateWalletName(context.Background(), wID.Data[len(wID.Data)-1].ID, "Wallet Tested by GCT")
if err != nil {
t.Error(err)
}
assert.NotEmpty(t, resp, errExpectedNonEmpty)
}

func TestDeleteWallet(t *testing.T) {
err := c.DeleteWallet(context.Background(), "")
if !errors.Is(err, errWalletIDEmpty) {
t.Errorf(errExpectMismatch, err, errWalletIDEmpty)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, c, canManipulateRealOrders)
wID, err := c.CreateWallet(context.Background(), testCrypto.String())
if err != nil {
t.Error(err)
}
// As of now, it seems like this next step always fails. DeleteWallet only lets you delete non-primary
// non-fiat wallets, but the only non-primary wallet is fiat. Trying to create a secondary wallet for
// any cryptocurrency using CreateWallet simply returns the details of the existing primary wallet.
t.Skip("endpoint bugged on their end, skipping")
err = c.DeleteWallet(context.Background(), wID.Data.ID)
if err != nil {
t.Error(err)
}
}

func TestCreateAddress(t *testing.T) {
_, err := c.CreateAddress(context.Background(), "", "")
if !errors.Is(err, errWalletIDEmpty) {
Expand Down Expand Up @@ -1765,8 +1716,12 @@ func TestGetOrderInfo(t *testing.T) {
}

func TestGetDepositAddress(t *testing.T) {
sharedtestvalues.SkipTestIfCredentialsUnset(t, c, canManipulateRealOrders)
_, err := c.GetDepositAddress(context.Background(), currency.BTC, "", "")
sharedtestvalues.SkipTestIfCredentialsUnset(t, c)
_, err := c.GetDepositAddress(context.Background(), currency.NewCode("fake currency that doesn't exist"), "", "")
if !errors.Is(err, errNoWalletForCurrency) {
t.Errorf(errExpectMismatch, err, errNoWalletForCurrency)
}
_, err = c.GetDepositAddress(context.Background(), testCrypto, "", "")
if err != nil {
t.Error(err)
}
Expand Down Expand Up @@ -2114,8 +2069,70 @@ func TestStringToFloatPtr(t *testing.T) {
}
}

func TestWsSomethingOrOther(t *testing.T) {
func TestWsConnect(t *testing.T) {
c.Websocket.Disable()

Check failure on line 2073 in exchanges/coinbasepro/coinbasepro_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `c.Websocket.Disable` is not checked (errcheck)
err := c.WsConnect()
if err.Error() != stream.WebsocketNotEnabled {
t.Errorf(errExpectMismatch, err, stream.WebsocketNotEnabled)
}
c.Websocket.Enable()

Check failure on line 2078 in exchanges/coinbasepro/coinbasepro_test.go

View workflow job for this annotation

GitHub Actions / lint

Error return value of `c.Websocket.Enable` is not checked (errcheck)
err = c.WsConnect()
if err != nil {
t.Error(err)
}
}

func TestWsHandleData(t *testing.T) {
c.Websocket.DataHandler = make(chan interface{}, 4)
_, err := c.wsHandleData(nil, 0)
if !errors.Is(err, jsonparser.KeyPathNotFoundError) {
t.Errorf(errExpectMismatch, err, jsonparser.KeyPathNotFoundError)
}
mockJson := []byte(`{"sequence_num": "l"}`)
_, err = c.wsHandleData(mockJson, 0)
if err.Error() != errParseUintInvalidSyntax {
t.Errorf(errExpectMismatch, err, errParseUintInvalidSyntax)
}
mockJson = []byte(`{"sequence_num": 1, /\\/"""}`)
_, err = c.wsHandleData(mockJson, 0)
if !errors.Is(err, jsonparser.KeyPathNotFoundError) {
t.Errorf(errExpectMismatch, err, jsonparser.KeyPathNotFoundError)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "subscriptions"}`)
_, err = c.wsHandleData(mockJson, 0)
if err != nil {
t.Error(err)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "", "events":}`)
_, err = c.wsHandleData(mockJson, 0)
if !errors.Is(err, jsonparser.UnknownValueTypeError) {
t.Errorf(errExpectMismatch, err, jsonparser.UnknownValueTypeError)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "status", "events": ["type": 1234]}`)
_, err = c.wsHandleData(mockJson, 0)
if err.Error() != errJsonInvalidCharacter {
t.Errorf(errExpectMismatch, err, errJsonInvalidCharacter)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "status", "events": [{"type": "moo"}]}`)
_, err = c.wsHandleData(mockJson, 0)
if err != nil {
t.Error(err)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "error", "events": [{"type": "moo"}]}`)
_, err = c.wsHandleData(mockJson, 0)
if err != nil {
t.Error(err)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "ticker", "events": ["type": ""}]}`)
_, err = c.wsHandleData(mockJson, 0)
if err.Error() != errJsonInvalidCharacter {
t.Errorf(errExpectMismatch, err, errJsonInvalidCharacter)
}
mockJson = []byte(`{"sequence_num": 0, "channel": "ticker", "events": [{"type": "moo", "tickers": [{"price": "1.1"}]}]}`)
_, err = c.wsHandleData(mockJson, 0)
if err != nil {
t.Error(err)
}
}

func skipTestIfLowOnFunds(t *testing.T) {
Expand Down
14 changes: 7 additions & 7 deletions exchanges/coinbasepro/coinbasepro_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1251,13 +1251,13 @@ type WebsocketOrderDataHolder struct {
// Changes [][3]string `json:"changes"`
// }

type wsGen struct {
Channel string `json:"channel"`
ClientID string `json:"client_id"`
Timestamp time.Time `json:"timestamp"`
SequenceNum uint64 `json:"sequence_num"`
Events []interface{} `json:"events"`
}
// type wsGen struct {
// Channel string `json:"channel"`
// ClientID string `json:"client_id"`
// Timestamp time.Time `json:"timestamp"`
// SequenceNum uint64 `json:"sequence_num"`
// Events []interface{} `json:"events"`
// }

// type wsStatus struct {
// Currencies []struct {
Expand Down
Loading

0 comments on commit 6ac86cd

Please sign in to comment.