Updated on 2026-08-14
This commit is contained in:
parent
abc5bc3d14
commit
6948a2c04a
8 changed files with 121 additions and 29 deletions
|
|
@ -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--;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ class VerifyCard : Fragment(), NfcAdapter.ReaderCallback {
|
|||
|
||||
companion object {
|
||||
val TAG: String = VerifyCard::class.java.simpleName
|
||||
|
||||
}
|
||||
|
||||
private var nfcManager: NfcManager? = null
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue