Updated on 2026-08-14

This commit is contained in:
Tangem 2018-12-18 11:42:27 +03:00
parent abc5bc3d14
commit 6948a2c04a
8 changed files with 121 additions and 29 deletions

View file

@ -42,6 +42,17 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DefaultObserver;
import io.reactivex.schedulers.Schedulers;
/**
* Request processor for Electrum Api
* Every request live cycle:
* 1. In application create request and call {@link ServerApiElectrum}.electrumRequestData(..)
* 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
* 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
*/
public class ServerApiElectrum {
private static String TAG = ServerApiElectrum.class.getSimpleName();
@ -60,16 +71,37 @@ public class ServerApiElectrum {
return requestsCount <= 0;
}
/**
* Interface for notification every request result
*/
public interface ElectrumRequestDataListener {
void onSuccess(ElectrumRequest electrumRequest);
/**
* Notify that request processing was successful
* @param electrumRequest - processed request containing received answer {@see electrumRequest.getAnswer() method}
*/
void onSuccess(ElectrumRequest electrumRequest);
/**
* Notify that request processing was successful
* @param electrumRequest - processed request containing occurred error {@see electrumRequest.getError() method}
*/
void onFail(ElectrumRequest electrumRequest);
}
/**
* Set notificaion listener
* @param listener
*/
public void setElectrumRequestData(ElectrumRequestDataListener listener) {
electrumRequestDataListener = listener;
}
/**
* Start process request
* @param ctx
* @param electrumRequest
*/
public void electrumRequestData(TangemContext ctx, ElectrumRequest electrumRequest) {
requestsCount++;
Log.i(TAG, String.format("New request[%d]: %s", requestsCount,electrumRequest.getMethod()));
@ -111,6 +143,9 @@ public class ServerApiElectrum {
electrumRequestDataListener.onFail(electrumRequest);
}
/**
* Called after completion request processing
*/
@Override
public void onComplete() {
requestsCount--;

View file

@ -295,7 +295,7 @@ public abstract class CoinEngine {
/**
* Notification that the all requests in sequence completed
* Call after a last request completed
* If occurred error return in ctx.error
* If occurred error return in {@link TangemContext} {@see TangemContext.getError()}
*
* @param success -*
*/
@ -319,12 +319,26 @@ public abstract class CoinEngine {
/**
* Start sequence of request to blockchain nodes needed to get balance and other information (for example unspent transaction) needed to
* show current state of wallet and prepare new withdrawal transaction
* Save result in {@link CoinData}
* If occurred error can be get at onComplete callback in {@link TangemContext}.getError()
* @param blockchainRequestsCallbacks - notifications
* @throws Exception
* @throws Exception if something goes wrong
*/
public abstract void requestBalanceAndUnspentTransactions(BlockchainRequestsCallbacks blockchainRequestsCallbacks) throws Exception;
/**
* Start sequence of request to blockchain nodes needed to get fee amount for a new transaction
* Save result in {@link CoinData} minFee, maxFee, normalFee
* @param blockchainRequestsCallbacks - notifications
* @throws Exception if something goes wrong
*/
public abstract void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) throws Exception;
/**
* Start sequence of request to blockchain nodes needed to send new transaction
* If occurred error can be get at onComplete callback in {@link TangemContext}.getError()
* @param blockchainRequestsCallbacks - notifications
* @throws Exception if something goes wrong
*/
public abstract void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) throws Exception;
}

View file

@ -1,6 +1,7 @@
package com.tangem.domain.wallet.token;
import android.net.Uri;
import android.os.Bundle;
import android.text.InputFilter;
import android.util.Log;
@ -13,6 +14,7 @@ import com.tangem.domain.wallet.CoinEngine;
import com.tangem.domain.wallet.ECDSASignatureETH;
import com.tangem.domain.wallet.EthTransaction;
import com.tangem.domain.wallet.Keccak256;
import com.tangem.domain.wallet.eth.EthData;
import com.tangem.tangemcard.data.TangemCard;
import com.tangem.domain.wallet.TangemContext;
import com.tangem.domain.wallet.BTCUtils;
@ -45,6 +47,13 @@ public class TokenEngine extends CoinEngine {
ctx.setCoinData(coinData);
} else if (ctx.getCoinData() instanceof TokenData) {
coinData = (TokenData) ctx.getCoinData();
} else if (ctx.getCoinData() instanceof EthData) {
// special case with receive card data substitution from server at the moment
Bundle B=new Bundle();
ctx.getCoinData().saveToBundle(B);
coinData = new TokenData();
coinData.loadFromBundle(B);
ctx.setCoinData(coinData);
} else {
throw new Exception("Invalid type of Blockchain data for TokenEngine");
}

View file

@ -21,25 +21,28 @@ import android.view.ViewGroup
import android.widget.Toast
import com.tangem.App
import com.tangem.Constant
import com.tangem.data.Blockchain
import com.tangem.data.network.ServerApiCommon
import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo
import com.tangem.tangemcard.tasks.VerifyCardTask
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.domain.wallet.*
import com.tangem.domain.wallet.BalanceValidator
import com.tangem.domain.wallet.CoinEngine
import com.tangem.domain.wallet.CoinEngineFactory
import com.tangem.domain.wallet.TangemContext
import com.tangem.presentation.activity.*
import com.tangem.presentation.dialog.NoExtendedLengthSupportDialog
import com.tangem.presentation.dialog.PINSwapWarningDialog
import com.tangem.presentation.dialog.ShowQRCodeDialog
import com.tangem.presentation.dialog.WaitSecurityDelayDialog
import com.tangem.data.Blockchain
import com.tangem.tangemcard.android.reader.NfcManager
import com.tangem.tangemcard.android.reader.NfcReader
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD
import com.tangem.tangemcard.data.EXTRA_TANGEM_CARD_UID
import com.tangem.tangemcard.data.TangemCard
import com.tangem.tangemcard.data.loadFromBundle
import com.tangem.tangemcard.reader.CardProtocol
import com.tangem.tangemcard.tasks.VerifyCardTask
import com.tangem.tangemcard.util.Util
import com.tangem.tangemserver.android.ServerApiTangem
import com.tangem.tangemserver.android.model.CardVerifyAndGetInfo
import com.tangem.util.UtilHelper
import com.tangem.wallet.R
import kotlinx.android.synthetic.main.fr_loaded_wallet.*
@ -108,10 +111,6 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
btnExtract.isEnabled = false
btnExtract.backgroundTintList = inactiveColor
refresh()
startVerify(lastTag)
tvWallet.text = ctx.coinData.wallet
// set listeners
@ -406,6 +405,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
val cardVerifyAndGetInfoListener: ServerApiTangem.CardVerifyAndGetInfoListener = object : ServerApiTangem.CardVerifyAndGetInfoListener {
override fun onSuccess(cardVerifyAndGetArtworkResponse: CardVerifyAndGetInfo.Response?) {
Log.i(TAG,"cardVerifyAndGetInfoListener onSuccess")
if( activity==null || !UtilHelper.isOnline(activity!!)) return
val result = cardVerifyAndGetArtworkResponse?.results!![0]
if (result.error != null) {
ctx.card!!.isOnlineVerified = false
@ -413,8 +414,9 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
ctx.card!!.isOnlineVerified = result.passed
// if (requestCounter == 0)
requestCounter--
// if (requestCounter == 0)
updateViews()
if (!result.passed) return
@ -423,13 +425,6 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
Log.w(TAG, "Batch ${result.batch} info changed to '$result'")
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!))
App.localStorage.applySubstitution(ctx.card!!)
//todo - check this is not need after refactoring
// if (ctx.blockchain == Blockchain.Token || ctx.blockchain == Blockchain.Ethereum) {
// ctx.card!!.setBlockchainIDFromCard(Blockchain.Ethereum.id)
//ctx.blockchain=Blockchain.Ethereum
//engine=engine!!.swithToOtherEngine(Blockchain.Ethereum)
// }
refresh()
}
if (result.artwork != null && App.localStorage.checkNeedUpdateArtwork(result.artwork)) {
@ -443,6 +438,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
override fun onFail(message: String?) {
Log.i(TAG,"cardVerifyAndGetInfoListener onFail")
if( activity==null || !UtilHelper.isOnline(activity!!)) return
requestCounter--
updateViews()
}
@ -453,6 +449,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
val artworkListener: ServerApiTangem.ArtworkListener = object : ServerApiTangem.ArtworkListener {
override fun onSuccess(artworkId: String?, inputStream: InputStream?, updateDate: Date?) {
Log.i(TAG,"artworkListener onSuccess")
if( activity==null || !UtilHelper.isOnline(activity!!)) return
App.localStorage.updateArtwork(artworkId!!, inputStream!!, updateDate!!)
requestCounter--
ivTangemCard.setImageBitmap(App.localStorage.getCardArtworkBitmap(ctx.card!!))
@ -461,6 +458,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
override fun onFail(message: String?) {
Log.i(TAG,"artworkListener onFail")
if( activity==null || !UtilHelper.isOnline(activity!!)) return
requestCounter--
updateViews()
}
@ -469,27 +467,32 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
// request rate info listener
serverApiCommon.setRateInfoData {
if( activity==null || !UtilHelper.isOnline(activity!!)) return@setRateInfoData
val rate = it.priceUsd.toFloat()
ctx.coinData!!.rate = rate
ctx.coinData!!.rateAlter = rate
}
refresh()
startVerify(lastTag)
}
override fun onResume() {
super.onResume()
nfcManager!!.onResume()
nfcManager.onResume()
}
override fun onPause() {
super.onPause()
nfcManager!!.onPause()
nfcManager.onPause()
if (timerRepeatRefresh != null)
timerRepeatRefresh!!.cancel()
}
override fun onStop() {
super.onStop()
nfcManager!!.onStop()
nfcManager.onStop()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -722,6 +725,8 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
fun updateViews() {
if( activity==null || !UtilHelper.isOnline(activity!!)) return
if (timerHideErrorAndMessage != null) {
timerHideErrorAndMessage!!.cancel()
timerHideErrorAndMessage = null
@ -780,7 +785,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
} else
tvBlockchain.text = ctx.blockchainName
if (engine.hasBalanceInfo()) {
if (requestCounter==0 && engine.hasBalanceInfo()) {
btnExtract.isEnabled = true
btnExtract.backgroundTintList = activeColor
} else {
@ -815,6 +820,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
object : CoinEngine.BlockchainRequestsCallbacks {
override fun onComplete(success: Boolean) {
Log.i(TAG, "requestBalanceAndUnspentTransactions onComplete: "+success.toString()+", request counter "+requestCounter.toString())
if( activity==null || !UtilHelper.isOnline(activity!!)) return
requestCounter--
if(! success)
{
@ -824,6 +830,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
}
override fun onProgress() {
if( activity==null || !UtilHelper.isOnline(activity!!)) return
Log.i(TAG, "requestBalanceAndUnspentTransactions onProgress")
updateViews()
}
@ -864,7 +871,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
// Token
else if (ctx.blockchain == Blockchain.Token) {
val engine = CoinEngineFactory.create(ctx)
// val engine = CoinEngineFactory.create(ctx)
// requestInfura(ServerApiInfura.INFURA_ETH_CALL, (engine as TokenEngine).getContractAddress(ctx.card))
requestRateInfo("ethereum")
}
@ -923,7 +930,7 @@ class LoadedWallet : Fragment(), NfcAdapter.ReaderCallback, CardProtocol.Notific
val sUID = Util.byteArrayToHexString(uid)
if (ctx.card.uid != sUID) {
// Log.d(TAG, "Invalid UID: $sUID")
nfcManager!!.ignoreTag(isoDep.tag)
nfcManager.ignoreTag(isoDep.tag)
return
} else {
// Log.v(TAG, "UID: $sUID")

View file

@ -35,7 +35,6 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
companion object {
val TAG: String = VerifyCard::class.java.simpleName
}
private var nfcManager: NfcManager? = null

View file

@ -2,6 +2,11 @@ package com.tangem.tangemcard.data.external;
import com.tangem.tangemcard.data.TangemCard;
/**
* This interface provide method to make substitution of read card data (token symbol, contract address)
* if they was unknown when the card was produced
*/
public interface CardDataSubstitutionProvider {
void applySubstitution(TangemCard card);
}

View file

@ -1,5 +1,9 @@
package com.tangem.tangemcard.data.external;
/**
* This interfaces provide function to randomly select parameters to run one VerifyCode command, check answer and
* state that card is genuine or not
*/
public interface FirmwaresDigestsProvider {
VerifyCodeRecord selectRandomVerifyCodeBlock(String firmwareVersion);

View file

@ -2,10 +2,29 @@ package com.tangem.tangemcard.data.external;
import java.util.List;
/**
* Interface of PINsProvider - object that know some list of PINs (used when start first time read), PIN2 (used for protected operation) and store last used PIN
* to use it in following operations
*/
public interface PINsProvider {
/**
* @return list of known PINs
* This PINs used when start reading of card
* When start reading a PINs from this list used sequential in search PIN algorithm until right PIN found
*/
List<String> getPINs();
/**
* @return PIN2 for protected operations
*/
String getPIN2();
/**
* Call after successful first time reading of card to store founded PIN (normally this PIN must be returned in next time {@see getPINs} at first position)
* @param pin
*/
void setLastUsedPIN(String pin);
List<String> getPINs();
}