#ifndef COINBASE_SUBSCRIPTION_H #define COINBASE_SUBSCRIPTION_H #include #include #include #include #include #include #include //------------------------------------------------------------------------------ namespace coinbase { static Json::Value GetSubscribeMsg() { Json::Value root; std::string api_key = "eefbcbb8-281f-433a-a5f0-e9d9391e33d6"; std::string secret = "K276bkmMolDW6zHmmC47tBXy0DTUKvdT"; std::string channel_name = "level2"; std::vector crypto_ids = {"BTC-USD"}; root["type"] = Json::Value("subscribe"); Json::Value product_ids(Json::ValueType::arrayValue); size_t index = 0; for (auto i: crypto_ids) { product_ids.insert(index++, i); } root["product_ids"] = product_ids; root["channel"] = "level2"; root["api_key"] = api_key; // The new way using clock = std::chrono::system_clock; std::time_t now = clock::to_time_t(clock::now()); root["timestamp"] = std::to_string(now); // The signature should be created by first concatenating the // UNIX timestamp and channel name and then concatenating and // comma-seprating the list of product Ids. Then hashing the // phrase using Hmac256 with the secret key. // --------------------------------------------------------- std::string signature = std::to_string(now) + channel_name; if (crypto_ids.size() == 1) signature += crypto_ids.front(); else { for (auto i = crypto_ids.begin(); i != crypto_ids.end() - 1; i++) { signature.append(*i); signature.append(","); } signature += crypto_ids.back(); } std::cout << "signature: " << signature << std::endl; // The Exchange/Pro API specifies to base64-decode the // alphanumeric secret string (resulting in 64 bytes) before // using it as the key for HMAC. Also, base64-encode the // digest output before sending in the header. The Advanced // Trade API does not require this decoding and encoding. // Thus, secret_base64_decoded is not used. std::string secret_base64_decoded; CryptoPP::StringSource ss1(secret, true, new CryptoPP::Base64Decoder( new CryptoPP::StringSink(secret_base64_decoded))); //------------------------------------------------------------------------------- std::cout << "secret: " << secret << std::endl; std::string digest; try { CryptoPP::HMAC< CryptoPP::SHA256 > hmac((const unsigned char*)secret.c_str(), secret.size()); CryptoPP::StringSource ss2(signature, true, new CryptoPP::HashFilter(hmac, new CryptoPP::StringSink(digest))); } catch(const CryptoPP::Exception& e) { std::cerr << e.what() << std::endl; exit(1); } // Hex encode the digest output. Use lower case hex characters // to match toString of crypto-js HmacSHA256 used in the // Advanced Trade API docs //------------------------------------------------------------- std::string hmac_hex_encoded; CryptoPP::StringSource ss3(digest, true, new CryptoPP::HexEncoder( new CryptoPP::StringSink(hmac_hex_encoded))); std::transform(hmac_hex_encoded.begin(), hmac_hex_encoded.end(), hmac_hex_encoded.begin(), [](unsigned char c){ return std::tolower(c); }); root["signature"] = Json::Value(hmac_hex_encoded); return root; } } #endif