首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >发送post请求时使用c#的bybit签名错误

发送post请求时使用c#的bybit签名错误
EN

Stack Overflow用户
提问于 2021-11-03 19:42:38
回答 2查看 404关注 0票数 2

我尝试向bybit api发送一个简单的post请求,但一直收到10004 sign错误。以下是响应:

代码语言:javascript
复制
{"ret_code":10004,"ret_msg":"error sign! origin_string[api_key=(my api key)\u0026symbol=BTCUSDT\u0026timestamp=1635967650768]","ext_code":"","ext_info":"","result":null,"time_now":"1635967651.397800"}

这是我用来发送请求的代码。

代码语言:javascript
复制
public async static Task<string> cancelAllOrders()
    {
        string ts = await GenerateTimeStamp();
        string paramString = "api_key=" + apiKey + "&symbol=BTCUSDT" + "timestamp=" + ts;
        string sign = CreateSignature(secretKey, paramString);
        CancelOrderContent co = new CancelOrderContent(apiKey, "BTCUSDT", ts, sign);

        var client = new RestClient(ApiUrl + "/v2/private/order/cancelAll");
        var request = new RestRequest();
        request.AddJsonBody(co);
        var response = client.Post(request);
        Trace.WriteLine(response.StatusCode.ToString() + "   " + response);
        return "";
    }

下面是我为请求正文序列化为JSON的类。

代码语言:javascript
复制
public class CancelOrderContent
    {
        public string api_key;
        public string sign;
        public string symbol;
        public string timestamp;

        public CancelOrderContent(string api_key, string symbol, string timestamp,string sign)
        {
            this.api_key = api_key;
            this.symbol = symbol;
            this.timestamp = timestamp;
            this.sign = sign;
        }
    }

下面是我用来创建签名的代码:

代码语言:javascript
复制
public static string CreateSignature(string secret, string message)
        {
            var signatureBytes = Hmacsha256(Encoding.UTF8.GetBytes(secret), Encoding.UTF8.GetBytes(message));

            return ByteArrayToString(signatureBytes);
        }

        private static byte[] Hmacsha256(byte[] keyByte, byte[] messageBytes)
        {
            using (var hash = new HMACSHA256(keyByte))
            {
                return hash.ComputeHash(messageBytes);
            }
        }

我尝试了各种方法来解决这个问题,但我似乎无法摆脱它。我尝试了多个端点,但仍然得到相同的错误。

EN

回答 2

Stack Overflow用户

发布于 2021-12-01 15:13:14

2022/01/17仍然有效。

嘿@Vexatious我在bybit-api尝试提交订单时遇到了类似的问题,尽管我知道我的密钥设置正确,但我仍然收到密钥被拒绝,权限不足的错误。

也许ByBit改变了什么?Lib过时了?谁知道呢。

我注意到的一件主要事情是,在将签名附加到请求正文之前,它们要求您按字母顺序对参数进行排序。

编辑:更新是因为我认识到GET请求也同样令人困惑。向下滚动查看POST请求示例。

GETPOST请求的处理方式不同

数据{

  1. axios(https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=sign)
  2. axios(https://api-testnet.bybit.com/POST,:queryString})

签名

两个的:在生成签名之前,您必须按字母顺序排列参数。

  1. 获取包含‘API _ alphabetically.
  2. Iterate’的单个对象的查询参数,不包括API Secret。
  3. 将查询参数的QueryString排序到对象的排序关键字上,构建一个符号,如下面的示例所示
  4. 使用带十六进制摘要的hmac sha256创建符号(查看底部的./QueryString)

例如:"aParam=foo&bParam=bar",

这就是我们要处理的sign参数。

GET请求:将sign参数附加到QueryString的末尾并发送,可能需要使用标头

代码语言:javascript
复制
// Might still need {'Content-Type': 'application/x-www-form-urlencoded'}
// header depending on what request lib you're using.

const url = "https://api-testnet.bybit.com/GET?aParam=foo&bParam=bar&sign=" + sign

POST请求:要求对象作为请求数据(仍然是类似于上面的QueryString的形式)发送,而不是类似于GET请求的完全构建的Http字符串。将sign参数添加到您用来生成签名的QueryString的末尾,将其分配给您的请求处理程序data参数,然后继续执行!

我确实想出了一个最小的工作版本,成功地在他们的testnet上发布了一个现货订单,这是jest测试。

./bybit.test.ts

代码语言:javascript
复制
test("WORKING BYBIT TRADE.", async () => {
        const serverTime:number = (await axios.get(`https://api-testnet.bybit.com/spot/v1/time`)).data

        // These need to be within 1000ms of eachother (I'm pree sure, their formula is kinda confusing)
        console.log(`Their Timestamp`, serverTime)
        console.log(`Our Timestamp`, Date.now())

        const queryParams = {
            // Alphabetically ordered
            // (Sign generation function should deal with unordered params using .sort())
            'api_key': bybitApiKey,
            qty:10,
            recvWindow: 10000,
            side:"BUY",
            symbol:"ETHUSDT",
            timestamp: Date.now(),
            type:"MARKET",
        }

        const queryString = querystring.stringify(queryParams)
        const sign = "&sign=" + getSignature(queryParams, bybitSecret)
        const fullQuery = queryString + sign

        console.log(`FullQuery example`, fullQuery) 
        // api_key=...&qty=10&recvWindow=10000&side=BUY&symbol=ETHUSDT&timestamp=1638371037593&type=MARKET&sign=...

        let result = await axios(`https://api-testnet.bybit.com/spot/v1/order`, {
            withCredentials: true,
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            method: "POST",
            data: fullQuery,
        })

        console.log(`Post Status`, result.status)
        console.log(`Post Body`, result.data)
    })

    /**
        Post Status 200
        
        Post Body {
          ret_code: 0,
          ret_msg: '',
          ext_code: null,
          ext_info: null,
          result: {
            accountId: '...',
            symbol: 'ETHUSDT',
            symbolName: 'ETHUSDT',
            orderLinkId: '...',
            orderId: '...',
            transactTime: '...',
            price: '0',
            origQty: '10',
            executedQty: '0',
            status: 'FILLED',
            timeInForce: 'GTC',
            type: 'MARKET',
            side: 'BUY'
          }
    */
    }

./sign.ts

代码语言:javascript
复制
import crypto from 'crypto'

export function getSignature(parameters: any, secret: string) {
    var orderedParams = "";

    Object.keys(parameters).sort().forEach(function(key) {
        orderedParams += key + "=" + parameters[key] + "&";
    });
    orderedParams = orderedParams.substring(0, orderedParams.length - 1);

    return crypto.createHmac('sha256', secret).update(orderedParams).digest('hex');
}

希望这能有所帮助!

票数 2
EN

Stack Overflow用户

发布于 2021-11-06 04:37:16

我刚刚为Javascript应用编程接口弄明白了这一点,但使用的是ByBit而不是C#。然而,我确实了解C#,所以希望这能为你工作。

使用POST的HMAC端点需要与GET请求中相同的ByBit数据加密。您可以执行以下操作,而不是对查询字符串中的参数进行签名(并向其追加&sign=xxxx ):

  • 对序列化的对象进行签名,
  • 然后在POST之前将object.sign = "xxxx“添加到对象中。

这就是C#类变得棘手的地方。您有一个带有sign属性的CancelOrderContent。这将使用空值序列化键'sign‘。但是,ByBit应用编程接口不会接受这一点,因为签名的数据将不同。

你要么必须

  • 序列化没有‘CancelOrderContent
  • add’密钥( CancelOrderContentNosignkey )的对象,
  • 将属性从CancelOrderContentNosignkey复制到新的CancelOrderContent签名散列字符串到CancelOrderContent object.sign
  • ,然后使用签名密钥/值对

发布序列化对象

或者..。

  • 按您现在的方式序列化对象,
  • ,但随后删除序列化的字符串以删除,"sign":''部件。然后,
  • 对该字符串进行签名,
  • 然后将符号值添加到对象,<代码>H225<代码>H126再次将其序列化为JSON,然后<代码>H227<代码>H128将其作为数据发布。<代码>H229<代码>F230

我相信这将会起作用,因为我必须这样做才能让它在JS中工作。但是,添加符号键/值更容易,因为没有类。

它的一个变体是将CancelOrderContent设置为动态类型,其中直到序列化/签名之后才添加“sign”键/值。

注意,当您手动将对象序列化为JSON时(不要使用paramString),理论上序列化程序应该与RestRequest.AddJsonBody()中使用或配置的序列化程序相同。

抱歉,我没有C#代码,但这应该可以工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69830871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档