Updated on 2026-08-14

This commit is contained in:
Tangem 2018-09-05 01:06:51 +03:00
parent 22d155e526
commit b1134eb19e
17 changed files with 3029 additions and 7 deletions

View file

@ -0,0 +1,327 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.internal.LinkedTreeMap;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.util.Util;
import com.tangem.wallet.R;
import java.io.IOException;
import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
//import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
/**
* HTTP
* Used in Cryptonit service
*/
public class Cryptonit {
private static final String SERVER_URL = "https://www.cryptonit.net:443/gateway/";
private static class Method {
public static final String AUTHENTICATE = SERVER_URL + "public/authenticate";
public static final String BALANCE = SERVER_URL + "private/balance";
public static final String WITHDRAW_COINS = SERVER_URL + "private/withdrawCoins";
}
public static class Model {
static class Authenticate
{
public static class Request
{
public String username;
public String password;
}
public static class Response
{
boolean success;
String[] missing_authenticators;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
AuthenticationResult results;
}
static class AuthenticationResult {
// token (string): authentication token,
// nick (string),
// stayLoggedIn (boolean),
// integer lastLogin (integer): JavaScript time OR NEVER for first login,
// preferredLanguage (string) = ['en' or 'de']
}
}
public static class Balance {
static class Request {
String[] currencies;
}
public static class Response {
public boolean success;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
public BalanceResult[] results;
public static class BalanceResult {
public String currency;
public double balance;
public String receiveAddress; //the current address to receive funds for this account, if available,
public boolean fiat; // Is this a FIAT currency? If false, this is a CRYPTO currency.,
public Object[] unprocessedTransactions; // (array, optional): list of unprocessed transactions, if pass field withTransactions
}
}
}
public static class WithdrawCoins {
public static class Request {
public String currency;
public Double amount;
String toAddress;
Double includeMinerFee;
String password;
}
public static class Response {
public Boolean success;
public String[] missing_authenticators;
public Object[] infos;
public Object[] warnings;
public Object[] errors;
}
}
}
public interface Api {
@Headers("Content-Type: application/json")
@POST(Method.AUTHENTICATE)
Call<Model.Authenticate.Response> authenticate(@Body Model.Authenticate.Request request);
@Headers("Content-Type: application/json")
@POST(Method.BALANCE)
Observable<Model.Balance.Response> getBalance(@Header("Auth-Token") String authToken, @Body Model.Balance.Request request);
@Headers("Content-Type: application/json")
@POST(Method.WITHDRAW_COINS)
Observable<Model.WithdrawCoins.Response> withdrawCoins(@Header("Auth-Token") String authToken, @Body Model.WithdrawCoins.Request request);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private ErrorListener errorListener;
private Context context;
private String authToken;
public Cryptonit(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
username = sp.getString(context.getResources().getString(R.string.key_cryptonit_username), "");
password = sp.getString(context.getResources().getString(R.string.key_cryptonit_password), "");
fee = sp.getString(context.getResources().getString(R.string.key_cryptonit_fee), "0.0");
}
public String username;
public String password;
private String fee;
public String getFee() {
return fee;
}
public void setFee(String value)
{
fee=value;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_fee), fee)
.apply();
}
public Boolean haveAccountInfo() {
return !username.isEmpty() && !password.isEmpty();
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_username), username)
.putString(context.getResources().getString(R.string.key_cryptonit_password), password)
.apply();
}
public interface BalanceListener {
void onBalanceData(Model.Balance.Response response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Model.WithdrawCoins.Response response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
@SuppressLint("CheckResult")
public void requestBalance(String currency) {
initApi();
// Log.e("CRYPTONIT2", "username: " + username);
// Log.e("CRYPTONIT2", "password: " + password);
// Log.e("CRYPTONIT2", "auth-token: " + authToken);
Model.Balance.Request request=new Model.Balance.Request();
request.currencies=new String[] {currency};
api.getBalance(authToken, request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestWithdrawCoins(String currency, Double amount, String address) {
initApi();
// Log.e("CRYPTONIT2", "username: " + username);
// Log.e("CRYPTONIT2", "password: " + password);
// Log.e("CRYPTONIT2", "auth-token: " + authToken);
Model.WithdrawCoins.Request request=new Model.WithdrawCoins.Request();
request.currency=currency;
request.amount=amount;
request.toAddress=address;
request.includeMinerFee=Double.parseDouble(fee);
request.password=password;
api.withdrawCoins(authToken, request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.success != null && response.success)
withdrawalListener.onWithdrawalComplete(response);
else {
errorListener.onError(new Exception(((LinkedTreeMap) response.errors[0]).entrySet().toArray()[0].toString()));
}
},
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("errors").getAsString()));
// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
} else {
errorListener.onError(e);
}
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
// addInterceptor(logging).
addInterceptor(new AuthorizationInterceptor()).build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
public class AuthorizationInterceptor implements Interceptor {
AuthorizationInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request mainRequest=chain.request();
if( !mainRequest.url().toString().endsWith("authenticate")&& authToken==null )
{
Model.Authenticate.Request authRequest=new Model.Authenticate.Request();
authRequest.username=username;
authRequest.password=password;
retrofit2.Response<Model.Authenticate.Response> authResponse=api.authenticate(authRequest).execute();
if( authResponse.isSuccessful() && authResponse.body().success)
{
String newToken = authResponse.headers().get("auth-token");
if (newToken != null) {
authToken = newToken;
}
}else{
throw new IOException("Authentication error: "+authResponse.message());
}
}
if( authToken!=null ) {
mainRequest = mainRequest.newBuilder().addHeader("auth-token", authToken).build();
}
Response mainResponse = chain.proceed(mainRequest);
if (!mainResponse.isSuccessful()) {
authToken=null;
}
return mainResponse;
}
}
}

View file

@ -0,0 +1,283 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.annotations.SerializedName;
import com.google.gson.internal.LinkedTreeMap;
import com.jakewharton.retrofit2.adapter.rxjava2.HttpException;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.util.Util;
import com.tangem.wallet.R;
import java.io.IOException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
//import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.Path;
/**
* HTTP
* Used in Cryptonit_OtherAPI service
*/
public class Cryptonit_OtherAPI {
private static final String SERVER_URL = "https://api.cryptonit.net/api/";
private static class Method {
public static final String BALANCE = SERVER_URL + "balance/{cryptoCurrency}%2F{fiatCurrency}";
public static final String CRYPTO_WITHDRAWAL = SERVER_URL + "crypto_withdrawal/";
}
public static class Response {
public static class Balance{
@SerializedName("btc_balance")
public String btc_balance;
@SerializedName("eur_balance")
public String eur_balance;
@SerializedName("eth_balance")
public String eth_balance;
@SerializedName("etn_balance")
public String etn_balance;
@SerializedName("btc_reserved")
public String btc_reserved;
@SerializedName("eur_reserved")
public String eur_reserved;
@SerializedName("eth_reserved")
public String eth_reserved;
@SerializedName("etn_reserved")
public String etn_reserved;
@SerializedName("btc_available")
public String btc_available;
@SerializedName("eur_available")
public String eur_available;
@SerializedName("eth_available")
public String eth_available;
@SerializedName("etn_available")
public String etn_available;
@SerializedName("btceur_fee")
public String btceur_fee;
@SerializedName("etheur_fee")
public String etheur_fee;
@SerializedName("etnbtc_fee")
public String etnbtc_fee;
@SerializedName("fee")
public String fee;
}
public static class CryptoWithdrawal {
@SerializedName("success")
public Boolean success;
@SerializedName("status")
public String status;
@SerializedName("reason")
public Object reason;
}
}
public interface Api {
@Multipart
@Headers("accept: multipart/form-data")
@POST(Method.BALANCE)
Observable<Response.Balance> getBalance(
@Path("cryptoCurrency") String cryptoCurrency, @Path("fiatCurrency") String fiatCurrency,
@Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce);
@Multipart
@Headers("accept: multipart/form-data")
@POST(Method.CRYPTO_WITHDRAWAL)
Observable<Response.CryptoWithdrawal> cryptoWithdrawal(
@Part(value = "currency") RequestBody currency, @Part("amount") RequestBody amount, @Part("address") RequestBody address,
@Part(value = "key") RequestBody key, @Part("signature") RequestBody signature, @Part("nonce") RequestBody nonce);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private ErrorListener errorListener;
private Context context;
public Cryptonit_OtherAPI(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
key = sp.getString(context.getResources().getString(R.string.key_cryptonit_key), "");
userId = sp.getString(context.getResources().getString(R.string.key_cryptonit_user_id), "");
secret = sp.getString(context.getResources().getString(R.string.key_cryptonit_secret), "");
nonce = sp.getInt(context.getResources().getString(R.string.key_cryptonit_nonce), 0);
}
public String key;
public String userId;
public String secret;
private Integer nonce;
public String getSecretDescription() {
if (secret == null || secret.isEmpty()) return "";
return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length());
}
public Boolean havaAccountInfo() {
return (!userId.isEmpty() && !key.isEmpty() && !secret.isEmpty());
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
nonce = 1;
sp.edit()
.putString(context.getResources().getString(R.string.key_cryptonit_key), key)
.putString(context.getResources().getString(R.string.key_cryptonit_user_id), userId)
.putString(context.getResources().getString(R.string.key_cryptonit_secret), secret)
.putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce)
.apply();
}
private void incNonce() {
nonce++;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putInt(context.getResources().getString(R.string.key_cryptonit_nonce), nonce).apply();
}
public interface BalanceListener {
void onBalanceData(Response.Balance response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Response.CryptoWithdrawal response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
private String calcSignature() throws Exception {
incNonce();
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
String data = nonce.toString() + userId + key;
return Util.bytesToHex(sha256_HMAC.doFinal(data.getBytes("UTF-8")));
}
@SuppressLint("CheckResult")
public void requestBalance(String cryptoCurrency, String fiatCurrency) throws Exception {
initApi();
String signature = calcSignature();
Log.e("CRYPTONIT", "user: " + userId);
Log.e("CRYPTONIT", "key: " + key);
Log.e("CRYPTONIT", "secret: " + secret);
Log.e("CRYPTONIT", "nonce: " + nonce);
Log.e("CRYPTONIT", "signature: " + signature);
api.getBalance(cryptoCurrency, fiatCurrency,
RequestBody.create(MediaType.parse("text/plain"), key),
RequestBody.create(MediaType.parse("text/plain"), signature),
RequestBody.create(MediaType.parse("text/plain"), nonce.toString()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(balanceModel -> balanceListener.onBalanceData(balanceModel),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestCryptoWithdrawal(String currency, String amount, String address) throws Exception {
initApi();
String signature = calcSignature();
Log.e("CRYPTONIT", "user: " + userId);
Log.e("CRYPTONIT", "key: " + key);
Log.e("CRYPTONIT", "secret: " + secret);
Log.e("CRYPTONIT", "nonce: " + nonce);
Log.e("CRYPTONIT", "signature: " + signature);
api.cryptoWithdrawal(
RequestBody.create(MediaType.parse("text/plain"), currency),
RequestBody.create(MediaType.parse("text/plain"), amount),
RequestBody.create(MediaType.parse("text/plain"), address),
RequestBody.create(MediaType.parse("text/plain"), key),
RequestBody.create(MediaType.parse("text/plain"), signature),
RequestBody.create(MediaType.parse("text/plain"), nonce.toString()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
if (response.success != null && response.success)
withdrawalListener.onWithdrawalComplete(response);
else {
LinkedTreeMap reason = (LinkedTreeMap) response.reason;
errorListener.onError(new Exception(reason.entrySet().toArray()[0].toString()));
}
},
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString()));
if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
} else {
errorListener.onError(e);
}
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
// addInterceptor(logging).
build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
}

View file

@ -0,0 +1,358 @@
package com.tangem.data.network;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import com.tangem.util.Util;
import com.tangem.wallet.R;
import org.spongycastle.util.encoders.Base64;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
//import okhttp3.logging.HttpLoggingInterceptor;
import okio.Buffer;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
/**
* HTTP
* Used in Kraken service
*/
public class Kraken {
private static final String SERVER_URL = "https://api.kraken.com";
private static class Method {
public static final String BALANCE = SERVER_URL + "/0/private/Balance";
public static final String WITHDRAW_INFO = SERVER_URL + "/0/private/WithdrawInfo";
public static final String WITHDRAW = SERVER_URL + "/0/private/Withdraw";
}
public static class Model {
public static class Balance {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String XXBT;
public String XETH;
public String BCH;
}
}
}
public static class WithdrawInfo {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String fee;
public String amount;
}
}
}
public static class Withdraw {
public static class Response {
public String[] error;
public Result result;
public static class Result {
public String refid;
}
}
}
}
public interface Api {
@FormUrlEncoded
@POST(Method.BALANCE)
Observable<Model.Balance.Response> getBalance(@Field("nonce") String nonce);
@FormUrlEncoded
@POST(Method.WITHDRAW_INFO)
Observable<Model.WithdrawInfo.Response> WithdrawInfo(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount);
@FormUrlEncoded
@POST(Method.WITHDRAW)
Observable<Model.Withdraw.Response> Withdraw(@Field("nonce") String nonce, @Field("asset") String asset, @Field("key") String key, @Field("amount") String amount);
}
private Api api = null;
private BalanceListener balanceListener;
private WithdrawalListener withdrawalListener;
private WithdrawalInfoListener withdrawalInfoListener;
private ErrorListener errorListener;
private Context context;
public Kraken(Context context) {
this.context = context;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
key = sp.getString(context.getResources().getString(R.string.key_kraken_key), "");
secret = sp.getString(context.getResources().getString(R.string.key_kraken_secret), "");
nonce = sp.getInt(context.getResources().getString(R.string.key_kraken_nonce), 0);
}
public String key;
public String secret;
private Integer nonce;
public String getSecretDescription() {
if (secret == null || secret.isEmpty()) return "";
return secret.substring(0, 3) + "..." + secret.substring(secret.length() - 3, secret.length());
}
public Boolean haveAccountInfo() {
return (!key.isEmpty() && !secret.isEmpty());
}
public void saveAccountInfo() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit()
.putString(context.getResources().getString(R.string.key_kraken_key), key)
.putString(context.getResources().getString(R.string.key_kraken_secret), secret)
.putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce)
.apply();
}
private void incNonce() {
nonce++;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putInt(context.getResources().getString(R.string.key_kraken_nonce), nonce).apply();
}
public interface BalanceListener {
void onBalanceData(Model.Balance.Response response);
}
public interface WithdrawalInfoListener {
void onWithdrawalInfoComplete(Model.WithdrawInfo.Response response);
}
public interface WithdrawalListener {
void onWithdrawalComplete(Model.Withdraw.Response response);
}
public interface ErrorListener {
void onError(Throwable throwable);
}
public void setBalanceListener(BalanceListener listener) {
balanceListener = listener;
}
public void setWithdrawalListener(WithdrawalListener listener) {
withdrawalListener = listener;
}
public void setWithdrawalInfoListener(WithdrawalInfoListener listener) {
withdrawalInfoListener = listener;
}
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
private static final String HMAC_SHA512 = "HmacSHA512";
private String bodyToString(final RequestBody request){
try {
final RequestBody copy = request;
final Buffer buffer = new Buffer();
if(copy != null)
copy.writeTo(buffer);
else
return "";
return buffer.readUtf8();
}
catch (final IOException e) {
return "did not work";
}
}
private String calcSignature(String url, RequestBody requestBody) throws NoSuchAlgorithmException, InvalidKeyException, IOException {
String postData=bodyToString(requestBody);
// create SHA-256 hash of the nonce and the POST data
String s=nonce+postData;
byte[] sha256 = Util.calculateSHA256(s);
// set the API method and retrieve the path
byte[] path = url.getBytes(StandardCharsets.UTF_8);
// decode the API secret, it's the HMAC key
byte[] hmacKey = Base64.decode(secret);
// create the HMAC message from the path and the previous hash
ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
outputStream.write(path);
outputStream.write(sha256);
byte[] hmacMessage = outputStream.toByteArray();//concatArrays(path, sha256);
Mac mac = Mac.getInstance(HMAC_SHA512);
mac.init(new SecretKeySpec(hmacKey, HMAC_SHA512));
byte[] hmacSignature=mac.doFinal(hmacMessage);
byte[] b64Signature = Base64.encode(hmacSignature);
return new String(b64Signature, StandardCharsets.UTF_8);
}
@SuppressLint("CheckResult")
public void requestBalance() throws Exception {
initApi();
Log.e("kraken", "key: " + key);
Log.e("kraken", "secret: " + secret);
Log.e("kraken", "nonce: " + nonce);
api.getBalance(nonce.toString())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> balanceListener.onBalanceData(response),
// handle error
this::FireError
);
}
@SuppressLint("CheckResult")
public void requestWithdrawInfo(String currency, String amount, String withdrawKey) throws Exception {
initApi();
// Log.e("kraken", "key: " + key);
// Log.e("kraken", "secret: " + secret);
// Log.e("kraken", "nonce: " + nonce);
String asset=CurrencyToAsset(currency);
// withdrawKey = "test";
api.WithdrawInfo(nonce.toString(), asset, withdrawKey, amount)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> withdrawalInfoListener.onWithdrawalInfoComplete(response),
// handle error
this::FireError
);
}
private static String CurrencyToAsset(String currency) throws Exception {
switch (currency)
{
case "BTC": return "XXBT";
case "BCH": return "BCH";
case "ETH": return "XETH";
default:
throw new Exception("Unsupported currency!");
}
}
@SuppressLint("CheckResult")
public void requestWithdraw(String currency, String amount, String withdrawKey) throws Exception {
initApi();
// Log.e("kraken", "key: " + key);
// Log.e("kraken", "secret: " + secret);
// Log.e("kraken", "nonce: " + nonce);
String asset=CurrencyToAsset(currency);
// withdrawKey = "test";
api.Withdraw(nonce.toString(), asset, withdrawKey, amount)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> withdrawalListener.onWithdrawalComplete(response),
// handle error
this::FireError
);
}
private void FireError(Throwable e) throws IOException {
// if (e.getClass() == HttpException.class && ((HttpException) e).code() == 500) {
// JsonObject jsonObject = new JsonParser().parse(((HttpException) e).response().errorBody().string()).getAsJsonObject();
// errorListener.onError(new Exception(e.getMessage() + ": " + jsonObject.get("reason").getAsString()));
// if (jsonObject.get("reason").getAsString().equals("Invalid nonce")) nonce += 1000;
// } else {
errorListener.onError(e);
// }
}
private void initApi() {
if (api != null) return;
// HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient httpClient = new OkHttpClient.Builder().
addInterceptor(new AuthorizationInterceptor()).
// addInterceptor(logging).
build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
api = retrofit.create(Api.class);
}
public class AuthorizationInterceptor implements Interceptor {
AuthorizationInterceptor() {
}
@Override
public Response intercept(Chain chain) throws IOException {
Request mainRequest=chain.request();
try {
mainRequest = mainRequest.newBuilder().
addHeader("API-Key", key).
addHeader("API-Sign", calcSignature(mainRequest.url().toString().substring(SERVER_URL.length()), mainRequest.body())).
build();
incNonce();
} catch (Exception e) {
e.printStackTrace();
throw new IOException("Can't calculate signature: "+e.getMessage());
}
return chain.proceed(mainRequest);
}
}
}

View file

@ -0,0 +1,238 @@
package com.tangem.presentation.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.InputFilter
import android.view.View
import com.tangem.data.network.Cryptonit_OtherAPI
import com.tangem.domain.cardReader.NfcManager
import com.tangem.domain.wallet.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemCard
import com.tangem.util.DecimalDigitsInputFilter
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_other_api_withdrawal.*
import java.io.IOException
class PrepareCryptonitOtherAPIWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitOtherAPIWithdrawalActivity::class.java.simpleName
private const val REQUEST_CODE_SCAN_QR_KEY = 1
private const val REQUEST_CODE_SCAN_QR_SECRET = 2
private const val REQUEST_CODE_SCAN_QR_USER_ID = 3
}
private var useCurrencyX1000: Boolean = false
private var card: TangemCard? = null
private var nfcManager: NfcManager? = null
private var cryptonit: Cryptonit_OtherAPI? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_other_api_withdrawal)
MainActivity.commonInit(applicationContext)
nfcManager = NfcManager(this, this)
card = TangemCard(intent.getStringExtra("UID"))
card!!.loadFromBundle(intent.extras!!.getBundle("Card"))
cryptonit = Cryptonit_OtherAPI(this)
tvKey.text = cryptonit!!.key
tvUserID.text = cryptonit!!.userId
tvSecret.text = cryptonit!!.secretDescription
tvCardID.text = card!!.cidDescription
tvWallet.text = card!!.wallet
val engine = CoinEngineFactory.create(card!!.blockchain)
when (card!!.blockchain) {
Blockchain.Ethereum, Blockchain.EthereumTestNet -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
Blockchain.Bitcoin, Blockchain.BitcoinTestNet, Blockchain.BitcoinCash, Blockchain.BitcoinCashTestNet -> {
tvCurrency.text = "m" + card!!.blockchain.currency
useCurrencyX1000 = true
}
else -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
}
etAmount.setText(engine.convertByteArrayToAmount(card!!, card!!.denomination))
when (card!!.blockchain) {
Blockchain.Bitcoin ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
Blockchain.BitcoinCash ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
Blockchain.Ethereum ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
else -> {
}
}
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
// if (!engine.checkAmount(card, strAmount))
// etAmount.error = getString(R.string.unknown_amount_format)
var dblAmount: Double = strAmount.toDouble()
if (useCurrencyX1000) dblAmount /= 1000.0
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal)
cryptonit!!.requestCryptoWithdrawal(card!!.blockchain.currency, dblAmount.toString(), card!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
//Toast.makeText(this, strAmount, Toast.LENGTH_LONG).show()
// val balance = engine.getBalanceLong(card)!! / (card!!.blockchain.multiplier / 1000.0)
// if (etAmount.text.toString().replace(",", ".").toDouble() > balance) {
// etAmount.error = getString(R.string.not_enough_funds_on_your_account)
// return@setOnClickListener
// }
}
ivCameraKey.setOnClickListener {
val intent = Intent(baseContext, QrScanActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SCAN_QR_KEY)
}
ivCameraSecret.setOnClickListener {
val intent = Intent(baseContext, QrScanActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SCAN_QR_SECRET)
}
ivCameraUserId.setOnClickListener {
val intent = Intent(baseContext, QrScanActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SCAN_QR_USER_ID)
}
ivRefreshBalance.setOnClickListener { doRequestBalance() }
cryptonit!!.setBalanceListener { response ->
when (card!!.blockchain) {
Blockchain.Ethereum, Blockchain.EthereumTestNet -> {
tvBalance.text = response.eth_available
}
Blockchain.Bitcoin, Blockchain.BitcoinTestNet, Blockchain.BitcoinCash, Blockchain.BitcoinCashTestNet -> {
tvBalance.text = response.btc_available
}
else -> {
}
}
tvBalanceCurrency.text = card!!.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
rlProgressBar.visibility = View.INVISIBLE
btnLoad.isActivated = true
}
cryptonit!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
cryptonit!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.success != null && response.success!!) finish()
else {
tvError.visibility = View.VISIBLE
tvError.text = response.reason!!.toString()
}
}
btnLoad.isActivated = false
doRequestBalance()
}
private fun doRequestBalance() {
if (cryptonit!!.havaAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
cryptonit!!.requestBalance(card!!.blockchain.currency, "USD")
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)
}
}
// private fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
// this.addTextChangedListener(object : TextWatcher {
// override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
// }
//
// override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
// }
//
// override fun afterTextChanged(editable: Editable?) {
// afterTextChanged.invoke(editable.toString())
// }
// })
// }
public override fun onResume() {
super.onResume()
nfcManager!!.onResume()
}
public override fun onPause() {
super.onPause()
nfcManager!!.onPause()
}
public override fun onStop() {
super.onStop()
nfcManager!!.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if( resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode") ) {
when(requestCode) {
REQUEST_CODE_SCAN_QR_KEY -> {
cryptonit!!.key = data.getStringExtra("QRCode")
tvKey!!.text = cryptonit!!.key
}
REQUEST_CODE_SCAN_QR_SECRET -> {
cryptonit!!.secret = data.getStringExtra("QRCode")
tvSecret!!.text = cryptonit!!.secretDescription
}
REQUEST_CODE_SCAN_QR_USER_ID -> {
cryptonit!!.userId = data.getStringExtra("QRCode")
tvUserID!!.text = cryptonit!!.userId
}
}
cryptonit!!.saveAccountInfo()
doRequestBalance()
}
}
override fun onTagDiscovered(tag: Tag) {
try {
// Log.w(javaClass.name, "Ignore discovered tag!")
nfcManager!!.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
}

View file

@ -0,0 +1,185 @@
package com.tangem.presentation.activity
import android.annotation.SuppressLint
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.InputFilter
import android.view.View
import android.widget.Toast
import com.tangem.data.network.Cryptonit
import com.tangem.domain.cardReader.NfcManager
import com.tangem.domain.wallet.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemCard
import com.tangem.util.DecimalDigitsInputFilter
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_cryptonit_withdrawal.*
import java.io.IOException
class PrepareCryptonitWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareCryptonitWithdrawalActivity::class.java.simpleName
}
private var useCurrencyX1000: Boolean = false
private var card: TangemCard? = null
private var nfcManager: NfcManager? = null
private var cryptonit: Cryptonit? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_cryptonit_withdrawal)
MainActivity.commonInit(applicationContext)
nfcManager = NfcManager(this, this)
card = TangemCard(intent.getStringExtra("UID"))
card!!.loadFromBundle(intent.extras!!.getBundle("Card"))
cryptonit = Cryptonit(this)
etUsername.setText(cryptonit!!.username)
etPassword.setText(cryptonit!!.password)
etFee.setText(cryptonit!!.fee)
tvCardID.text = card!!.cidDescription
tvWallet.text = card!!.wallet
val engine = CoinEngineFactory.create(card!!.blockchain)
when (card!!.blockchain) {
Blockchain.Ethereum -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
Blockchain.Bitcoin, Blockchain.BitcoinCash -> {
tvCurrency.text = "m" + card!!.blockchain.currency
useCurrencyX1000 = true
}
else -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
}
tvFeeCurrency.text = tvCurrency.text
etAmount.setText(engine.convertByteArrayToAmount(card!!, card!!.denomination))
when (card!!.blockchain) {
Blockchain.Bitcoin -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
}
Blockchain.BitcoinCash -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
}
Blockchain.Ethereum -> {
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
etFee.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
}
else -> {
}
}
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
val strFee: String = etFee.text.toString().replace(",", ".")
var dblAmount: Double = strAmount.toDouble()
var dblFee: Double = strFee.toDouble()
if (useCurrencyX1000){
dblAmount /= 1000.0
dblFee /= 1000.0
}
cryptonit!!.fee=strFee
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_withdrawal)
cryptonit!!.requestWithdrawCoins(card!!.blockchain.currency, dblAmount, card!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
ivRefreshBalance.setOnClickListener {
cryptonit!!.username=etUsername.text.toString()
cryptonit!!.password=etPassword.text.toString()
cryptonit!!.saveAccountInfo()
doRequestBalance()
}
cryptonit!!.setBalanceListener { response ->
tvBalance.text = response.results[0].balance.toString()
tvBalanceCurrency.text = response.results[0].currency // card!!.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
rlProgressBar.visibility = View.INVISIBLE
btnLoad.visibility = View.VISIBLE
}
cryptonit!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
cryptonit!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.success != null && response.success!!){
Toast.makeText(this,"Withdrawal successful!", Toast.LENGTH_LONG).show();
finish()
}
else {
tvError.visibility = View.VISIBLE
tvError.text = response.errors.toString()
}
}
btnLoad.visibility = View.INVISIBLE
doRequestBalance()
}
private fun doRequestBalance() {
if (cryptonit!!.haveAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.cryptonit_request_balance)
tvError.visibility = View.INVISIBLE
cryptonit!!.requestBalance(card!!.blockchain.currency)
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.cryptonit_not_enough_account_data)
}
}
public override fun onResume() {
super.onResume()
nfcManager!!.onResume()
}
public override fun onPause() {
super.onPause()
nfcManager!!.onPause()
}
public override fun onStop() {
super.onStop()
nfcManager!!.onStop()
}
override fun onTagDiscovered(tag: Tag) {
try {
nfcManager!!.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
}

View file

@ -0,0 +1,286 @@
package com.tangem.presentation.activity
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.InputFilter
import android.view.View
import android.widget.Toast
import com.tangem.data.network.Kraken
import com.tangem.domain.cardReader.NfcManager
import com.tangem.domain.wallet.Blockchain
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemCard
import com.tangem.util.DecimalDigitsInputFilter
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.activity_prepare_kraken_withdrawal.*
import java.io.IOException
import java.math.BigDecimal
import java.net.URI
import java.util.*
class PrepareKrakenWithdrawalActivity : AppCompatActivity(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = PrepareKrakenWithdrawalActivity::class.java.simpleName
private const val REQUEST_CODE_SCAN_QR = 1
}
private var useCurrencyX1000: Boolean = false
private var card: TangemCard? = null
private var nfcManager: NfcManager? = null
private var kraken: Kraken? = null
private var fee: BigDecimal? = null
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_prepare_kraken_withdrawal)
MainActivity.commonInit(applicationContext)
nfcManager = NfcManager(this, this)
card = TangemCard(intent.getStringExtra("UID"))
card!!.loadFromBundle(intent.extras!!.getBundle("Card"))
kraken = Kraken(this)
tvKey.text = kraken!!.key
tvSecret.text = kraken!!.secretDescription
tvCardID.text = card!!.cidDescription
tvWallet.text = card!!.wallet
val engine = CoinEngineFactory.create(card!!.blockchain)
when (card!!.blockchain) {
Blockchain.Ethereum, Blockchain.EthereumTestNet -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
Blockchain.Bitcoin, Blockchain.BitcoinTestNet, Blockchain.BitcoinCash, Blockchain.BitcoinCashTestNet -> {
tvCurrency.text = "m" + card!!.blockchain.currency
useCurrencyX1000 = true
}
else -> {
tvCurrency.text = engine.getBalanceCurrency(card)
useCurrencyX1000 = false
}
}
etAmount.setText(engine.convertByteArrayToAmount(card!!, card!!.denomination))
when (card!!.blockchain) {
Blockchain.Bitcoin ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(5))
Blockchain.BitcoinCash ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(8))
Blockchain.Ethereum ->
etAmount.filters = arrayOf<InputFilter>(DecimalDigitsInputFilter(18))
else -> {
}
}
// set listeners
btnLoad.setOnClickListener {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
var dblAmount: Double = strAmount.toDouble()
if (useCurrencyX1000) dblAmount /= 1000.0
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
kraken!!.requestWithdrawInfo(card!!.blockchain.currency, dblAmount.toString(), card!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
ivCamera.setOnClickListener {
val intent = Intent(baseContext, QrScanActivity::class.java)
startActivityForResult(intent, REQUEST_CODE_SCAN_QR)
}
ivRefreshBalance.setOnClickListener { doRequestBalance() }
kraken!!.setBalanceListener { response ->
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
when (card!!.blockchain) {
Blockchain.Ethereum -> {
tvBalance.text = response.result.XETH.trimEnd('0')
}
Blockchain.Bitcoin -> {
tvBalance.text = response.result.XXBT.trimEnd('0')
}
Blockchain.BitcoinCash -> {
tvBalance.text = response.result.BCH.trimEnd('0')
}
else -> {
tvBalance.text = "???"
}
}
tvBalanceCurrency.text = card!!.blockchain.currency
tvBalance.setTextColor(Color.BLACK)
btnLoad.visibility = View.VISIBLE
}
rlProgressBar.visibility = View.INVISIBLE
}
kraken!!.setErrorListener { throwable ->
throwable.printStackTrace()
rlProgressBar.visibility = View.INVISIBLE
tvError.visibility = View.VISIBLE
tvError.text = throwable.message
}
kraken!!.setWithdrawalListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
Toast.makeText(this,"Withdrawal successful!", Toast.LENGTH_LONG).show()
finish()
}
}
kraken!!.setWithdrawalInfoListener { response ->
rlProgressBar.visibility = View.INVISIBLE
if (response.error != null && response.error.isNotEmpty()) {
tvError.visibility = View.VISIBLE
tvError.text = Arrays.toString(response.error)
} else {
fee = BigDecimal(response.result.fee)
showConfirmDialog()
}
}
btnLoad.visibility = View.INVISIBLE
doRequestBalance()
}
// Method to show an alert dialog with yes, no and cancel button
private fun showConfirmDialog() {
// Late initialize an alert dialog object
lateinit var dialog: AlertDialog
// Initialize a new instance of alert dialog builder object
val builder = AlertDialog.Builder(this)
// Set a title for alert dialog
builder.setTitle("Please confirm withdraw")
// Set a message for alert dialog
builder.setMessage(String.format("Continue with fee %s %s?", fee!!.toString().trimEnd('0'),card!!.blockchain.currency))
// On click listener for dialog buttons
val dialogClickListener = DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
try {
val strAmount: String = etAmount.text.toString().replace(",", ".")
var dblAmount: Double = strAmount.toDouble()
if (useCurrencyX1000) dblAmount /= 1000.0
dblAmount+=fee!!.toDouble()
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_withdrawal)
//Toast.makeText(this, String.format("Withdraw %s!",dblAmount.toString()), Toast.LENGTH_LONG).show()
kraken!!.requestWithdraw(card!!.blockchain.currency, dblAmount.toString(), card!!.wallet)
} catch (e: Exception) {
etAmount.error = getString(R.string.unknown_amount_format)
}
}
DialogInterface.BUTTON_NEGATIVE -> {
Toast.makeText(this, "Operation canceled!", Toast.LENGTH_LONG).show()
}
}
}
// Set the alert dialog positive/yes button
builder.setPositiveButton("YES", dialogClickListener)
// Set the alert dialog negative/no button
builder.setNegativeButton("NO", dialogClickListener)
// Initialize the AlertDialog using builder object
dialog = builder.create()
// Finally, display the alert dialog
dialog.show()
}
private fun doRequestBalance() {
if (kraken!!.haveAccountInfo()) {
rlProgressBar.visibility = View.VISIBLE
tvProgressDescription.text = getString(R.string.kraken_request_balance)
tvError.visibility = View.INVISIBLE
kraken!!.requestBalance()
} else {
tvError.visibility = View.VISIBLE
tvError.text = getString(R.string.kraken_not_enough_account_data)
}
}
public override fun onResume() {
super.onResume()
nfcManager!!.onResume()
}
public override fun onPause() {
super.onPause()
nfcManager!!.onPause()
}
public override fun onStop() {
super.onStop()
nfcManager!!.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && data != null && data.extras!!.containsKey("QRCode")) {
when (requestCode) {
REQUEST_CODE_SCAN_QR -> {
val uri = URI(data.getStringExtra("QRCode"))
var query = uri.query
var params = query.split("&")
for (param in params) {
if (param.startsWith("key=")) kraken!!.key = param.substring(4)
else if (param.startsWith("secret=")) kraken!!.secret = param.substring(7)
}
tvKey!!.text = kraken!!.key
tvSecret!!.text = kraken!!.secretDescription
}
}
kraken!!.saveAccountInfo()
doRequestBalance()
}
}
override fun onTagDiscovered(tag: Tag) {
try {
// Log.w(javaClass.name, "Ignore discovered tag!")
nfcManager!!.ignoreTag(tag)
} catch (e: IOException) {
e.printStackTrace()
}
}
}

View file

@ -1,6 +1,7 @@
package com.tangem.presentation.fragment
import android.app.Activity
import android.app.AlertDialog
import android.content.*
import android.content.Context.CLIPBOARD_SERVICE
import android.content.pm.PackageManager
@ -36,6 +37,7 @@ import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.util.Util
import com.tangem.util.UtilHelper
import com.tangem.wallet.BuildConfig
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_loaded_wallet.*
import java.util.*
@ -51,6 +53,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
private const val REQUEST_CODE_ENTER_NEW_PIN2 = 6
private const val REQUEST_CODE_REQUEST_PIN2_FOR_SWAP_PIN = 7
private const val REQUEST_CODE_SWAP_PIN = 8
private const val REQUEST_CODE_RECEIVE_PAYMENT = 9
}
private var singleToast: Toast? = null
@ -133,12 +136,53 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
tvWallet.setOnClickListener { doShareWallet(false) }
ivQR.setOnClickListener { doShareWallet(true) }
btnLoad.setOnClickListener {
try {
val intent = Intent(Intent.ACTION_VIEW, CoinEngineFactory.create(card!!.blockchain)!!.getShareWalletUri(card))
intent.addCategory(Intent.CATEGORY_DEFAULT)
startActivity(intent)
} catch (e: ActivityNotFoundException) {
showSingleToast(R.string.no_compatible_wallet)
if (BuildConfig.DEBUG) {
val items = arrayOf<CharSequence>(getString(R.string.in_app), getString(R.string.via_cryptonit), getString(R.string.via_kraken))
val dialog = AlertDialog.Builder(activity).setTitle(getString(R.string.select_loading_method)).setItems(items
) { _, which ->
when (items[which]) {
getString(R.string.in_app) -> {
try {
val intent = Intent(Intent.ACTION_VIEW, CoinEngineFactory.create(card!!.blockchain)!!.getShareWalletUri(card))
intent.addCategory(Intent.CATEGORY_DEFAULT)
startActivity(intent)
} catch (e: ActivityNotFoundException) {
showSingleToast(R.string.no_compatible_wallet)
}
}
// getString(R.string.via_cryptonit2) -> {
// val intent = Intent(context, PrepareCryptonitOtherAPIWithdrawalActivity::class.java)
// intent.putExtra("UID", card!!.uid)
// intent.putExtra("Card", card!!.asBundle)
// startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
// }
getString(R.string.via_cryptonit) -> {
val intent = Intent(context, PrepareCryptonitWithdrawalActivity::class.java)
intent.putExtra("UID", card!!.uid)
intent.putExtra("Card", card!!.asBundle)
startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
}
getString(R.string.via_kraken) -> {
val intent = Intent(context, PrepareKrakenWithdrawalActivity::class.java)
intent.putExtra("UID", card!!.uid)
intent.putExtra("Card", card!!.asBundle)
startActivityForResult(intent, REQUEST_CODE_RECEIVE_PAYMENT)
}
else -> {
}
}
}
dialog.show()
} else {
try {
val intent = Intent(Intent.ACTION_VIEW, CoinEngineFactory.create(card!!.blockchain)!!.getShareWalletUri(card))
intent.addCategory(Intent.CATEGORY_DEFAULT)
startActivity(intent)
} catch (e: ActivityNotFoundException) {
showSingleToast(R.string.no_compatible_wallet)
}
}
}
btnDetails.setOnClickListener {
@ -351,7 +395,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
updateViews()
}
REQUEST_CODE_SEND_PAYMENT -> {
REQUEST_CODE_SEND_PAYMENT, REQUEST_CODE_RECEIVE_PAYMENT -> {
if (resultCode == Activity.RESULT_OK) {
srlLoadedWallet!!.postDelayed({ this.refresh() }, 10000)
srlLoadedWallet!!.isRefreshing = true