2
2
package bitfinex
3
3
4
4
import (
5
+ "bytes"
5
6
"crypto/hmac"
6
7
"crypto/sha512"
7
- "encoding/base64"
8
8
"encoding/hex"
9
9
"encoding/json"
10
10
"fmt"
@@ -18,7 +18,7 @@ import (
18
18
19
19
const (
20
20
// BaseURL is the v2 REST endpoint.
21
- BaseURL = "https://api.bitfinex.com/v2"
21
+ BaseURL = "https://api.bitfinex.com/v2/ "
22
22
23
23
// WebSocketURL is the v2 Websocket endpoint.
24
24
WebSocketURL = "wss://api.bitfinex.com/ws/2"
@@ -38,6 +38,10 @@ type Client struct {
38
38
39
39
// Services
40
40
Websocket * bfxWebsocket
41
+ Orders * OrderService
42
+ Platform * PlatformService
43
+ Positions * PositionService
44
+ Trades * TradeService
41
45
}
42
46
43
47
func NewClient () * Client {
@@ -50,12 +54,16 @@ func NewClientWithHTTP(h *http.Client) *Client {
50
54
c := & Client {BaseURL : baseURL , HTTPClient : h }
51
55
52
56
c .Websocket = newBfxWebsocket (c , WebSocketURL )
57
+ c .Orders = & OrderService {client : c }
58
+ c .Platform = & PlatformService {client : c }
59
+ c .Positions = & PositionService {client : c }
60
+ c .Trades = & TradeService {client : c }
53
61
54
62
return c
55
63
}
56
64
57
65
// NewRequest create new API request. Relative url can be provided in refURL.
58
- func (c * Client ) newRequest (method string , refURL string , params url.Values ) (* http.Request , error ) {
66
+ func (c * Client ) newRequest (method string , refURL string , params url.Values , body io. Reader ) (* http.Request , error ) {
59
67
rel , err := url .Parse (refURL )
60
68
if err != nil {
61
69
return nil , err
@@ -65,7 +73,7 @@ func (c *Client) newRequest(method string, refURL string, params url.Values) (*h
65
73
}
66
74
67
75
u := c .BaseURL .ResolveReference (rel )
68
- req , err := http .NewRequest (method , u .String (), nil )
76
+ req , err := http .NewRequest (method , u .String (), body )
69
77
70
78
if err != nil {
71
79
return nil , err
@@ -76,39 +84,39 @@ func (c *Client) newRequest(method string, refURL string, params url.Values) (*h
76
84
77
85
// NewAuthenticatedRequest creates new http request for authenticated routes
78
86
func (c * Client ) newAuthenticatedRequest (m string , refURL string , data map [string ]interface {}) (* http.Request , error ) {
79
- req , err := c .newRequest (m , refURL , nil )
80
- if err != nil {
81
- return nil , err
82
- }
87
+ refURL = "auth/r/" + refURL
83
88
84
- payload := map [string ]interface {}{
85
- "request" : "/v2/" + refURL ,
86
- "nonce" : utils .GetNonce (),
89
+ if data == nil {
90
+ data = map [string ]interface {}{}
87
91
}
88
92
89
- for k , v := range data {
90
- payload [k ] = v
93
+ b , err := json .Marshal (data )
94
+ if err != nil {
95
+ return nil , err
91
96
}
92
97
93
- payloadJSON , err := json .Marshal (payload )
98
+ rd := bytes .NewReader (b )
99
+ req , err := c .newRequest (m , refURL , nil , rd )
94
100
if err != nil {
95
101
return nil , err
96
102
}
97
103
98
- payloadEnc := base64 .StdEncoding .EncodeToString (payloadJSON )
104
+ nonce := utils .GetNonce ()
105
+ message := "/api/v2/" + refURL + nonce + string (b )
106
+ sig := c .sign (message )
99
107
100
108
req .Header .Add ("Content-Type" , "application/json" )
101
109
req .Header .Add ("Accept" , "application/json" )
102
- req .Header .Add ("X-BFX-APIKEY " , c . APIKey )
103
- req .Header .Add ("X-BFX-PAYLOAD " , payloadEnc )
104
- req .Header .Add ("X-BFX-SIGNATURE " , c .signPayload ( payloadEnc ) )
110
+ req .Header .Add ("bfx-nonce " , nonce )
111
+ req .Header .Add ("bfx-signature " , sig )
112
+ req .Header .Add ("bfx-apikey " , c .APIKey )
105
113
106
114
return req , nil
107
115
}
108
116
109
- func (c * Client ) signPayload ( payload string ) string {
117
+ func (c * Client ) sign ( msg string ) string {
110
118
sig := hmac .New (sha512 .New384 , []byte (c .APISecret ))
111
- sig .Write ([]byte (payload ))
119
+ sig .Write ([]byte (msg ))
112
120
return hex .EncodeToString (sig .Sum (nil ))
113
121
}
114
122
@@ -158,14 +166,40 @@ func checkResponse(r *Response) error {
158
166
return nil
159
167
}
160
168
169
+ var raw []interface {}
161
170
// Try to decode error message
162
171
errorResponse := & ErrorResponse {Response : r }
163
- err := json .Unmarshal (r .Body , errorResponse )
172
+ err := json .Unmarshal (r .Body , & raw )
164
173
if err != nil {
165
174
errorResponse .Message = "Error decoding response error message. " +
166
175
"Please see response body for more information."
176
+ return errorResponse
177
+ }
178
+
179
+ if len (raw ) < 3 {
180
+ errorResponse .Message = fmt .Sprintf ("Expected response to have three elements but got %#v" , raw )
181
+ return errorResponse
167
182
}
168
183
184
+ if str , ok := raw [0 ].(string ); ! ok || str != "error" {
185
+ errorResponse .Message = fmt .Sprintf ("Expected first element to be \" error\" but got %#v" , raw )
186
+ return errorResponse
187
+ }
188
+
189
+ code , ok := raw [1 ].(float64 )
190
+ if ! ok {
191
+ errorResponse .Message = fmt .Sprintf ("Expected second element to be error code but got %#v" , raw )
192
+ return errorResponse
193
+ }
194
+ errorResponse .Code = int (code )
195
+
196
+ msg , ok := raw [2 ].(string )
197
+ if ! ok {
198
+ errorResponse .Message = fmt .Sprintf ("Expected third element to be error message but got %#v" , raw )
199
+ return errorResponse
200
+ }
201
+ errorResponse .Message = msg
202
+
169
203
return errorResponse
170
204
}
171
205
@@ -174,14 +208,16 @@ func checkResponse(r *Response) error {
174
208
type ErrorResponse struct {
175
209
Response * Response
176
210
Message string `json:"message"`
211
+ Code int `json:"code"`
177
212
}
178
213
179
214
func (r * ErrorResponse ) Error () string {
180
- return fmt .Sprintf ("%v %v: %d %v" ,
215
+ return fmt .Sprintf ("%v %v: %d %v (%d) " ,
181
216
r .Response .Response .Request .Method ,
182
217
r .Response .Response .Request .URL ,
183
218
r .Response .Response .StatusCode ,
184
219
r .Message ,
220
+ r .Code ,
185
221
)
186
222
}
187
223
@@ -194,7 +230,6 @@ func (c *Client) do(req *http.Request, v interface{}) (*Response, error) {
194
230
defer resp .Body .Close ()
195
231
196
232
response := newResponse (resp )
197
-
198
233
err = checkResponse (response )
199
234
if err != nil {
200
235
return response , err
0 commit comments