Updated on 2026-08-14
This commit is contained in:
commit
bd8d84a85a
680 changed files with 51751 additions and 6799 deletions
|
|
@ -1,29 +1,41 @@
|
|||
package com.tangem.data;
|
||||
|
||||
import com.tangem.tangemcard.R;
|
||||
import com.tangem.card_android.R;
|
||||
|
||||
/**
|
||||
* Created by dvol on 06.08.2017.
|
||||
*/
|
||||
public enum Blockchain {
|
||||
Unknown("", "", R.drawable.ic_logo_unknown, ""),
|
||||
Bitcoin("BTC", "BTC", R.drawable.ic_logo_bitcoin, "Bitcoin"),
|
||||
BitcoinTestNet("BTC/test", "BTC", R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"),
|
||||
Ethereum("ETH", "ETH", R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
EthereumTestNet("ETH/test", "ETH", R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"),
|
||||
Token("Token", "ERC20", R.drawable.ic_logo_bat_token, "Ethereum"),
|
||||
BitcoinCash("BCH", "BCH", R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"),
|
||||
Litecoin("LTC", "LTC", R.drawable.ic_logo_bitcoin, "Litecoin"),
|
||||
Stellar("XLM", "XLM", R.drawable.ic_logo_stellar, "Stellar Lumens"),
|
||||
StellarTestNet("XLM/test", "XLM", R.drawable.ic_logo_stellar, "Stellar Lumens");
|
||||
Blockchain(String ID, String currency, int imageResource, String officialName) {
|
||||
Unknown("", "", 1.0, R.drawable.ic_logo_unknown, ""),
|
||||
Bitcoin("BTC", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin, "Bitcoin"),
|
||||
BitcoinTestNet("BTC/test", "BTC", 100000000.0, R.drawable.ic_logo_bitcoin_testnet, "Bitcoin Testnet"),
|
||||
Ethereum("ETH", "ETH", 1.0, R.drawable.ic_logo_ethereum, "Ethereum"),
|
||||
EthereumTestNet("ETH/test", "ETH", 1.0, R.drawable.ic_logo_ethereum_testnet, "Ethereum Testnet"),
|
||||
Token("Token", "ETH", 1.0, R.drawable.ic_logo_bat_token, "Ethereum"),
|
||||
NftToken("NftToken", "", 1.0, R.drawable.tangem2, "Ethereum"),
|
||||
BitcoinCash("BCH", "BCH", 100000000.0, R.drawable.ic_logo_bitcoin_cash, "Bitcoin Cash"),
|
||||
Litecoin("LTC", "LTC", 100000000.0, R.drawable.tangem2, "Litecoin"),
|
||||
Rootstock("RSK", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
|
||||
RootstockToken("RskToken", "RBTC", 1.0, R.drawable.tangem2, "RSK"),
|
||||
Cardano("CARDANO", "ADA", 1000000.0, R.drawable.tangem2, "Cardano"),
|
||||
Ripple ("XRP", "XRP", 1000000.0, R.drawable.tangem2, "XRP"),
|
||||
Binance("BINANCE", "BNB", 100000000.0, R.drawable.tangem2, "Binance"),
|
||||
BinanceTestNet("BINANCE/test", "BNB", 100000000.0, R.drawable.tangem2, "Binance Testnet"),
|
||||
Matic("MATIC", "MTX", 1.0, R.drawable.tangem2, "Matic"),
|
||||
MaticTestNet("MATIC/test", "MTX", 1.0, R.drawable.tangem2, "Matic Testnet");
|
||||
Stellar("XLM", "XLM", R.drawable.ic_logo_stellar, "Stellar"),
|
||||
StellarTestNet("XLM/test", "XLM", R.drawable.ic_logo_stellar, "Stellar Testnet");
|
||||
|
||||
Blockchain(String ID, String currency, double multiplier, int imageResource, String officialName) {
|
||||
mID = ID;
|
||||
mCurrency = currency;
|
||||
// mMultiplier = multiplier;
|
||||
mImageResource = imageResource;
|
||||
mOfficialName = officialName;
|
||||
}
|
||||
|
||||
private String mID, mOfficialName;
|
||||
//private double mMultiplier;
|
||||
private String mCurrency;
|
||||
private int mImageResource;
|
||||
|
||||
|
|
@ -35,6 +47,10 @@ public enum Blockchain {
|
|||
return mOfficialName;
|
||||
}
|
||||
|
||||
// public double getMultiplier() {
|
||||
// return mMultiplier;
|
||||
// }
|
||||
|
||||
public String getCurrency() {
|
||||
return mCurrency;
|
||||
}
|
||||
|
|
@ -78,7 +94,6 @@ public enum Blockchain {
|
|||
return resourceId;
|
||||
}
|
||||
|
||||
//TODO - ???
|
||||
public static int getLogoImageResource(String blockchainID, String symbolName) {
|
||||
switch (blockchainID) {
|
||||
case "BTC":
|
||||
|
|
|
|||
|
|
@ -20,11 +20,7 @@ import java.util.Objects;
|
|||
|
||||
public class LogFileProvider extends ContentProvider {
|
||||
|
||||
private static final String CLASS_NAME = "LogFileProvider";
|
||||
|
||||
// The authority is the symbolic name for the provider class
|
||||
// public static final String AUTHORITY = "com.tangem.LogFileProvider";
|
||||
// public static final String AUTHORITY = "com.tangem.LogFileProvider";
|
||||
private static final String TAG = LogFileProvider.class.getSimpleName() + "-oF";
|
||||
|
||||
// UriMatcher used to match against incoming requests
|
||||
private UriMatcher uriMatcher;
|
||||
|
|
@ -43,15 +39,11 @@ public class LogFileProvider extends ContentProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode)
|
||||
throws FileNotFoundException {
|
||||
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
|
||||
|
||||
String LOG_TAG = CLASS_NAME + "-oF";
|
||||
Log.v(TAG, "Called with uri: '" + uri + "'." + uri.getLastPathSegment());
|
||||
|
||||
Log.v(LOG_TAG,
|
||||
"Called with uri: '" + uri + "'." + uri.getLastPathSegment());
|
||||
|
||||
// Check incoming Uri against the matcher
|
||||
// check incoming Uri against the matcher
|
||||
switch (uriMatcher.match(uri)) {
|
||||
|
||||
// If it returns 1 - then it matches the Uri defined in onCreate
|
||||
|
|
@ -60,7 +52,7 @@ public class LogFileProvider extends ContentProvider {
|
|||
// The desired file name is specified by the last segment of the
|
||||
// path
|
||||
// E.g.
|
||||
// 'content://it.my.app.LogFileProvider/Test.txt'
|
||||
// 'content://it.my.app.LogFileProvider/Test1.txt'
|
||||
// Take this and build the path to the file
|
||||
String fileLocation = getContext().getCacheDir() + File.separator
|
||||
+ uri.getLastPathSegment();
|
||||
|
|
@ -73,9 +65,8 @@ public class LogFileProvider extends ContentProvider {
|
|||
|
||||
// Otherwise unrecognised Uri
|
||||
default:
|
||||
Log.v(LOG_TAG, "Unsupported uri: '" + uri + "'.");
|
||||
throw new FileNotFoundException("Unsupported uri: "
|
||||
+ uri.toString());
|
||||
Log.v(TAG, "Unsupported uri: '" + uri + "'.");
|
||||
throw new FileNotFoundException("Unsupported uri: " + uri.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package com.tangem.data;
|
|||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.tangemcard.util.Util;
|
||||
import com.tangem.card_common.util.Util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
|
|
@ -226,7 +226,7 @@ public class Logger {
|
|||
//
|
||||
// verifyStoragePermissions(activity);
|
||||
// initLogFile(activity.getApplicationContext());
|
||||
// t.start();
|
||||
// t.init();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
|
@ -268,7 +268,7 @@ public class Logger {
|
|||
// //Checks if the app has permission to write to device storage
|
||||
// //If the app does not has permission then the user will be prompted to grant permissions
|
||||
// public static void verifyStoragePermissions(Activity activity) {
|
||||
// // Check if we have write permission
|
||||
// // check if we have write permission
|
||||
// int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
//
|
||||
// if (permission != PackageManager.PERMISSION_GRANTED) {
|
||||
|
|
|
|||
44
app/src/main/java/com/tangem/data/dp/PrefsManager.kt
Normal file
44
app/src/main/java/com/tangem/data/dp/PrefsManager.kt
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.data.dp
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
|
||||
import com.orhanobut.hawk.Hawk
|
||||
import com.tangem.Constant
|
||||
|
||||
class PrefsManager {
|
||||
companion object {
|
||||
const val PREF_NAME = "tangem_access"
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private var instance: PrefsManager? = null
|
||||
|
||||
fun getInstance(): PrefsManager {
|
||||
if (instance == null) {
|
||||
instance = PrefsManager()
|
||||
}
|
||||
return instance as PrefsManager
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var context: Context
|
||||
private lateinit var preferences: SharedPreferences
|
||||
|
||||
fun init(context: Context) {
|
||||
this.context = context
|
||||
preferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
|
||||
Hawk.init(context).build()
|
||||
}
|
||||
|
||||
val lastWalletAddress: String
|
||||
get() = Hawk.get(Constant.PREF_LAST_WALLET_ADDRESS, "")
|
||||
|
||||
fun saveLastWalletAddress(value: String) {
|
||||
Hawk.put(Constant.PREF_LAST_WALLET_ADDRESS, value)
|
||||
}
|
||||
|
||||
fun clearLastWalletAddress() {
|
||||
Hawk.delete(Constant.PREF_LAST_WALLET_ADDRESS)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package com.tangem.data.fingerprint;
|
|||
import android.os.AsyncTask;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.tangem.presentation.activity.PinSaveActivity;
|
||||
import com.tangem.ui.activity.PinSaveActivity;
|
||||
import com.tangem.wallet.R;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ import android.security.keystore.KeyPermanentlyInvalidatedException;
|
|||
import android.security.keystore.KeyProperties;
|
||||
|
||||
import com.tangem.Constant;
|
||||
import com.tangem.tangemcard.android.data.PINStorage;
|
||||
import com.tangem.presentation.activity.PinRequestActivity;
|
||||
import com.tangem.card_android.android.data.PINStorage;
|
||||
import com.tangem.ui.activity.PinRequestActivity;
|
||||
import com.tangem.util.LOG;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
|
@ -26,6 +27,8 @@ import javax.crypto.SecretKey;
|
|||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
||||
public static final String TAG = StartFingerprintReaderTask.class.getSimpleName();
|
||||
|
||||
private WeakReference<PinRequestActivity> reference;
|
||||
|
||||
private KeyStore keyStore;
|
||||
|
|
@ -64,16 +67,14 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
|
||||
@Override
|
||||
protected void onPostExecute(final Boolean success) {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
onCancelled();
|
||||
|
||||
if (!success) {
|
||||
pinRequestActivity.doLog("Authentication failed!");
|
||||
LOG.i(TAG, "Authentication failed!");
|
||||
} else {
|
||||
fingerprintHelper.startAuth(fingerprintManager, cryptoObject);
|
||||
pinRequestActivity.doLog("Authenticate using fingerprint!");
|
||||
|
||||
LOG.i(TAG, "Authenticate using fingerprint!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,9 +86,7 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
}
|
||||
|
||||
private boolean getKeyStore() {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
pinRequestActivity.doLog("Getting keystore...");
|
||||
LOG.i(TAG, "Getting keystore...");
|
||||
try {
|
||||
keyStore = KeyStore.getInstance(Constant.KEYSTORE);
|
||||
keyStore.load(null); // Create empty keystore
|
||||
|
|
@ -101,9 +100,7 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
public boolean createNewKey(boolean forceCreate) {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
pinRequestActivity.doLog("Creating new key...");
|
||||
LOG.i(TAG, "Creating new key...");
|
||||
try {
|
||||
if (forceCreate)
|
||||
keyStore.deleteEntry(Constant.KEY_ALIAS);
|
||||
|
|
@ -120,9 +117,9 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
);
|
||||
|
||||
generator.generateKey();
|
||||
pinRequestActivity.doLog("Key created.");
|
||||
LOG.i(TAG, "Key created.");
|
||||
} else
|
||||
pinRequestActivity.doLog("Key exists.");
|
||||
LOG.i(TAG, "Key exists.");
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
|
@ -133,9 +130,7 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
}
|
||||
|
||||
private boolean getCipher() {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
pinRequestActivity.doLog("Getting cipher...");
|
||||
LOG.i(TAG, "Getting cipher...");
|
||||
try {
|
||||
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
|
||||
return true;
|
||||
|
|
@ -150,7 +145,7 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
private boolean initCipher(int mode) {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
pinRequestActivity.doLog("Initializing cipher...");
|
||||
LOG.i(TAG, "Initializing cipher...");
|
||||
try {
|
||||
keyStore.load(null);
|
||||
SecretKey keyspec = (SecretKey) keyStore.getKey(Constant.KEY_ALIAS, null);
|
||||
|
|
@ -181,9 +176,7 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
|
||||
@TargetApi(Build.VERSION_CODES.M)
|
||||
private boolean initCryptObject() {
|
||||
PinRequestActivity pinRequestActivity = reference.get();
|
||||
|
||||
pinRequestActivity.doLog("Initializing crypt object...");
|
||||
LOG.i(TAG, "Initializing crypt object...");
|
||||
try {
|
||||
cryptoObject = new FingerprintManager.CryptoObject(cipher);
|
||||
return true;
|
||||
|
|
@ -193,5 +186,4 @@ public class StartFingerprintReaderTask extends AsyncTask<Void, Void, Boolean> {
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
package com.tangem.data.local
|
||||
|
||||
import android.content.Context
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import com.tangem.card_common.data.TangemCard
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class PendingTransactionsStorage
|
||||
(
|
||||
val context: Context
|
||||
) {
|
||||
private lateinit var cardTransactions: MutableMap<String, CardTransactionsInfo>
|
||||
private val transactionsFile: File = File(context.filesDir, "transactions.json")
|
||||
|
||||
private var cacheDir: File? = null
|
||||
|
||||
init {
|
||||
cacheDir = File(context.filesDir, "artworks")
|
||||
if (!cacheDir!!.exists())
|
||||
cacheDir!!.mkdirs()
|
||||
|
||||
if (transactionsFile.exists()) {
|
||||
try {
|
||||
transactionsFile.bufferedReader().use { cardTransactions = Gson().fromJson(it, object : TypeToken<HashMap<String, CardTransactionsInfo>>() {}.type) }
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
cardTransactions = HashMap()
|
||||
}
|
||||
} else {
|
||||
cardTransactions = HashMap()
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearExpired()
|
||||
{
|
||||
for(cardId in cardTransactions.keys) {
|
||||
cardTransactions[cardId]!!.transactions.removeAll { it.isExpired() }
|
||||
}
|
||||
cardTransactions.entries.removeAll { it.value.isEmpty() }
|
||||
}
|
||||
|
||||
fun save() {
|
||||
clearExpired()
|
||||
val sTransactions = Gson().toJson(cardTransactions)
|
||||
|
||||
transactionsFile.bufferedWriter().use { it.write(sTransactions) }
|
||||
}
|
||||
|
||||
fun putTransaction(card: TangemCard, txId: String, expireTimeoutInSeconds: Int) {
|
||||
val sendDate=Date()
|
||||
val calendar=Calendar.getInstance()
|
||||
calendar.time=sendDate
|
||||
calendar.add(Calendar.SECOND, expireTimeoutInSeconds)
|
||||
val expireDate=calendar.time
|
||||
putTransaction(card.cidDescription, txId, sendDate, expireDate)
|
||||
}
|
||||
|
||||
private fun putTransaction(cardId: String, txId: String, sendDate: Date, expireDate: Date) {
|
||||
val transactionInfo = TransactionInfo(
|
||||
txId, sendDate, expireDate
|
||||
)
|
||||
if (cardTransactions[cardId] == null) {
|
||||
cardTransactions[cardId] = CardTransactionsInfo(arrayListOf())
|
||||
}
|
||||
cardTransactions[cardId]?.transactions?.add(transactionInfo)
|
||||
save()
|
||||
}
|
||||
|
||||
fun getTransactions(card: TangemCard): CardTransactionsInfo? {
|
||||
clearExpired()
|
||||
return cardTransactions[card.cidDescription]
|
||||
}
|
||||
|
||||
fun hasTransactions(card: TangemCard): Boolean {
|
||||
val cardTransactionsInfo=getTransactions(card)
|
||||
if( cardTransactionsInfo!=null ) return cardTransactionsInfo.transactions.count()>0
|
||||
return false
|
||||
}
|
||||
|
||||
fun removeTransaction(card: TangemCard, txId: String)
|
||||
{
|
||||
cardTransactions[card.cidDescription]?.transactions?.removeAll { it.tx==txId }
|
||||
save()
|
||||
}
|
||||
|
||||
data class TransactionInfo(
|
||||
val tx: String,
|
||||
val sendDate: Date,
|
||||
val expireDate: Date
|
||||
) {
|
||||
fun isExpired(): Boolean {
|
||||
return Date().after(expireDate)
|
||||
}
|
||||
}
|
||||
|
||||
data class CardTransactionsInfo(
|
||||
var transactions: MutableList<TransactionInfo>
|
||||
) {
|
||||
fun isEmpty(): Boolean {
|
||||
return transactions.count()==0
|
||||
}
|
||||
}
|
||||
}
|
||||
30
app/src/main/java/com/tangem/data/network/AdaliteApi.java
Normal file
30
app/src/main/java/com/tangem/data/network/AdaliteApi.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.AdaliteBody;
|
||||
import com.tangem.data.network.model.AdaliteResponse;
|
||||
import com.tangem.data.network.model.AdaliteResponseUtxo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
public interface AdaliteApi {
|
||||
@GET(ServerApiAdalite.ADALITE_ADDRESS)
|
||||
Call<AdaliteResponse> adaliteAddress(@Path("address") String address);
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(ServerApiAdalite.ADALITE_UNSPENT_OUTPUTS)
|
||||
Call<AdaliteResponseUtxo> adaliteUnspent(@Body String address);
|
||||
|
||||
// @GET(ServerApiAdalite.ADALITE_TRANSACTION)
|
||||
// Call<AdaliteResponse> adaliteTransaction(@Path("txId") String txId);
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(ServerApiAdalite.ADALITE_SEND)
|
||||
Call<List> adaliteSend(@Body AdaliteBody adaliteBody);
|
||||
}
|
||||
13
app/src/main/java/com/tangem/data/network/BinanceApi.java
Normal file
13
app/src/main/java/com/tangem/data/network/BinanceApi.java
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.BinanceFees;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
|
||||
public interface BinanceApi {
|
||||
@GET("fees")
|
||||
Call<List<BinanceFees>> binanceFees();
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.BlockcypherBody;
|
||||
import com.tangem.data.network.model.BlockcypherResponse;
|
||||
import com.tangem.data.network.model.BlockcypherFee;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface BlockcypherApi {
|
||||
@GET(Server.ApiBlockcypher.Method.MAIN)
|
||||
Call<BlockcypherFee> blockcypherMain(@Path("blockchain") String blockchain);
|
||||
|
||||
@GET(Server.ApiBlockcypher.Method.ADDRESS)
|
||||
Call<BlockcypherResponse> blockcypherAddress(@Path("blockchain") String blockchain, @Path("address") String address);
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(Server.ApiBlockcypher.Method.PUSH)
|
||||
Call<BlockcypherResponse> blockcypherPush(@Path("blockchain") String blockchain, @Body BlockcypherBody blockcypherBody, @Query("token") String token);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package com.tangem.data.network
|
||||
|
||||
enum class BlockcypherToken(val token: String) {
|
||||
T_001("aa8184b0e0894b88a5688e01b3dc1e82"),
|
||||
T_002("56c4ca23c6484c8f8864c32fde4def8d"),
|
||||
T_003("66a8a37c5e9d4d2c9bb191acfe7f93aa")
|
||||
}
|
||||
|
|
@ -2,12 +2,14 @@ package com.tangem.data.network;
|
|||
|
||||
import com.tangem.data.network.model.RateInfoResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface CoinmarketApi {
|
||||
@GET(Server.ApiCoinmarket.Method.V1_TICKER_CONVERT)
|
||||
Observable<List<RateInfoResponse>> getRateInfoList();
|
||||
@Headers("X-CMC_PRO_API_KEY: f6622117-c043-47a0-8975-9d673ce484de")
|
||||
@GET(Server.ApiCoinmarket.Method.PRICE_CONVERSION)
|
||||
Observable<RateInfoResponse> getRateInfo(@Query("amount") int amount, @Query("symbol") String cryptoId);
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ 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.tangemcard.util.Util;
|
||||
import com.tangem.card_common.util.Util;
|
||||
import com.tangem.wallet.R;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
|
|||
32
app/src/main/java/com/tangem/data/network/InsightApi.java
Normal file
32
app/src/main/java/com/tangem/data/network/InsightApi.java
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.InsightBody;
|
||||
import com.tangem.data.network.model.InsightResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.GET;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
import retrofit2.http.Query;
|
||||
|
||||
public interface InsightApi {
|
||||
@GET(ServerApiInsight.INSIGHT_ADDRESS)
|
||||
Call<InsightResponse> insightAddress(@Path("address") String address);
|
||||
|
||||
@GET(ServerApiInsight.INSIGHT_UNSPENT_OUTPUTS)
|
||||
Call<List<InsightResponse>> insightUnspent(@Path("address") String address);
|
||||
|
||||
@GET(ServerApiInsight.INSIGHT_TRANSACTION)
|
||||
Call<InsightResponse> insightTransaction(@Path("txId") String txId);
|
||||
|
||||
@GET(ServerApiInsight.INSIGHT_FEE)
|
||||
Call<InsightResponse> insightFee();
|
||||
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(ServerApiInsight.INSIGHT_SEND)
|
||||
Call<InsightResponse> insightSend(@Body InsightBody body );
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import android.content.SharedPreferences;
|
|||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
|
||||
import com.tangem.tangemcard.util.Util;
|
||||
import com.tangem.card_common.util.Util;
|
||||
import com.tangem.wallet.R;
|
||||
|
||||
import org.spongycastle.util.encoders.Base64;
|
||||
|
|
|
|||
15
app/src/main/java/com/tangem/data/network/MaticApi.java
Normal file
15
app/src/main/java/com/tangem/data/network/MaticApi.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.InfuraBody;
|
||||
import com.tangem.data.network.model.InfuraResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface MaticApi {
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(Server.ApiMaticTesnet.Method.MAIN)
|
||||
Call<InfuraResponse> matic(@Body InfuraBody body);
|
||||
}
|
||||
15
app/src/main/java/com/tangem/data/network/RippleApi.java
Normal file
15
app/src/main/java/com/tangem/data/network/RippleApi.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.RippleBody;
|
||||
import com.tangem.data.network.model.RippleResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface RippleApi {
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST("./")
|
||||
Call<RippleResponse> ripple(@Body RippleBody body);
|
||||
}
|
||||
15
app/src/main/java/com/tangem/data/network/RootstockApi.java
Normal file
15
app/src/main/java/com/tangem/data/network/RootstockApi.java
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import com.tangem.data.network.model.InfuraBody;
|
||||
import com.tangem.data.network.model.InfuraResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.http.Body;
|
||||
import retrofit2.http.Headers;
|
||||
import retrofit2.http.POST;
|
||||
|
||||
public interface RootstockApi {
|
||||
@Headers("Content-Type: application/json")
|
||||
@POST(Server.ApiRootstock.Method.MAIN)
|
||||
Call<InfuraResponse> rootstock(@Body InfuraBody body);
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ public class Server {
|
|||
public static final String URL_COINMARKET = ServerURL.API_COINMARKETCAP;
|
||||
|
||||
public static class Method {
|
||||
static final String V1_TICKER_CONVERT = URL_COINMARKET + "v1/ticker/?convert=USD&lmit=10";
|
||||
static final String PRICE_CONVERSION = URL_COINMARKET + "v1/tools/price-conversion";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -28,7 +28,29 @@ public class Server {
|
|||
public static final String URL_INFURA = ServerURL.API_INFURA;
|
||||
|
||||
public static class Method {
|
||||
static final String MAIN = URL_INFURA + "613a0b14833145968b1f656240c7d245";
|
||||
static final String MAIN = URL_INFURA + "v3/613a0b14833145968b1f656240c7d245";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://public-node.rsk.co/
|
||||
*/
|
||||
public static class ApiRootstock {
|
||||
public static final String URL_ROOTSTOCK = ServerURL.API_ROOTSTOCK;
|
||||
|
||||
public static class Method {
|
||||
static final String MAIN = URL_ROOTSTOCK;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://testnet2.matic.network
|
||||
*/
|
||||
public static class ApiMaticTesnet {
|
||||
public static final String URL_MATIC_TESTNET = ServerURL.API_MATIC_TESTNET ;
|
||||
|
||||
public static class Method {
|
||||
static final String MAIN = URL_MATIC_TESTNET;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,4 +67,42 @@ public class Server {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://dex.binance.org/
|
||||
*/
|
||||
|
||||
public static class ApiBinance {
|
||||
public static final String URL_BINANCE = ServerURL.API_BINANCE;
|
||||
|
||||
public static class Method {
|
||||
public static final String API_V1 = URL_BINANCE + "api/v1/";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://testnet-dex.binance.org/
|
||||
*/
|
||||
|
||||
public static class ApiBinanceTestnet {
|
||||
public static final String URL_BINANCE_TESTNET = ServerURL.API_BINANCE_TESTNET;
|
||||
|
||||
public static class Method {
|
||||
public static final String API_V1 = URL_BINANCE_TESTNET + "api/v1/";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://api.blockcypher.com/
|
||||
*/
|
||||
|
||||
public static class ApiBlockcypher {
|
||||
public static final String URL_BLOCKCYPHER = ServerURL.API_BLOCKCYPHER;
|
||||
static final String V1_MAIN = "v1/{blockchain}/main";
|
||||
|
||||
public static class Method {
|
||||
static final String MAIN = URL_BLOCKCYPHER + V1_MAIN;
|
||||
static final String ADDRESS = MAIN + "/addrs/{address}?unspentOnly=true&includeScript=true";
|
||||
static final String PUSH = MAIN + "/txs/push";
|
||||
}
|
||||
}
|
||||
}
|
||||
144
app/src/main/java/com/tangem/data/network/ServerApiAdalite.java
Normal file
144
app/src/main/java/com/tangem/data/network/ServerApiAdalite.java
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.data.network.model.AdaliteBody;
|
||||
import com.tangem.data.network.model.AdaliteResponse;
|
||||
import com.tangem.data.network.model.AdaliteResponseUtxo;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
import retrofit2.converter.scalars.ScalarsConverterFactory;
|
||||
|
||||
public class ServerApiAdalite {
|
||||
private static String TAG = ServerApiAdalite.class.getSimpleName();
|
||||
|
||||
public static final String ADALITE_ADDRESS = "/api/addresses/summary/{address}";
|
||||
public static final String ADALITE_UNSPENT_OUTPUTS = "/api/bulk/addresses/utxo";
|
||||
// public static final String ADALITE_TRANSACTION = "/api/txs/raw/{txId}}";
|
||||
public static final String ADALITE_SEND = "/api/v2/txs/signed";
|
||||
|
||||
private int requestsCount = 0;
|
||||
|
||||
public static String lastNode;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, AdaliteResponse adaliteResponse);
|
||||
|
||||
void onSuccess(String method, AdaliteResponseUtxo adaliteResponseUtxo);
|
||||
|
||||
void onSuccess(String method, List listResponse);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String method, String wallet, String tx) {
|
||||
requestsCount++;
|
||||
String adaliteURL = "https://explorer2.adalite.io"; //TODO: make random selection
|
||||
this.lastNode = adaliteURL; //TODO: show node instead of URL
|
||||
|
||||
Retrofit retrofitAdalite = new Retrofit.Builder()
|
||||
.baseUrl(adaliteURL)
|
||||
.addConverterFactory(ScalarsConverterFactory.create())
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build();
|
||||
|
||||
AdaliteApi adaliteApi = retrofitAdalite.create(AdaliteApi.class);
|
||||
|
||||
switch (method) {
|
||||
case ADALITE_ADDRESS:
|
||||
|
||||
Call<AdaliteResponse> addressCall = adaliteApi.adaliteAddress(wallet);
|
||||
addressCall.enqueue(new Callback<AdaliteResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<AdaliteResponse> call, @NonNull Response<AdaliteResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<AdaliteResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case ADALITE_UNSPENT_OUTPUTS:
|
||||
Call<AdaliteResponseUtxo> outputsCall = adaliteApi.adaliteUnspent("[\"" + wallet + "\"]");
|
||||
outputsCall.enqueue(new Callback<AdaliteResponseUtxo>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<AdaliteResponseUtxo> call, @NonNull Response<AdaliteResponseUtxo> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<AdaliteResponseUtxo> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case ADALITE_SEND:
|
||||
Call<List> sendCall = adaliteApi.adaliteSend(new AdaliteBody(tx));
|
||||
sendCall.enqueue(new Callback<List>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List> call, @NonNull Response<List> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
responseListener.onFail(method, "undeclared method");
|
||||
Log.e(TAG, "requestData " + method + " onFailure - undeclared method");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
126
app/src/main/java/com/tangem/data/network/ServerApiBinance.java
Normal file
126
app/src/main/java/com/tangem/data/network/ServerApiBinance.java
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.wallet.TangemContext;
|
||||
import com.tangem.wallet.Transaction;
|
||||
import com.tangem.wallet.binance.BinanceData;
|
||||
import com.tangem.wallet.binance.client.BinanceDexApiRestClient;
|
||||
import com.tangem.wallet.binance.client.domain.Account;
|
||||
import com.tangem.wallet.binance.client.domain.Balance;
|
||||
import com.tangem.wallet.binance.client.domain.TransactionMetadata;
|
||||
import com.tangem.wallet.binance.client.encoding.message.TransactionRequestAssemblerExtSign;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||
import io.reactivex.observers.DefaultObserver;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
public class ServerApiBinance {
|
||||
private static String TAG = ServerApiBinance.class.getSimpleName();
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess();
|
||||
void onFail();
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void getBalance(TangemContext ctx, BinanceDexApiRestClient client) {
|
||||
Log.i(TAG, "new getBalance request");
|
||||
|
||||
Observable<Account> balanceObservable = Observable.just(new Account())
|
||||
.map(account -> client.getAccount(ctx.getCoinData().getWallet()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
|
||||
balanceObservable.subscribe(new DefaultObserver<Account>() {
|
||||
@Override
|
||||
public void onNext(Account account) {
|
||||
Log.i(TAG, "getBalance onNext");
|
||||
// account = client.getAccount(ctx.getCoinData().getWallet());
|
||||
BinanceData binanceData = (BinanceData) ctx.getCoinData();
|
||||
|
||||
for (Balance balance : account.getBalances()) {
|
||||
if (balance.getSymbol().equals("BNB")) {
|
||||
binanceData.setBalanceReceived(true);
|
||||
binanceData.setBalance(balance.getFree());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!binanceData.isBalanceReceived()) {
|
||||
binanceData.setBalanceReceived(true);
|
||||
binanceData.setBalance("0");
|
||||
}
|
||||
|
||||
binanceData.setAccountNumber(account.getAccountNumber());
|
||||
binanceData.setSequence(account.getSequence());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "getBalance onError" + e.getMessage());
|
||||
if (e.getMessage().contains("code=404")) {
|
||||
((BinanceData)ctx.getCoinData()).setError404(true);
|
||||
responseListener.onFail();
|
||||
} else {
|
||||
e.printStackTrace();
|
||||
ctx.setError(e.getMessage());
|
||||
responseListener.onFail();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.i(TAG, "getBalance onComplete");
|
||||
responseListener.onSuccess();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void sendTransaction (byte[] txForSend, BinanceDexApiRestClient client) {
|
||||
Log.i(TAG, "new sendTransaction request");
|
||||
|
||||
RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend);
|
||||
|
||||
Observable<List<TransactionMetadata>> sendObservable = Observable.just(new ArrayList<>())
|
||||
.map(metadatas -> client.broadcastNoWallet(requestBody, true))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
|
||||
sendObservable.subscribe(new DefaultObserver<List<TransactionMetadata>>() {
|
||||
@Override
|
||||
public void onNext(List<TransactionMetadata> metadatas ) {
|
||||
// RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend);
|
||||
// List<TransactionMetadata> metadatas = client.broadcastNoWallet(requestBody, true);
|
||||
if (!metadatas.isEmpty() && metadatas.get(0).isOk()) {
|
||||
responseListener.onSuccess();
|
||||
} else {
|
||||
Log.e(TAG, "Transaction send error");
|
||||
responseListener.onFail();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
Log.e(TAG, "sendTransaction onError" + e.getMessage());
|
||||
e.printStackTrace();
|
||||
responseListener.onFail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.i(TAG, "sendTransaction onComplete");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
import com.tangem.data.network.model.BlockcypherBody;
|
||||
import com.tangem.data.network.model.BlockcypherFee;
|
||||
import com.tangem.data.network.model.BlockcypherResponse;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class ServerApiBlockcypher {
|
||||
private static String TAG = ServerApiRipple.class.getSimpleName();
|
||||
|
||||
public static final String BLOCKCYPHER_ADDRESS = "blockcypher_address";
|
||||
public static final String BLOCKCYPHER_FEE = "blockcypher_fee";
|
||||
public static final String BLOCKCYPHER_SEND = "blockcypher_send";
|
||||
|
||||
private int requestsCount = 0;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, BlockcypherResponse blockcypherResponse);
|
||||
|
||||
void onSuccess(String method, BlockcypherFee blockcypherFee);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String blockchainID, String method, String wallet, String tx) {
|
||||
requestsCount++;
|
||||
String blockchain = blockchainID.toLowerCase();
|
||||
BlockcypherApi blockcypherApi = App.Companion.getNetworkComponent().getRetrofitBlockcypher().create(BlockcypherApi.class);
|
||||
|
||||
switch (method) {
|
||||
case BLOCKCYPHER_ADDRESS:
|
||||
Call<BlockcypherResponse> addressCall = blockcypherApi.blockcypherAddress(blockchain, wallet);
|
||||
addressCall.enqueue(new Callback<BlockcypherResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<BlockcypherResponse> call, @NonNull Response<BlockcypherResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<BlockcypherResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case BLOCKCYPHER_FEE:
|
||||
Call<BlockcypherFee> feeCall = blockcypherApi.blockcypherMain(blockchain);
|
||||
feeCall.enqueue(new Callback<BlockcypherFee>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<BlockcypherFee> call, @NonNull Response<BlockcypherFee> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<BlockcypherFee> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case BLOCKCYPHER_SEND:
|
||||
BlockcypherToken blockcypherToken = BlockcypherToken.values()[new Random().nextInt(BlockcypherToken.values().length)];
|
||||
|
||||
Call<BlockcypherResponse> sendCall = blockcypherApi.blockcypherPush(blockchain, new BlockcypherBody(tx), blockcypherToken.getToken());
|
||||
sendCall.enqueue(new Callback<BlockcypherResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<BlockcypherResponse> call, @NonNull Response<BlockcypherResponse> response) {
|
||||
if (response.code() == 201) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<BlockcypherResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
responseListener.onFail(method, "undeclared method");
|
||||
Log.e(TAG, "requestData " + method + " onFailure - undeclared method");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.support.annotation.NonNull;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
|
|
@ -24,19 +24,19 @@ public class ServerApiCommon {
|
|||
public static final int ESTIMATE_FEE_PRIORITY = 2;
|
||||
public static final int ESTIMATE_FEE_NORMAL = 3;
|
||||
public static final int ESTIMATE_FEE_MINIMAL = 6;
|
||||
private EstimateFeeListener estimateFeeListener;
|
||||
private EstimatedFeeListener estimatedFeeListener;
|
||||
|
||||
public interface EstimateFeeListener {
|
||||
public interface EstimatedFeeListener {
|
||||
void onSuccess(int blockCount, String estimateFeeResponse);
|
||||
void onFail(int blockCount, String message);
|
||||
}
|
||||
|
||||
public void setEstimateFee(EstimateFeeListener listener) {
|
||||
estimateFeeListener = listener;
|
||||
public void setBtcEstimatedFeeListener(EstimatedFeeListener listener) {
|
||||
estimatedFeeListener = listener;
|
||||
}
|
||||
|
||||
public void estimateFee(int blockCount) {
|
||||
EstimatefeeApi estimatefeeApi = App.getNetworkComponent().getRetrofitEstimatefee().create(EstimatefeeApi.class);
|
||||
public void requestBtcEstimatedFee(int blockCount) {
|
||||
EstimatefeeApi estimatefeeApi = App.Companion.getNetworkComponent().getRetrofitEstimatefee().create(EstimatefeeApi.class);
|
||||
|
||||
Call<String> call;
|
||||
switch (blockCount) {
|
||||
|
|
@ -60,17 +60,17 @@ public class ServerApiCommon {
|
|||
@Override
|
||||
public void onResponse(@NonNull Call<String> call, @NonNull Response<String> response) {
|
||||
if (response.code() == 200) {
|
||||
estimateFeeListener.onSuccess(blockCount, response.body());
|
||||
Log.i(TAG, "estimateFee onResponse " + response.code() + " " + response.body());
|
||||
estimatedFeeListener.onSuccess(blockCount, response.body());
|
||||
Log.i(TAG, "requestBtcEstimatedFee onResponse " + response.code() + " " + response.body());
|
||||
} else
|
||||
estimateFeeListener.onFail(blockCount, response.body());
|
||||
Log.e(TAG, "estimateFee onResponse " + response.code());
|
||||
estimatedFeeListener.onFail(blockCount, response.body());
|
||||
Log.e(TAG, "requestBtcEstimatedFee onResponse " + response.code());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<String> call, @NonNull Throwable t) {
|
||||
estimateFeeListener.onFail(blockCount, t.getMessage());
|
||||
Log.e(TAG, "estimateFee onFailure " + t.getMessage());
|
||||
estimatedFeeListener.onFail(blockCount, t.getMessage());
|
||||
Log.e(TAG, "requestBtcEstimatedFee onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -79,33 +79,51 @@ public class ServerApiCommon {
|
|||
* HTTP
|
||||
* Used in Crypto-currency course
|
||||
*/
|
||||
private RateInfoDataListener rateInfoDataListener;
|
||||
private RateInfoListener rateInfoListener;
|
||||
|
||||
public interface RateInfoDataListener {
|
||||
public interface RateInfoListener {
|
||||
void onSuccess(RateInfoResponse rateInfoResponse);
|
||||
|
||||
void onFail(String message);
|
||||
}
|
||||
|
||||
public void setRateInfoData(RateInfoDataListener listener) {
|
||||
rateInfoDataListener = listener;
|
||||
public void setRateInfoListener(RateInfoListener listener) {
|
||||
rateInfoListener = listener;
|
||||
}
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
public void rateInfoData(String cryptoId) {
|
||||
CoinmarketApi coinmarketApi = App.getNetworkComponent().getRetrofitCoinmarketcap().create(CoinmarketApi.class);
|
||||
public void requestRateInfo(String cryptoId) {
|
||||
CoinmarketApi coinmarketApi = App.Companion.getNetworkComponent().getRetrofitCoinmarketcap().create(CoinmarketApi.class);
|
||||
|
||||
coinmarketApi.getRateInfoList()
|
||||
// Call<RateInfoResponse> call = coinmarketApi.getRateInfo(1, cryptoId);
|
||||
//
|
||||
// call.enqueue(new Callback<RateInfoResponse>() {
|
||||
// @Override
|
||||
// public void onResponse(@NonNull Call<RateInfoResponse> call, @NonNull Response<RateInfoResponse> response) {
|
||||
// if (response.code() == 200) {
|
||||
// rateInfoListener.onSuccess(response.body());
|
||||
// Log.i(TAG, "coinmarketcap onResponse " + response.code());
|
||||
// } else {
|
||||
// rateInfoListener.onFail("Rate info error:" + String.valueOf(response.code()));
|
||||
// Log.e(TAG, "coinmarketcap onResponse " + response.code());
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void onFailure(@NonNull Call<RateInfoResponse> call, @NonNull Throwable t) {
|
||||
// rateInfoListener.onFail(String.valueOf(t.getMessage()));
|
||||
// Log.e(TAG, "coinmarketcap onFailure " + t.getMessage());
|
||||
// }
|
||||
// });
|
||||
coinmarketApi.getRateInfo(1, cryptoId)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(rateInfoModelList -> {
|
||||
if (!rateInfoModelList.isEmpty()) {
|
||||
for (RateInfoResponse rateInfoMode : rateInfoModelList) {
|
||||
if (rateInfoMode.getId().equals(cryptoId)) {
|
||||
rateInfoDataListener.onSuccess(rateInfoMode);
|
||||
Log.i(TAG, "rateInfoData " + cryptoId + " onResponse " + "200");
|
||||
}
|
||||
}
|
||||
} else
|
||||
Log.e(TAG, "rateInfoData " + cryptoId + " onResponse " + "Empty");
|
||||
.subscribe(rateInfoResponse -> {
|
||||
if (rateInfoResponse.getData().getQuote().getUsd().getPrice() != null) {
|
||||
rateInfoListener.onSuccess(rateInfoResponse);
|
||||
Log.i(TAG, "coinmarketcap onResponse " + 200);
|
||||
} else {
|
||||
rateInfoListener.onFail("Rate info error: wrong response");
|
||||
}
|
||||
},
|
||||
// handle error
|
||||
Throwable::printStackTrace);
|
||||
|
|
@ -126,7 +144,7 @@ public class ServerApiCommon {
|
|||
}
|
||||
|
||||
public void requestLastVersion() {
|
||||
UpdateVersionApi updateVersionApi = App.getNetworkComponent().getRetrofitGithubusercontent().create(UpdateVersionApi.class);
|
||||
UpdateVersionApi updateVersionApi = App.Companion.getNetworkComponent().getRetrofitGitHubUserContent().create(UpdateVersionApi.class);
|
||||
|
||||
Call<ResponseBody> call = updateVersionApi.getLastVersion();
|
||||
call.enqueue(new Callback<ResponseBody>() {
|
||||
|
|
|
|||
|
|
@ -3,13 +3,12 @@ package com.tangem.data.network;
|
|||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
import com.tangem.domain.wallet.TangemContext;
|
||||
import com.tangem.wallet.TangemContext;
|
||||
import com.tangem.data.Blockchain;
|
||||
import com.tangem.domain.wallet.bch.BitcoinCashNode;
|
||||
import com.tangem.domain.wallet.btc.BitcoinNode;
|
||||
import com.tangem.domain.wallet.btc.BitcoinNodeTestNet;
|
||||
import com.tangem.domain.wallet.ltc.LitecoinNode;
|
||||
import com.tangem.tangemcard.reader.CardProtocol;
|
||||
import com.tangem.wallet.bch.BitcoinCashNode;
|
||||
import com.tangem.wallet.btc.BitcoinNode;
|
||||
import com.tangem.wallet.btc.BitcoinNodeTestNet;
|
||||
import com.tangem.wallet.ltc.LitecoinNode;
|
||||
import com.tangem.wallet.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
|
|
@ -24,7 +23,6 @@ import java.net.InetSocketAddress;
|
|||
import java.net.Socket;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
|
@ -47,22 +45,23 @@ import io.reactivex.schedulers.Schedulers;
|
|||
/**
|
||||
* Request processor for Electrum Api
|
||||
* Every request live cycle:
|
||||
* 1. In application create request and call {@link ServerApiElectrum}.electrumRequestData(..)
|
||||
* 1. In application create request and call {@link ServerApiElectrum}.requestData(..)
|
||||
* 2. Try send every request for max 4 times,
|
||||
* 3. If all 4 times fail call DefaultObserver<ElectrumRequest>.onError (defined in .electrumRequestData(..)) and than
|
||||
* {@link ElectrumRequestDataListener}.onFail(...) callback
|
||||
* 3. If all 4 times fail call DefaultObserver<ElectrumRequest>.onError (defined in .requestData(..)) and than
|
||||
* {@link ResponseListener}.onFail(...) callback
|
||||
* Error can be acquired with {@link ElectrumRequest}.getError() method
|
||||
* 4. If request network communication finished successfully then call DefaultObserver<ElectrumRequest>.onComplete (defined in .electrumRequestData) and than
|
||||
* {@link ElectrumRequestDataListener}.onSuccess(...) callback
|
||||
* 4. If request network communication finished successfully then call DefaultObserver<ElectrumRequest>.onComplete (defined in .requestData) and than
|
||||
* {@link ResponseListener}.onSuccess(...) callback
|
||||
*/
|
||||
public class ServerApiElectrum {
|
||||
public static final String ERROR_STARTS_WITH_CODE_32601 = "{\"code\":-32601,";
|
||||
private static String TAG = ServerApiElectrum.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* TCP, SSL
|
||||
* Used in BTC, BCH
|
||||
*/
|
||||
private ElectrumRequestDataListener electrumRequestDataListener;
|
||||
private ResponseListener responseListener;
|
||||
private String host;
|
||||
private int port;
|
||||
|
||||
|
|
@ -76,7 +75,7 @@ public class ServerApiElectrum {
|
|||
/**
|
||||
* Interface for notification every request result
|
||||
*/
|
||||
public interface ElectrumRequestDataListener {
|
||||
public interface ResponseListener {
|
||||
|
||||
/**
|
||||
* Notify that request processing was successful
|
||||
|
|
@ -94,8 +93,8 @@ public class ServerApiElectrum {
|
|||
* Set notificaion listener
|
||||
* @param listener
|
||||
*/
|
||||
public void setElectrumRequestData(ElectrumRequestDataListener listener) {
|
||||
electrumRequestDataListener = listener;
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -104,7 +103,7 @@ public class ServerApiElectrum {
|
|||
* @param ctx
|
||||
* @param electrumRequest
|
||||
*/
|
||||
public void electrumRequestData(TangemContext ctx, ElectrumRequest electrumRequest) {
|
||||
public void requestData(TangemContext ctx, ElectrumRequest electrumRequest) {
|
||||
requestsCount++;
|
||||
Log.i(TAG, String.format("New request[%d]: %s", requestsCount,electrumRequest.getMethod()));
|
||||
Observable<ElectrumRequest> checkElectrumDataObserver = Observable.just(electrumRequest)
|
||||
|
|
@ -129,20 +128,20 @@ public class ServerApiElectrum {
|
|||
@Override
|
||||
public void onNext(ElectrumRequest v) {
|
||||
if (electrumRequest.answerData != null) {
|
||||
Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onNext != null");
|
||||
Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onNext != null");
|
||||
} else {
|
||||
Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onNext == null");
|
||||
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onNext == null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
requestsCount--;
|
||||
Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onError " + e.getMessage());
|
||||
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onError " + e.getMessage());
|
||||
Log.e(TAG, String.format("%d requests left in processing",requestsCount));
|
||||
electrumRequest.setError(ctx.getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
//setErrorOccurred(e.getMessage());//;
|
||||
electrumRequestDataListener.onFail(electrumRequest);
|
||||
responseListener.onFail(electrumRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -152,16 +151,16 @@ public class ServerApiElectrum {
|
|||
public void onComplete() {
|
||||
requestsCount--;
|
||||
if (electrumRequest.answerData != null) {
|
||||
Log.i(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onComplete, answerData!=null");
|
||||
Log.i(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData!=null");
|
||||
} else {
|
||||
Log.e(TAG, "electrumRequestData " + electrumRequest.getMethod() + " onComplete, answerData==null");
|
||||
Log.e(TAG, "requestData " + electrumRequest.getMethod() + " onComplete, answerData==null");
|
||||
}
|
||||
Log.e(TAG, String.format("%d requests left in processing",requestsCount));
|
||||
if (electrumRequest.answerData != null && electrumRequest.getError()==null) {
|
||||
electrumRequestDataListener.onSuccess(electrumRequest);
|
||||
responseListener.onSuccess(electrumRequest);
|
||||
} else {
|
||||
// if( error==null || error.isEmpty() ) setErrorOccurred(ctx.getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
electrumRequestDataListener.onFail(electrumRequest);
|
||||
responseListener.onFail(electrumRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -231,7 +230,7 @@ public class ServerApiElectrum {
|
|||
|
||||
private void doElectrumRequestTcp(ElectrumRequest electrumRequest, String host, int port) {
|
||||
try {
|
||||
Socket socket = App.getNetworkComponent().getSocket();
|
||||
Socket socket = App.Companion.getNetworkComponent().getSocket();
|
||||
socket.setSoTimeout(3000);
|
||||
Log.i(TAG, "Start process "+electrumRequest.getMethod()+" @ "+host + ":" + port);
|
||||
socket.connect(new InetSocketAddress(InetAddress.getByName(host), port));
|
||||
|
|
@ -250,15 +249,21 @@ public class ServerApiElectrum {
|
|||
electrumRequest.port = port;
|
||||
if (electrumRequest.answerData != null) {
|
||||
Log.i(TAG, ">> " + electrumRequest.answerData);
|
||||
if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) )
|
||||
{
|
||||
// method unknown error???
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
electrumRequest.answerData=null;
|
||||
}
|
||||
} else {
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
|
||||
Log.i(TAG, ">> <NULL>");
|
||||
}
|
||||
|
||||
} catch (ConnectException e) {
|
||||
//e.printStackTrace();
|
||||
//electrumRequestDataListener.onFail(e.getMessage());
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
|
||||
//responseListener.onFail(e.getMessage());
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
|
||||
Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
|
||||
} finally {
|
||||
Log.i(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " socket.close");
|
||||
|
|
@ -269,13 +274,13 @@ public class ServerApiElectrum {
|
|||
{
|
||||
e.printStackTrace();
|
||||
Log.e(TAG,"Can't close socket");
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
//e.printStackTrace();
|
||||
//electrumRequestDataListener.onFail(e.getMessage());
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
//responseListener.onFail(e.getMessage());
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
Log.e(TAG, "doElectrumRequestTcp " + electrumRequest.getMethod() + " IOException " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -312,14 +317,16 @@ public class ServerApiElectrum {
|
|||
// install the all-trusting host verifier
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
|
||||
|
||||
SSLSocket sslSocket;
|
||||
Socket sslSocket = new Socket();
|
||||
|
||||
List<ElectrumRequest> result = new ArrayList<>();
|
||||
Collections.addAll(result, electrumRequest);
|
||||
|
||||
try {
|
||||
Log.i(TAG, host + " " + port);
|
||||
sslSocket = (SSLSocket) sf.createSocket(host, port);
|
||||
sslSocket.connect(new InetSocketAddress(host,port), 3000);
|
||||
sslSocket.setSoTimeout(3000);
|
||||
sslSocket = sf.createSocket(sslSocket, host, port, true);
|
||||
try {
|
||||
OutputStream os = sslSocket.getOutputStream();
|
||||
OutputStreamWriter out = new OutputStreamWriter(os, "UTF-8");
|
||||
|
|
@ -333,14 +340,20 @@ public class ServerApiElectrum {
|
|||
electrumRequest.answerData = in.readLine();
|
||||
if (electrumRequest.answerData != null) {
|
||||
Log.i(TAG, ">> " + electrumRequest.answerData);
|
||||
if( (electrumRequest.getError()!=null && electrumRequest.getError().startsWith(ERROR_STARTS_WITH_CODE_32601)) )
|
||||
{
|
||||
// method unknown error???
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
electrumRequest.answerData=null;
|
||||
}
|
||||
} else {
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_answer));
|
||||
Log.i(TAG, ">> <NULL>");
|
||||
}
|
||||
|
||||
} catch (ConnectException e) {
|
||||
e.printStackTrace();
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_no_connection));
|
||||
Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " ConnectException " + e.getMessage());
|
||||
} finally {
|
||||
Log.i(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " socket.close");
|
||||
|
|
@ -349,7 +362,7 @@ public class ServerApiElectrum {
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "Can't close ssl socket");
|
||||
}
|
||||
|
|
@ -357,11 +370,11 @@ public class ServerApiElectrum {
|
|||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain_communication_error));
|
||||
Log.e(TAG, "doElectrumRequestSsl " + electrumRequest.getMethod() + " IOException " + e.getMessage());
|
||||
}
|
||||
} catch (NoSuchAlgorithmException | KeyManagementException e) {
|
||||
electrumRequest.setError(App.getInstance().getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
electrumRequest.setError(App.Companion.getInstance().getString(R.string.cannot_obtain_data_from_blockchain));
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
|
|
@ -38,21 +38,21 @@ public class ServerApiInfura {
|
|||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private InfuraBodyListener infuraBodyListener;
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface InfuraBodyListener {
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, InfuraResponse infuraResponse);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setInfuraResponse(InfuraBodyListener listener) {
|
||||
infuraBodyListener = listener;
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void infura(String method, int id, String wallet, String contract, String tx) {
|
||||
public void requestData(String method, int id, String wallet, String contract, String tx) {
|
||||
requestsCount++;
|
||||
InfuraApi infuraApi = App.getNetworkComponent().getRetrofitInfura().create(InfuraApi.class);
|
||||
InfuraApi infuraApi = App.Companion.getNetworkComponent().getRetrofitInfura().create(InfuraApi.class);
|
||||
|
||||
InfuraBody infuraBody;
|
||||
switch (method) {
|
||||
|
|
@ -86,18 +86,18 @@ public class ServerApiInfura {
|
|||
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
infuraBodyListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "infura " + method + " onResponse " + response.code());
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
infuraBodyListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "infura " + method + " onResponse " + response.code());
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
|
||||
infuraBodyListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "infura " + method + " onFailure " + t.getMessage());
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
129
app/src/main/java/com/tangem/data/network/ServerApiInsight.java
Normal file
129
app/src/main/java/com/tangem/data/network/ServerApiInsight.java
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.data.network.model.InsightBody;
|
||||
import com.tangem.data.network.model.InsightResponse;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class ServerApiInsight {
|
||||
private static String TAG = ServerApiInsight.class.getSimpleName();
|
||||
|
||||
public static final String INSIGHT_ADDRESS = "/addr/{address}";
|
||||
public static final String INSIGHT_UNSPENT_OUTPUTS = "/addr/{address}/utxo";
|
||||
public static final String INSIGHT_TRANSACTION = "/rawtx/{txId}";
|
||||
public static final String INSIGHT_FEE = "/utils/estimatefee?nbBlocks=2,3,6";
|
||||
public static final String INSIGHT_SEND = "/tx/send";
|
||||
|
||||
private int requestsCount = 0;
|
||||
|
||||
public static String lastNode;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, InsightResponse insightResponse);
|
||||
|
||||
void onSuccess(String method, List<InsightResponse> utxoList);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String method, String wallet, String tx) {
|
||||
requestsCount++;
|
||||
String insightURL = "http://130.185.109.17:3001/insigth-api"; //TODO: make random selection
|
||||
this.lastNode = insightURL; //TODO: show node instead of URL
|
||||
|
||||
Retrofit retrofitInsight = new Retrofit.Builder()
|
||||
.baseUrl(insightURL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build();
|
||||
|
||||
// InsightApi insightApi = App.getNetworkComponent().getRetrofitInsight(insightURL).create(InsightApi.class);
|
||||
InsightApi insightApi = retrofitInsight.create(InsightApi.class);
|
||||
|
||||
if (method.equals(INSIGHT_UNSPENT_OUTPUTS)) {
|
||||
Call<List<InsightResponse>> call = insightApi.insightUnspent(wallet);
|
||||
call.enqueue(new Callback<List<InsightResponse>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List<InsightResponse>> call, @NonNull Response<List<InsightResponse>> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<InsightResponse>> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
Call<InsightResponse> call;
|
||||
|
||||
switch (method) {
|
||||
case INSIGHT_ADDRESS:
|
||||
call = insightApi.insightAddress(wallet);
|
||||
break;
|
||||
|
||||
case INSIGHT_TRANSACTION:
|
||||
call = insightApi.insightTransaction(tx);
|
||||
break;
|
||||
|
||||
case INSIGHT_FEE:
|
||||
call = insightApi.insightFee();
|
||||
break;
|
||||
|
||||
case INSIGHT_SEND:
|
||||
call = insightApi.insightSend(new InsightBody(tx));
|
||||
break;
|
||||
|
||||
default:
|
||||
call = insightApi.insightAddress(wallet);
|
||||
break;
|
||||
}
|
||||
call.enqueue(new Callback<InsightResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<InsightResponse> call, @NonNull Response<InsightResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<InsightResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
105
app/src/main/java/com/tangem/data/network/ServerApiMatic.java
Normal file
105
app/src/main/java/com/tangem/data/network/ServerApiMatic.java
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
import com.tangem.data.network.model.InfuraBody;
|
||||
import com.tangem.data.network.model.InfuraResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class ServerApiMatic {
|
||||
private static String TAG = ServerApiMatic.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* HTTP
|
||||
* Infura
|
||||
* <p>
|
||||
* eth_getBalance
|
||||
* eth_getTransactionCount
|
||||
* eth_call
|
||||
* eth_sendRawTransaction
|
||||
* eth_gasPrice
|
||||
*/
|
||||
public static final String MATIC_ETH_GET_BALANCE = "eth_getBalance";
|
||||
public static final String MATIC_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount";
|
||||
public static final String MATIC_ETH_GET_PENDING_COUNT = "eth_getPendingCount";
|
||||
public static final String MATIC_ETH_CALL = "eth_call";
|
||||
public static final String MATIC_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction";
|
||||
public static final String MATIC_ETH_GAS_PRICE = "eth_gasPrice";
|
||||
|
||||
private int requestsCount=0;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, InfuraResponse infuraResponse);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String method, int id, String wallet, String contract, String tx) {
|
||||
requestsCount++;
|
||||
MaticApi maticApi = App.Companion.getNetworkComponent().getRetrofitMaticTesnet().create(MaticApi.class);
|
||||
|
||||
InfuraBody infuraBody;
|
||||
switch (method) {
|
||||
case MATIC_ETH_GET_BALANCE:
|
||||
case MATIC_ETH_GET_TRANSACTION_COUNT:
|
||||
infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id);
|
||||
break;
|
||||
case MATIC_ETH_GET_PENDING_COUNT:
|
||||
infuraBody = new InfuraBody(MATIC_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id);
|
||||
break;
|
||||
case MATIC_ETH_CALL:
|
||||
String address = wallet.substring(2);
|
||||
infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id);
|
||||
break;
|
||||
|
||||
case MATIC_ETH_SEND_RAW_TRANSACTION:
|
||||
infuraBody = new InfuraBody(method, new String[]{tx}, id);
|
||||
break;
|
||||
|
||||
case MATIC_ETH_GAS_PRICE:
|
||||
infuraBody = new InfuraBody(method, id);
|
||||
break;
|
||||
|
||||
default:
|
||||
infuraBody = new InfuraBody();
|
||||
}
|
||||
|
||||
Call<InfuraResponse> call = maticApi.matic(infuraBody);
|
||||
call.enqueue(new Callback<InfuraResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
117
app/src/main/java/com/tangem/data/network/ServerApiRipple.java
Normal file
117
app/src/main/java/com/tangem/data/network/ServerApiRipple.java
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.data.network.model.RippleBody;
|
||||
import com.tangem.data.network.model.RippleResponse;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
public class ServerApiRipple {
|
||||
private static String TAG = ServerApiRipple.class.getSimpleName();
|
||||
|
||||
public static final String RIPPLE_ACCOUNT_INFO = "account_info";
|
||||
public static final String RIPPLE_ACCOUNT_UNCONFIRMED = "account_unconfirmed";
|
||||
public static final String RIPPLE_SUBMIT = "submit";
|
||||
public static final String RIPPLE_FEE = "fee";
|
||||
public static final String RIPPLE_SERVER_STATE = "server_state";
|
||||
|
||||
private int requestsCount = 0;
|
||||
|
||||
public static String lastNode;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, RippleResponse rippleResponse);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String method, String wallet, String tx) {
|
||||
requestsCount++;
|
||||
String rippleURL = "https://s1.ripple.com:51234"; //TODO: make random selection
|
||||
lastNode = rippleURL; //TODO: show node instead of URL
|
||||
|
||||
Retrofit retrofitRipple = new Retrofit.Builder()
|
||||
.baseUrl(rippleURL)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build();
|
||||
|
||||
RippleApi rippleApi = retrofitRipple.create(RippleApi.class);
|
||||
|
||||
RippleBody rippleBody;
|
||||
HashMap<String, String> paramsMap;
|
||||
|
||||
switch (method) {
|
||||
case RIPPLE_ACCOUNT_INFO:
|
||||
paramsMap = new HashMap<>();
|
||||
paramsMap.put("account", wallet);
|
||||
paramsMap.put("ledger_index", "validated");
|
||||
rippleBody = new RippleBody(method, paramsMap);
|
||||
break;
|
||||
|
||||
case RIPPLE_ACCOUNT_UNCONFIRMED:
|
||||
paramsMap = new HashMap<>();
|
||||
paramsMap.put("account", wallet);
|
||||
paramsMap.put("ledger_index", "current");
|
||||
// paramsMap.put("queue", "true"); TODO: make queue check if needed
|
||||
rippleBody = new RippleBody(RIPPLE_ACCOUNT_INFO, paramsMap);
|
||||
break;
|
||||
|
||||
case RIPPLE_SERVER_STATE:
|
||||
rippleBody = new RippleBody(method, new HashMap<>());
|
||||
break;
|
||||
|
||||
case RIPPLE_FEE:
|
||||
rippleBody = new RippleBody(method, new HashMap<>());
|
||||
break;
|
||||
|
||||
case RIPPLE_SUBMIT:
|
||||
paramsMap = new HashMap<>();
|
||||
paramsMap.put("tx_blob", tx);
|
||||
rippleBody = new RippleBody(method, paramsMap);
|
||||
break;
|
||||
|
||||
default:
|
||||
rippleBody = new RippleBody();
|
||||
}
|
||||
|
||||
Call<RippleResponse> call = rippleApi.ripple(rippleBody);
|
||||
call.enqueue(new Callback<RippleResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<RippleResponse> call, @NonNull Response<RippleResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<RippleResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package com.tangem.data.network;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tangem.App;
|
||||
import com.tangem.data.network.model.InfuraBody;
|
||||
import com.tangem.data.network.model.InfuraResponse;
|
||||
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class ServerApiRootstock {
|
||||
private static String TAG = ServerApiRootstock.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* HTTP
|
||||
* Rootstock
|
||||
* <p>
|
||||
* eth_getBalance
|
||||
* eth_getTransactionCount
|
||||
* eth_call
|
||||
* eth_sendRawTransaction
|
||||
* eth_gasPrice
|
||||
*/
|
||||
public static final String ROOTSTOCK_ETH_GET_BALANCE = "eth_getBalance";
|
||||
public static final String ROOTSTOCK_ETH_GET_TRANSACTION_COUNT = "eth_getTransactionCount";
|
||||
public static final String ROOTSTOCK_ETH_GET_PENDING_COUNT = "eth_getPendingCount";
|
||||
public static final String ROOTSTOCK_ETH_CALL = "eth_call";
|
||||
public static final String ROOTSTOCK_ETH_SEND_RAW_TRANSACTION = "eth_sendRawTransaction";
|
||||
public static final String ROOTSTOCK_ETH_GAS_PRICE = "eth_gasPrice";
|
||||
|
||||
private int requestsCount=0;
|
||||
|
||||
public boolean isRequestsSequenceCompleted() {
|
||||
Log.i(TAG, String.format("isRequestsSequenceCompleted: %s (%d requests left)", String.valueOf(requestsCount <= 0), requestsCount));
|
||||
return requestsCount <= 0;
|
||||
}
|
||||
|
||||
private ResponseListener responseListener;
|
||||
|
||||
public interface ResponseListener {
|
||||
void onSuccess(String method, InfuraResponse infuraResponse);
|
||||
|
||||
void onFail(String method, String message);
|
||||
}
|
||||
|
||||
public void setResponseListener(ResponseListener listener) {
|
||||
responseListener = listener;
|
||||
}
|
||||
|
||||
public void requestData(String method, int id, String wallet, String contract, String tx) {
|
||||
requestsCount++;
|
||||
RootstockApi rootstockApi = App.Companion.getNetworkComponent().getRetrofitRootstock().create(RootstockApi.class);
|
||||
|
||||
InfuraBody infuraBody;
|
||||
switch (method) {
|
||||
case ROOTSTOCK_ETH_GET_BALANCE:
|
||||
case ROOTSTOCK_ETH_GET_TRANSACTION_COUNT:
|
||||
infuraBody = new InfuraBody(method, new String[]{wallet, "latest"}, id);
|
||||
break;
|
||||
case ROOTSTOCK_ETH_GET_PENDING_COUNT:
|
||||
infuraBody = new InfuraBody(ROOTSTOCK_ETH_GET_TRANSACTION_COUNT, new String[]{wallet, "pending"}, id);
|
||||
break;
|
||||
case ROOTSTOCK_ETH_CALL:
|
||||
String address = wallet.substring(2);
|
||||
infuraBody = new InfuraBody(method, new Object[]{new InfuraBody.EthCallParams("0x70a08231000000000000000000000000" + address, contract), "latest"}, id);
|
||||
break;
|
||||
|
||||
case ROOTSTOCK_ETH_SEND_RAW_TRANSACTION:
|
||||
infuraBody = new InfuraBody(method, new String[]{tx}, id);
|
||||
break;
|
||||
|
||||
case ROOTSTOCK_ETH_GAS_PRICE:
|
||||
infuraBody = new InfuraBody(method, id);
|
||||
break;
|
||||
|
||||
default:
|
||||
infuraBody = new InfuraBody();
|
||||
}
|
||||
|
||||
Call<InfuraResponse> call = rootstockApi.rootstock(infuraBody);
|
||||
call.enqueue(new Callback<InfuraResponse>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<InfuraResponse> call, @NonNull Response<InfuraResponse> response) {
|
||||
if (response.code() == 200) {
|
||||
requestsCount--;
|
||||
responseListener.onSuccess(method, response.body());
|
||||
Log.i(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
} else {
|
||||
responseListener.onFail(method, String.valueOf(response.code()));
|
||||
Log.e(TAG, "requestData " + method + " onResponse " + response.code());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<InfuraResponse> call, @NonNull Throwable t) {
|
||||
responseListener.onFail(method, String.valueOf(t.getMessage()));
|
||||
Log.e(TAG, "requestData " + method + " onFailure " + t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2,9 +2,14 @@ package com.tangem.data.network;
|
|||
|
||||
class ServerURL {
|
||||
static final String API_TANGEM = "https://verify.tangem.com/";
|
||||
static final String API_COINMARKETCAP = "https://api.coinmarketcap.com/";
|
||||
static final String API_INFURA = "https://mainnet.infura.io/v3/";
|
||||
static final String API_COINMARKETCAP = "https://pro-api.coinmarketcap.com/";
|
||||
static final String API_INFURA = "https://mainnet.infura.io/";
|
||||
static final String API_ESTIMATEFEE = "https://estimatefee.com/";
|
||||
static final String API_UPDATE_VERSION = "https://raw.githubusercontent.com/";
|
||||
static final String API_ROOTSTOCK = "https://public-node.rsk.co/";
|
||||
static final String API_BLOCKCYPHER = "https://api.blockcypher.com/";
|
||||
static final String API_BINANCE = "https://dex.binance.org/";
|
||||
static final String API_BINANCE_TESTNET = "https://testnet-dex.binance.org/";
|
||||
static final String API_MATIC_TESTNET = "https://testnet2.matic.network";
|
||||
static final String API_STELLAR = "https://horizon-testnet.stellar.org";
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class AdaliteBody {
|
||||
private String signedTx;
|
||||
|
||||
public AdaliteBody(String signedTx) {
|
||||
this.signedTx = signedTx;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class AdaliteResponse(
|
||||
@SerializedName("Right")
|
||||
var right: AdaliteAddressData? = null
|
||||
)
|
||||
|
||||
data class AdaliteResponseUtxo(
|
||||
@SerializedName("Right")
|
||||
var right: List<AdaliteUtxoData>
|
||||
)
|
||||
|
||||
data class AdaliteAddressData(
|
||||
@SerializedName("caAddress")
|
||||
var caAddress: String? = null,
|
||||
|
||||
@SerializedName("caBalance")
|
||||
var caBalance: AdaliteCoins? = null,
|
||||
|
||||
@SerializedName("caTxList")
|
||||
var caTxList: List<AdaliteTxData>
|
||||
)
|
||||
|
||||
data class AdaliteCoins(
|
||||
@SerializedName("getCoin")
|
||||
var getCoin: Long? = null
|
||||
)
|
||||
|
||||
data class AdaliteUtxoData(
|
||||
@SerializedName("cuId")
|
||||
var cuId: String? = null,
|
||||
|
||||
@SerializedName("cuOutIndex")
|
||||
var cuOutIndex: Int? = null,
|
||||
|
||||
@SerializedName("cuCoins")
|
||||
var cuCoins: AdaliteCoins? = null
|
||||
)
|
||||
|
||||
data class AdaliteTxData(
|
||||
@SerializedName("ctbId")
|
||||
var ctbId: String? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BinanceFees(
|
||||
@SerializedName("fixed_fee_params")
|
||||
var fixed_fee_params: BinanceFixedFee? = null
|
||||
)
|
||||
|
||||
data class BinanceFixedFee(
|
||||
@SerializedName("msg_type")
|
||||
var msg_type: String? = null,
|
||||
|
||||
@SerializedName("fee")
|
||||
var fee: Int? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class BlockcypherBody {
|
||||
private String tx;
|
||||
|
||||
public BlockcypherBody(String tx) {
|
||||
this.tx = tx;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class BlockcypherResponse(
|
||||
@SerializedName("address")
|
||||
var address: String? = null,
|
||||
|
||||
@SerializedName("balance")
|
||||
var balance: Long? = null,
|
||||
|
||||
@SerializedName("unconfirmed_balance")
|
||||
var unconfirmed_balance: Long? = null,
|
||||
|
||||
@SerializedName("txrefs")
|
||||
var txrefs: List<BlockcypherTxref>? = null
|
||||
)
|
||||
|
||||
data class BlockcypherTxref(
|
||||
@SerializedName("tx_hash")
|
||||
var tx_hash: String? = null,
|
||||
|
||||
@SerializedName("tx_output_n")
|
||||
var tx_output_n: Int? = null,
|
||||
|
||||
@SerializedName("value")
|
||||
var value: Long? = null,
|
||||
|
||||
@SerializedName("confirmations")
|
||||
var confirmations: Long? = null,
|
||||
|
||||
@SerializedName("script")
|
||||
var script: String? = null
|
||||
)
|
||||
|
||||
data class BlockcypherFee(
|
||||
@SerializedName("low_fee_per_kb")
|
||||
var low_fee_per_kb: Long? = null,
|
||||
|
||||
@SerializedName("medium_fee_per_kb")
|
||||
var medium_fee_per_kb: Long? = null,
|
||||
|
||||
@SerializedName("high_fee_per_kb")
|
||||
var high_fee_per_kb: Long? = null
|
||||
)
|
||||
|
|
@ -4,6 +4,7 @@ public class InfuraBody {
|
|||
private String method;
|
||||
private Object[] params;
|
||||
private int id;
|
||||
private String jsonrpc = "2.0";
|
||||
|
||||
public InfuraBody() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ data class InfuraResponse(
|
|||
var id: Int? = null,
|
||||
|
||||
@SerializedName("result")
|
||||
var result: String = "",
|
||||
var result: String? = null,
|
||||
|
||||
@SerializedName("error")
|
||||
var error: String = ""
|
||||
var error: Object
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
public class InsightBody {
|
||||
private String rawtx;
|
||||
|
||||
public InsightBody(String rawtx){
|
||||
this.rawtx = rawtx;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class InsightResponse(
|
||||
@SerializedName("balanceSat")
|
||||
var balanceSat: Long? = null,
|
||||
|
||||
@SerializedName("unconfirmedBalanceSat")
|
||||
var unconfirmedBalanceSat: Long? = null,
|
||||
|
||||
@SerializedName("addrStr")
|
||||
var addrStr: String = "",
|
||||
|
||||
@SerializedName("txid")
|
||||
var txid: String = "",
|
||||
|
||||
@SerializedName("satoshis")
|
||||
var satoshis: Long? = null,
|
||||
|
||||
@SerializedName("height")
|
||||
var height: Int? = null,
|
||||
|
||||
@SerializedName("2")
|
||||
var fee2: String = "",
|
||||
|
||||
@SerializedName("3")
|
||||
var fee3: String = "",
|
||||
|
||||
@SerializedName("6")
|
||||
var fee6: String = "",
|
||||
|
||||
@SerializedName("rawtx")
|
||||
var rawtx: String = "",
|
||||
|
||||
@SerializedName("error")
|
||||
var error: String = ""
|
||||
)
|
||||
|
|
@ -1,76 +1,23 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class RateInfoResponse(
|
||||
@SerializedName(ID)
|
||||
var id: String = "",
|
||||
@SerializedName("data")
|
||||
var data: RateData? = null
|
||||
)
|
||||
|
||||
@SerializedName(NAME)
|
||||
var name: String = "",
|
||||
data class RateData(
|
||||
@SerializedName("quote")
|
||||
var quote: Quote? = null
|
||||
)
|
||||
|
||||
@SerializedName(SYMBOL)
|
||||
var symbol: String = "",
|
||||
data class Quote(
|
||||
@SerializedName("USD")
|
||||
var usd: CurrencyRate? = null
|
||||
)
|
||||
|
||||
@SerializedName(RANK)
|
||||
var rank: String = "",
|
||||
|
||||
@SerializedName(PRICE_USD)
|
||||
var priceUsd: String = "",
|
||||
|
||||
@SerializedName(PRICE_BTC)
|
||||
var priceBtc: String = "",
|
||||
|
||||
@SerializedName(VOLUME_USD_24H)
|
||||
var volumeUsd24h: String = "",
|
||||
|
||||
@SerializedName(MARKET_CAP_USD)
|
||||
var marketCapUsd: String = "",
|
||||
|
||||
@SerializedName(AVAILABLE_SUPPLY)
|
||||
var availableSupply: String = "",
|
||||
|
||||
@SerializedName(TOTAL_SUPPLY)
|
||||
var totalSupply: String = "",
|
||||
|
||||
@SerializedName(MAX_SUPPLY)
|
||||
var maxSupply: String = "",
|
||||
|
||||
@SerializedName(PERCENT_CHANGE_1H)
|
||||
var percentChange1h: String = "",
|
||||
|
||||
@SerializedName(PERCENT_CHANGE_24H)
|
||||
var percentChange24h: String = "",
|
||||
|
||||
@SerializedName(PERCENT_CHANGE_7H)
|
||||
var percentChange7h: String = "",
|
||||
|
||||
@SerializedName(LAST_UPDATED)
|
||||
var lastUpdated: String = ""
|
||||
|
||||
) : Parcelable {
|
||||
|
||||
companion object {
|
||||
val TAG: String = RateInfoResponse::class.java.simpleName
|
||||
|
||||
const val ID = "id"
|
||||
const val NAME = "name"
|
||||
const val SYMBOL = "symbol"
|
||||
const val RANK = "rank"
|
||||
const val PRICE_USD = "price_usd"
|
||||
const val PRICE_BTC = "price_btc"
|
||||
const val VOLUME_USD_24H = "24h_volume_usd"
|
||||
const val MARKET_CAP_USD = "market_cap_usd"
|
||||
const val AVAILABLE_SUPPLY = "available_supply"
|
||||
const val TOTAL_SUPPLY = "total_supply"
|
||||
const val MAX_SUPPLY = "max_supply"
|
||||
const val PERCENT_CHANGE_1H = "percent_change_1h"
|
||||
const val PERCENT_CHANGE_24H = "percent_change_24h"
|
||||
const val PERCENT_CHANGE_7H = "percent_change_7d"
|
||||
const val LAST_UPDATED = "last_updated"
|
||||
}
|
||||
|
||||
}
|
||||
data class CurrencyRate(
|
||||
@SerializedName("price")
|
||||
var price: Float? = null
|
||||
)
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.tangem.data.network.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class RippleBody {
|
||||
private String method;
|
||||
private ArrayList<HashMap<String,String>> params;
|
||||
|
||||
public RippleBody() {
|
||||
}
|
||||
|
||||
//for RIPPLE_FEE
|
||||
public RippleBody(String method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
public RippleBody(String method, HashMap<String,String> paramsMap) {
|
||||
this.method = method;
|
||||
ArrayList<HashMap<String, String>> paramsList = new ArrayList<>();
|
||||
paramsList.add(paramsMap);
|
||||
this.params = paramsList;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.tangem.data.network.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class RippleResponse(
|
||||
@SerializedName("result")
|
||||
var result: RippleResult? = null
|
||||
)
|
||||
|
||||
data class RippleResult(
|
||||
@SerializedName("account_data")
|
||||
var account_data: RippleAccountData? = null,
|
||||
|
||||
@SerializedName("validated")
|
||||
var validated: Boolean? = null,
|
||||
|
||||
//for RIPPLE_FEE
|
||||
@SerializedName("drops")
|
||||
var drops: RippleFeeDrops? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("engine_result_code")
|
||||
var engine_result_code: Int? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName ("engine_result_message")
|
||||
var engine_result_message: String? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("error")
|
||||
var error: String? = null,
|
||||
|
||||
//for RIPPLE_SUBMIT
|
||||
@SerializedName("error_exception")
|
||||
var error_exception: String? = null,
|
||||
|
||||
//for RIPPLE_SERVER_STATE
|
||||
@SerializedName("state")
|
||||
var state: RippleState? = null,
|
||||
|
||||
//for "Account not found error"
|
||||
@SerializedName("error_code")
|
||||
var error_code: Int? = null
|
||||
)
|
||||
|
||||
data class RippleAccountData(
|
||||
@SerializedName("Account")
|
||||
var account: String? = null,
|
||||
|
||||
@SerializedName("Balance")
|
||||
var balance: String? = null,
|
||||
|
||||
@SerializedName("Sequence")
|
||||
var sequence: Long? = null
|
||||
)
|
||||
|
||||
data class RippleFeeDrops(
|
||||
//enough to put tx to queue
|
||||
@SerializedName("minimum_fee")
|
||||
var minimum_fee: String? = null,
|
||||
|
||||
//enough to put tx to current ledger
|
||||
@SerializedName("open_ledger_fee")
|
||||
var open_ledger_fee: String? = null,
|
||||
|
||||
@SerializedName("median_fee")
|
||||
var median_fee: String? = null
|
||||
)
|
||||
|
||||
data class RippleState(
|
||||
@SerializedName("validated_ledger")
|
||||
var validated_ledger: RippleLedger? = null
|
||||
)
|
||||
|
||||
data class RippleLedger(
|
||||
@SerializedName("reserve_base")
|
||||
var reserve_base: Long? = null
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue