Skip to content
This repository has been archived by the owner on Aug 12, 2024. It is now read-only.

flutter: Response: {"code":"400004","msg":"Invalid KC-API-PASSPHRASE"} flutter: Failed to get account balance. Status Code: 401, Response Body: {"code":"400004","msg":"Invalid KC-API-PASSPHRASE"} #463

Open
Emaren opened this issue May 25, 2023 · 0 comments

Comments

@Emaren
Copy link

Emaren commented May 25, 2023

I'm just trying to make a connection with the Kucoin API but I am having difficulties:

import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:ntp/ntp.dart';

Future getNetworkTime() async {
DateTime currentTime = await NTP.now();
return currentTime;
}

class KucoinHomePage extends StatefulWidget {
KucoinHomePage({Key? key}) : super(key: key);
@OverRide
State createState() => _KucoinHomePageState();
}

class _KucoinHomePageState extends State {
late String _token = '';

final _formKey = GlobalKey();
final TextEditingController _symbolController = TextEditingController();
final TextEditingController _priceController = TextEditingController();
final TextEditingController _sizeController = TextEditingController();

late final Future _initToken;

_KucoinHomePageState() {
_initToken = initializeToken();
}

late WebSocketChannel _channel;
late FlutterLocalNotificationsPlugin localNotifications;

final String _serverUrl = "wss://push-private.kucoin.com/endpoint";

void showFilledOrderNotification(var order) {
var iOSPlatformChannelSpecifics = const DarwinNotificationDetails();
var platformChannelSpecifics =
NotificationDetails(iOS: iOSPlatformChannelSpecifics);

localNotifications.show(
    0, // Notification ID
    'Order Filled',
    'Your order for ${order['symbol']} has been filled.',
    platformChannelSpecifics);

}

final storage = const FlutterSecureStorage();

Future getAccountBalance() async {
var endpoint = "https://api.kucoin.com/api/v1/accounts";
var timestamp = (await getNetworkTime()).millisecondsSinceEpoch;
var method = "GET";
var requestPath = "/api/v1/accounts";
var queryString = '';
var body = '';

print('Endpoint: $endpoint');
print('Timestamp: $timestamp');
print('Method: $method');
print('RequestPath: $requestPath');
print('QueryString: $queryString');
print('Body: $body');

var secretKey = await storage.read(key: 'secretKey');
print('SecretKey: $secretKey');
try {
  if (secretKey == null) {
    throw Exception('Error: Secret Key is null.');
  }

  var secret = utf8.encode(secretKey);

  var preHash = utf8.encode(
      timestamp.toString() + method + requestPath + queryString + body);
  var hmacSha256 = Hmac(sha256, secret);
  var digest = hmacSha256.convert(preHash);
  var signature = base64Encode(digest.bytes);

  var apiKey = await storage.read(key: 'apiKey');
  var passphrase = await storage.read(key: 'passphrase');
  if (apiKey == null || passphrase == null) {
    throw Exception('Error: API Key or Passphrase is null.');
  }

  var headers = {
    "KC-API-KEY": apiKey,
    "KC-API-SIGN": signature,
    "KC-API-TIMESTAMP": timestamp.toString(),
    "KC-API-PASSPHRASE": passphrase,
    "KC-API-KEY-VERSION": '2',
  };

  print('Headers: $headers');

  var response = await http.get(
    Uri.parse(endpoint),
    headers: headers,
  );
  print('Response: ${response.body}');

  if (response.statusCode == 200) {
    var data = jsonDecode(response.body);
    double balance = data['data'][0]
        ['balance']; // Assume the first account is the one you want
    return balance;
  } else {
    print(
        'Failed to get account balance. Status Code: ${response.statusCode}, Response Body: ${response.body}');
    throw Exception(
        'Failed to get account balance'); // Here, instead of returning null, throw an exception
  }
} catch (error) {
  print('Error in getAccountBalance: $error');
  throw Exception('Failed to get account balance');
}

}

Future getWebSocketToken() async {
var endpoint = "https://api.kucoin.com/api/v1/bullet-private";
var timestamp = (await getNetworkTime()).millisecondsSinceEpoch;
var method = "POST";
var requestPath = "/api/v1/bullet-private";
var queryString = '';
var body = '';

print('Endpoint: $endpoint');
print('Timestamp: $timestamp');
print('Method: $method');
print('RequestPath: $requestPath');
print('QueryString: $queryString');
print('Body: $body');

var secretKey = await storage.read(key: 'secretKey');
print('SecretKey: $secretKey');
if (secretKey == null) {
  print('Error: Secret Key is null.');
  return;
}

var secret = utf8.encode(secretKey);

var preHash = utf8.encode(
    timestamp.toString() + method + requestPath + queryString + body);
var hmacSha256 = Hmac(sha256, secret);
var digest = hmacSha256.convert(preHash);
var signature = base64Encode(digest.bytes);

var apiKey = await storage.read(key: 'apiKey');
var passphrase = await storage.read(key: 'passphrase');
if (apiKey == null || passphrase == null) {
  print('Error: API Key or Passphrase is null.');
  return;
}

var headers = {
  "KC-API-KEY": apiKey,
  "KC-API-SIGN": signature,
  "KC-API-TIMESTAMP": timestamp.toString(),
  "KC-API-PASSPHRASE": passphrase,
  "KC-API-KEY-VERSION": '2',
};

print('Headers: $headers');

var response = await http.post(
  Uri.parse(endpoint),
  headers: headers,
);
print('Response: ${response.body}');

if (response.statusCode == 200) {
  var data = jsonDecode(response.body);
  _token = data['data']['token']; // Set the _token here
} else {
  print('Failed to get WebSocket token');
}

}

late Future _balance;

@OverRide
void initState() {
super.initState();
initializeToken();
_balance = getAccountBalance(); // fetch balance in initState
initToken.then(() {
print('Token before connect: $_token');
if (_token.isNotEmpty) {
// Ensure that _token is not empty
print('Token after connect: $_token');
_channel = WebSocketChannel.connect(Uri.parse(
'$_serverUrl/?token=$_token&[connectId=xxxxx]')); // Use the token here

    var initializationSettingsIOS = const DarwinInitializationSettings();
    var initializationSettings =
        InitializationSettings(iOS: initializationSettingsIOS);

    localNotifications = FlutterLocalNotificationsPlugin();
    localNotifications.initialize(initializationSettings);

    _channel.sink.add(jsonEncode({
      "id": "Your Unique ID", // Replace with your unique ID
      "type": "subscribe",
      "topic": "/spotMarket/orderMatches",
      "privateChannel": true,
      "response": true,
      "token": _token
    }));

    _channel.stream.listen((event) {
      print('Received event: $event'); // Debug print
      try {
        var data = jsonDecode(event);
        if (data['type'] == 'message') {
          var order = data[
              'data']; // Accessing 'data' directly, no need for jsonDecode
          print('Parsed order: $order'); // Debug print
          // Check if the order has been filled
          if (order['type'] == 'match') {
            print('Order match detected'); // Debug print
            showFilledOrderNotification(order);
          }
        }
      } catch (e) {
        print('Error parsing event data: $e'); // Debug print
      }
    }, onError: (error) {
      print('WebSocket error: $error'); // Debug print
    });
  } else {
    print('Failed to establish WebSocket connection: No valid token.');
  }
});

}

@OverRide
void dispose() {
localNotifications.cancelAll();
_channel.sink.close();
super.dispose();
}

Future initializeToken() async {
await storage.write(
key: 'secretKey',
value: '-',
);
await storage.write(
key: 'apiKey',
value: '-',
);
await storage.write(
key: 'passphrase',
value: '-',
);
await getWebSocketToken();
print('Token after init: $_token');
}

@OverRide
Widget build(BuildContext context) {
return FutureBuilder(
future: _balance,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Text('Balance: ${snapshot.data}');
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return CircularProgressIndicator();
},
);
}
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant