From 6da0b7dce542c158fac7dc039c27b28be4be9899 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:07:30 +1100 Subject: [PATCH 1/3] build(deps): Bump golang.org/x/time from 0.8.0 to 0.9.0 (#1768) Bumps [golang.org/x/time](https://github.com/golang/time) from 0.8.0 to 0.9.0. - [Commits](https://github.com/golang/time/compare/v0.8.0...v0.9.0) --- updated-dependencies: - dependency-name: golang.org/x/time dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0c866fe14aa..310b1caa855 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( golang.org/x/net v0.33.0 golang.org/x/term v0.27.0 golang.org/x/text v0.21.0 - golang.org/x/time v0.8.0 + golang.org/x/time v0.9.0 google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb google.golang.org/grpc v1.69.2 google.golang.org/protobuf v1.36.1 diff --git a/go.sum b/go.sum index aa402b4a5f9..c838c51e7df 100644 --- a/go.sum +++ b/go.sum @@ -335,8 +335,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= -golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 5ae149a0636767efb3bf89519fbdf60b78337da2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 17:33:36 +1100 Subject: [PATCH 2/3] build(deps): Bump golang.org/x/term from 0.27.0 to 0.28.0 (#1767) Bumps [golang.org/x/term](https://github.com/golang/term) from 0.27.0 to 0.28.0. - [Commits](https://github.com/golang/term/compare/v0.27.0...v0.28.0) --- updated-dependencies: - dependency-name: golang.org/x/term dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 310b1caa855..1a235db3f1d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/volatiletech/null v8.0.0+incompatible golang.org/x/crypto v0.31.0 golang.org/x/net v0.33.0 - golang.org/x/term v0.27.0 + golang.org/x/term v0.28.0 golang.org/x/text v0.21.0 golang.org/x/time v0.9.0 google.golang.org/genproto/googleapis/api v0.0.0-20241219192143-6b3ec007d9bb @@ -66,7 +66,7 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241219192143-6b3ec007d9bb // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index c838c51e7df..7cac7b14d29 100644 --- a/go.sum +++ b/go.sum @@ -325,10 +325,10 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190927073244-c990c680b611/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= From fcd78add9694a4a5b539ff58a043076d60ae1d7d Mon Sep 17 00:00:00 2001 From: Ryan O'Hara-Reid Date: Tue, 7 Jan 2025 12:03:32 +1100 Subject: [PATCH 3/3] bybit: Add protected subtype for account checking to reduce outbound requests (#1739) * bybit: Add protected sub type for account checking to reduce outbound requests * add type and string method plus fix linter with comment * linter: fix * whoops * Update exchanges/bybit/bybit.go Co-authored-by: Scott * Update exchanges/bybit/bybit.go Co-authored-by: Scott * glorious: nits --------- Co-authored-by: Ryan O'Hara-Reid Co-authored-by: Scott --- exchanges/bybit/bybit.go | 67 ++++++++++++++++++++---------- exchanges/bybit/bybit_live_test.go | 4 +- exchanges/bybit/bybit_test.go | 33 ++++++++++++--- exchanges/bybit/bybit_types.go | 24 +++++++++++ exchanges/bybit/bybit_wrapper.go | 4 +- 5 files changed, 100 insertions(+), 32 deletions(-) diff --git a/exchanges/bybit/bybit.go b/exchanges/bybit/bybit.go index 2a5503a73de..6ff82ea5f0a 100644 --- a/exchanges/bybit/bybit.go +++ b/exchanges/bybit/bybit.go @@ -27,10 +27,7 @@ import ( // Bybit is the overarching type across this package type Bybit struct { exchange.Base - - // AccountType holds information about whether the account to which the api key belongs is a unified margin account or not. - // 0: unified, and 1: for normal account - AccountType int64 + account accountTypeHolder } const ( @@ -45,8 +42,8 @@ const ( cSpot, cLinear, cOption, cInverse = "spot", "linear", "option", "inverse" - accountTypeNormal = 0 // 0: regular account - accountTypeUnified = 1 // 1: unified trade account + accountTypeNormal AccountType = 1 + accountTypeUnified AccountType = 2 longDatedFormat = "02Jan06" ) @@ -1176,8 +1173,9 @@ func (by *Bybit) GetPreUpgradeOrderHistory(ctx context.Context, category, symbol if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } var resp *TradeOrders return resp, by.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, "/v5/pre-upgrade/order/history", params, nil, &resp, defaultEPL) @@ -1189,8 +1187,9 @@ func (by *Bybit) GetPreUpgradeTradeHistory(ctx context.Context, category, symbol if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } if executionType != "" { params.Set("executionType", executionType) @@ -1205,8 +1204,9 @@ func (by *Bybit) GetPreUpgradeClosedPnL(ctx context.Context, category, symbol, c if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } var resp *ClosedProfitAndLossResponse return resp, by.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, "/v5/pre-upgrade/position/closed-pnl", params, nil, &resp, defaultEPL) @@ -1218,8 +1218,9 @@ func (by *Bybit) GetPreUpgradeTransactionLog(ctx context.Context, category, base if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } if transactionType != "" { params.Set("type", transactionType) @@ -1234,8 +1235,9 @@ func (by *Bybit) GetPreUpgradeOptionDeliveryRecord(ctx context.Context, category if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } if !expiryDate.IsZero() { params.Set("expData", expiryDate.Format(longDatedFormat)) @@ -1250,8 +1252,9 @@ func (by *Bybit) GetPreUpgradeUSDCSessionSettlement(ctx context.Context, categor if err != nil { return nil, err } - if by.AccountType == accountTypeNormal { - return nil, errAPIKeyIsNotUnified + err = by.RequiresUnifiedAccount(ctx) + if err != nil { + return nil, err } var resp *SettlementSession return resp, by.SendAuthHTTPRequestV5(ctx, exchange.RestSpot, http.MethodGet, "/v5/pre-upgrade/asset/settlement-record", params, nil, &resp, defaultEPL) @@ -2699,13 +2702,31 @@ func getSign(sign, secret string) (string, error) { return crypto.HexEncodeToString(hmacSigned), nil } -// RetrieveAndSetAccountType retrieve to set account type information -func (by *Bybit) RetrieveAndSetAccountType(ctx context.Context) error { - accInfo, err := by.GetAPIKeyInformation(ctx) +// FetchAccountType if not set fetches the account type from the API, stores it and returns it. Else returns the stored account type. +func (by *Bybit) FetchAccountType(ctx context.Context) (AccountType, error) { + by.account.m.Lock() + defer by.account.m.Unlock() + if by.account.accountType == 0 { + accInfo, err := by.GetAPIKeyInformation(ctx) + if err != nil { + return 0, err + } + // From endpoint 0:regular account; 1:unified trade account + // + 1 to make it 1 and 2 so that a zero value can be used to check if the account type has been set or not. + by.account.accountType = AccountType(accInfo.IsUnifiedTradeAccount + 1) + } + return by.account.accountType, nil +} + +// RequiresUnifiedAccount checks account type and returns error if not unified +func (by *Bybit) RequiresUnifiedAccount(ctx context.Context) error { + at, err := by.FetchAccountType(ctx) if err != nil { - return err + return nil //nolint:nilerr // if we can't get the account type, we can't check if it's unified or not, fail on call + } + if at != accountTypeUnified { + return fmt.Errorf("%w, account type: %s", errAPIKeyIsNotUnified, at) } - by.AccountType = accInfo.IsUnifiedTradeAccount // 0:regular account; 1:unified trade account return nil } diff --git a/exchanges/bybit/bybit_live_test.go b/exchanges/bybit/bybit_live_test.go index fc792be0955..299e9e2dc42 100644 --- a/exchanges/bybit/bybit_live_test.go +++ b/exchanges/bybit/bybit_live_test.go @@ -31,8 +31,8 @@ func TestMain(m *testing.M) { } if b.API.AuthenticatedSupport { - if err := b.RetrieveAndSetAccountType(context.Background()); err != nil { - log.Printf("%s unable to RetrieveAndSetAccountType: %v", b.Name, err) + if _, err := b.FetchAccountType(context.Background()); err != nil { + log.Printf("%s unable to FetchAccountType: %v", b.Name, err) } } diff --git a/exchanges/bybit/bybit_test.go b/exchanges/bybit/bybit_test.go index 4259eab31a7..9fa89c6fa13 100644 --- a/exchanges/bybit/bybit_test.go +++ b/exchanges/bybit/bybit_test.go @@ -3548,12 +3548,35 @@ func TestStringToOrderStatus(t *testing.T) { } } -func TestRetrieveAndSetAccountType(t *testing.T) { - sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders) - err := b.RetrieveAndSetAccountType(context.Background()) - if err != nil { - t.Fatal(err) +func TestFetchAccountType(t *testing.T) { + t.Parallel() + if !mockTests { + sharedtestvalues.SkipTestIfCredentialsUnset(t, b) } + val, err := b.FetchAccountType(context.Background()) + require.NoError(t, err) + require.NotZero(t, val) +} + +func TestAccountTypeString(t *testing.T) { + t.Parallel() + require.Equal(t, "unset", AccountType(0).String()) + require.Equal(t, "unified", accountTypeUnified.String()) + require.Equal(t, "normal", accountTypeNormal.String()) + require.Equal(t, "unknown", AccountType(3).String()) +} + +func TestRequiresUnifiedAccount(t *testing.T) { + t.Parallel() + if !mockTests { + sharedtestvalues.SkipTestIfCredentialsUnset(t, b) + } + err := b.RequiresUnifiedAccount(context.Background()) + require.NoError(t, err) + b := &Bybit{} //nolint:govet // Intentional shadow to avoid future copy/paste mistakes. Also stops race below. + b.account.accountType = accountTypeNormal + err = b.RequiresUnifiedAccount(context.Background()) + require.ErrorIs(t, err, errAPIKeyIsNotUnified) } func TestGetLatestFundingRates(t *testing.T) { diff --git a/exchanges/bybit/bybit_types.go b/exchanges/bybit/bybit_types.go index 656a4d2ffa7..16114557684 100644 --- a/exchanges/bybit/bybit_types.go +++ b/exchanges/bybit/bybit_types.go @@ -2,6 +2,7 @@ package bybit import ( "encoding/json" + "sync" "time" "github.com/gofrs/uuid" @@ -2035,3 +2036,26 @@ type Error struct { ExtCode string `json:"ext_code"` ExtMsg string `json:"ext_info"` } + +// accountTypeHolder holds the account type associated with the loaded API key. +type accountTypeHolder struct { + accountType AccountType + m sync.Mutex +} + +// AccountType constants +type AccountType uint8 + +// String returns the account type as a string +func (a AccountType) String() string { + switch a { + case 0: + return "unset" + case accountTypeNormal: + return "normal" + case accountTypeUnified: + return "unified" + default: + return "unknown" + } +} diff --git a/exchanges/bybit/bybit_wrapper.go b/exchanges/bybit/bybit_wrapper.go index acb3ae66949..1d473a47830 100644 --- a/exchanges/bybit/bybit_wrapper.go +++ b/exchanges/bybit/bybit_wrapper.go @@ -562,7 +562,7 @@ func (by *Bybit) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a var acc account.SubAccount var accountType string info.Exchange = by.Name - err := by.RetrieveAndSetAccountType(ctx) + at, err := by.FetchAccountType(ctx) if err != nil { return info, err } @@ -570,7 +570,7 @@ func (by *Bybit) UpdateAccountInfo(ctx context.Context, assetType asset.Item) (a case asset.Spot, asset.Options, asset.USDCMarginedFutures, asset.USDTMarginedFutures: - switch by.AccountType { + switch at { case accountTypeUnified: accountType = "UNIFIED" case accountTypeNormal: