diff --git a/.idea/dictionaries/.xml b/.idea/dictionaries/.xml new file mode 100644 index 0000000000..fc9ea1f34e --- /dev/null +++ b/.idea/dictionaries/.xml @@ -0,0 +1,7 @@ + + + + blockchains + + + \ No newline at end of file diff --git a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java b/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java index 8f1ec5fc5e..5694d0ad4a 100644 --- a/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java +++ b/app/src/main/java/com/tangem/wallet/bch/BtcCashEngine.java @@ -679,8 +679,12 @@ public class BtcCashEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java index 3bdc80e3b8..71953fc5cf 100644 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceAssetEngine.java @@ -11,7 +11,10 @@ import com.tangem.data.Blockchain; import com.tangem.data.network.BinanceApi; import com.tangem.data.network.Server; import com.tangem.data.network.ServerApiBinance; +import com.tangem.data.network.ServerApiPayId; import com.tangem.data.network.model.BinanceFees; +import com.tangem.data.network.model.PayIdAddress; +import com.tangem.data.network.model.PayIdResponse; import com.tangem.tangem_card.data.TangemCard; import com.tangem.tangem_card.reader.CardProtocol; import com.tangem.tangem_card.tasks.SignTask; @@ -44,6 +47,10 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import java.util.List; +import io.reactivex.CompletableObserver; +import io.reactivex.SingleObserver; +import io.reactivex.observers.DisposableCompletableObserver; +import io.reactivex.observers.DisposableSingleObserver; import retrofit2.Call; import retrofit2.Callback; import retrofit2.Response; @@ -154,6 +161,10 @@ public class BinanceAssetEngine extends CoinEngine { return false; } + if (address.contains("$")) { // PayID + return validatePayId(address); + } + try { Crypto.decodeAddress(address); } catch (Exception e) { @@ -380,6 +391,14 @@ public class BinanceAssetEngine extends CoinEngine { public SignTask.TransactionToSign constructTransaction(Amount amountValue, Amount feeValue, boolean IncFee, String targetAddress) throws Exception { checkBlockchainDataExists(); + String destination; + //PayID + if (coinData.getResolvedPayIdAddress() != null) { + destination = coinData.getResolvedPayIdAddress(); + } else { + destination = targetAddress; + } + String amount; if (IncFee && amountValue.getCurrency().equals(getFeeCurrency())) { //Coin transfer only @@ -398,7 +417,7 @@ public class BinanceAssetEngine extends CoinEngine { Transfer transfer = new Transfer(); transfer.setCoin(amountValue.getCurrency().equals(getFeeCurrency()) ? getFeeCurrency() : ctx.getCard().getContractAddress()); transfer.setFromAddress(ctx.getCoinData().getWallet()); - transfer.setToAddress(targetAddress); + transfer.setToAddress(destination); transfer.setAmount(amount); TransactionOption options = TransactionOption.DEFAULT_INSTANCE; @@ -490,6 +509,27 @@ public class BinanceAssetEngine extends CoinEngine { } public void requestFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks, String targetAddress, Amount amount) { + CompletableObserver payIdObserver = new DisposableCompletableObserver() { + @Override + public void onComplete() { + checkFee(blockchainRequestsCallbacks); + } + + @Override + public void onError(Throwable e) { + ctx.setError(e.getMessage()); + blockchainRequestsCallbacks.onComplete(false); + } + }; + + if (targetAddress.contains("$")) { // PayID + resolvePayID(targetAddress, payIdObserver); + } else { + checkFee(blockchainRequestsCallbacks); + } + } + + private void checkFee(BlockchainRequestsCallbacks blockchainRequestsCallbacks) { try { String baseUrl = Server.ApiBinance.Method.API_V1; @@ -535,6 +575,46 @@ public class BinanceAssetEngine extends CoinEngine { } } + private void resolvePayID(String targetAddress, CompletableObserver observer) { + final ServerApiPayId serverApiPayId = new ServerApiPayId(); + + SingleObserver payIdObserver = new DisposableSingleObserver() { + @Override + public void onSuccess(PayIdResponse payIdResponse) { + try { + String resolvedAddress = null; + for (PayIdAddress address : payIdResponse.getAddresses()) { + if (address.getPaymentNetwork().equals(ctx.getBlockchain().getCurrency()) && + address.getEnvironment().equals("MAINNET")) { + resolvedAddress = address.getAddressDetails().getAddress(); + break; + } + } + if (validateAddress(resolvedAddress)) { + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } + } else { + observer.onError(new Exception("Unknown address format in PayID response")); + } + } catch (Exception e) { + observer.onError(new Exception("Unknown response format on PayID request")); + } + } + + @Override + public void onError(Throwable e) { + Log.i(TAG, "onFail: " + "payID" + " " + e.getMessage()); + observer.onError(new Exception("PayID error:" + e.getMessage())); + } + }; + + serverApiPayId.getAddress(targetAddress, ctx.getBlockchain(), payIdObserver); + } + public void requestSendTransaction(BlockchainRequestsCallbacks blockchainRequestsCallbacks, byte[] txForSend) { // RequestBody requestBody = TransactionRequestAssemblerExtSign.createRequestBody(txForSend); try { diff --git a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java b/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java index a8f459b4bc..5fc513cb3a 100644 --- a/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java +++ b/app/src/main/java/com/tangem/wallet/binance/BinanceEngine.java @@ -575,8 +575,12 @@ public class BinanceEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java b/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java index 062f544334..ced2861a0e 100644 --- a/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/btc/BtcEngine.java @@ -1087,11 +1087,11 @@ public class BtcEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - if (resolvedAddress.equals(coinData.getWallet())) { - observer.onError(new Exception(ctx.getString(R.string.prepare_transaction_error_same_address))); - } else { + if (!resolvedAddress.equals(coinData.getWallet())) { coinData.setResolvedPayIdAddress(resolvedAddress); observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); } } else { observer.onError(new Exception("Unknown address format in PayID response")); diff --git a/app/src/main/java/com/tangem/wallet/cardano/CardanoEngine.java b/app/src/main/java/com/tangem/wallet/cardano/CardanoEngine.java index 68037e128b..16a7e2b2c6 100644 --- a/app/src/main/java/com/tangem/wallet/cardano/CardanoEngine.java +++ b/app/src/main/java/com/tangem/wallet/cardano/CardanoEngine.java @@ -9,7 +9,6 @@ import com.tangem.App; import com.tangem.Constant; import com.tangem.data.local.PendingTransactionsStorage; import com.tangem.data.network.ServerApiAdalite; -import com.tangem.data.network.ServerApiBlockcypher; import com.tangem.data.network.ServerApiPayId; import com.tangem.data.network.model.AdaliteResponse; import com.tangem.data.network.model.AdaliteResponseUtxo; @@ -776,8 +775,12 @@ public class CardanoEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } @@ -817,15 +820,8 @@ public class CardanoEngine extends CoinEngine { @Override public void onSuccess(String method, String stringResponse) { - if (method.equals(ServerApiAdalite.ADALITE_SEND)) { - if (stringResponse.equals("\"Transaction sent successfully!\"")) { - ctx.setError(null); - blockchainRequestsCallbacks.onComplete(true); - } else { // TODO: Make check for a valid send response - ctx.setError(stringResponse); - blockchainRequestsCallbacks.onComplete(false); - } - } + ctx.setError(null); + blockchainRequestsCallbacks.onComplete(true); } diff --git a/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java b/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java index 307adbee55..a18a6683ca 100644 --- a/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java +++ b/app/src/main/java/com/tangem/wallet/ducatus/DucatusEngine.java @@ -604,8 +604,12 @@ public class DucatusEngine extends BtcEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/eth/EthEngine.java b/app/src/main/java/com/tangem/wallet/eth/EthEngine.java index a0aae17a7d..0b8cf41106 100644 --- a/app/src/main/java/com/tangem/wallet/eth/EthEngine.java +++ b/app/src/main/java/com/tangem/wallet/eth/EthEngine.java @@ -674,7 +674,7 @@ public class EthEngine extends CoinEngine { } if (validateAddress(resolvedAddress)) { if (resolvedAddress.equals(coinData.getWallet())) { - ctx.setError(R.string.prepare_transaction_error_same_address); + ctx.setError("Resolved PayID address equals source address"); blockchainRequestsCallbacks.onComplete(false); } else { coinData.setResolvedPayIdAddress(resolvedAddress); diff --git a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java index 6a303a449d..9e92abd656 100644 --- a/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java +++ b/app/src/main/java/com/tangem/wallet/ltc/LtcEngine.java @@ -758,8 +758,12 @@ public class LtcEngine extends BtcEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/rsk/RskEngine.java b/app/src/main/java/com/tangem/wallet/rsk/RskEngine.java index 0e981ad42e..826158771f 100644 --- a/app/src/main/java/com/tangem/wallet/rsk/RskEngine.java +++ b/app/src/main/java/com/tangem/wallet/rsk/RskEngine.java @@ -200,7 +200,17 @@ public class RskEngine extends EthEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); + if (resolvedAddress.equals(coinData.getWallet())) { + ctx.setError("Resolved PayID address equals source address"); + blockchainRequestsCallbacks.onComplete(false); + } else { + coinData.setResolvedPayIdAddress(resolvedAddress); + if (serverApiRootstock.isRequestsSequenceCompleted() && serverApiPayId.isRequestsSequenceCompleted()) { + blockchainRequestsCallbacks.onComplete(!ctx.hasError()); + } else { + blockchainRequestsCallbacks.onProgress(); + } + } } else { ctx.setError("Unknown address format in PayID response"); blockchainRequestsCallbacks.onComplete(false); diff --git a/app/src/main/java/com/tangem/wallet/rsk/RskTokenEngine.java b/app/src/main/java/com/tangem/wallet/rsk/RskTokenEngine.java index 4907b39831..efa84c9476 100644 --- a/app/src/main/java/com/tangem/wallet/rsk/RskTokenEngine.java +++ b/app/src/main/java/com/tangem/wallet/rsk/RskTokenEngine.java @@ -231,7 +231,17 @@ public class RskTokenEngine extends TokenEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); + if (resolvedAddress.equals(coinData.getWallet())) { + ctx.setError("Resolved PayID address equals source address"); + blockchainRequestsCallbacks.onComplete(false); + } else { + coinData.setResolvedPayIdAddress(resolvedAddress); + if (serverApiRootstock.isRequestsSequenceCompleted() && serverApiPayId.isRequestsSequenceCompleted()) { + blockchainRequestsCallbacks.onComplete(!ctx.hasError()); + } else { + blockchainRequestsCallbacks.onProgress(); + } + } } else { ctx.setError("Unknown address format in PayID response"); blockchainRequestsCallbacks.onComplete(false); diff --git a/app/src/main/java/com/tangem/wallet/token/TokenEngine.java b/app/src/main/java/com/tangem/wallet/token/TokenEngine.java index a04ca3fa6d..cae64f6f2b 100644 --- a/app/src/main/java/com/tangem/wallet/token/TokenEngine.java +++ b/app/src/main/java/com/tangem/wallet/token/TokenEngine.java @@ -877,7 +877,7 @@ public class TokenEngine extends CoinEngine { } if (validateAddress(resolvedAddress)) { if (resolvedAddress.equals(coinData.getWallet())) { - ctx.setError(R.string.prepare_transaction_error_same_address); + ctx.setError("Resolved PayID address equals source address"); blockchainRequestsCallbacks.onComplete(false); } else { coinData.setResolvedPayIdAddress(resolvedAddress); diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java b/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java index 882e4e8c7c..0de8d22584 100644 --- a/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java +++ b/app/src/main/java/com/tangem/wallet/xlm/XlmAssetEngine.java @@ -589,7 +589,7 @@ public class XlmAssetEngine extends CoinEngine { CompletableObserver payIdObserver = new DisposableCompletableObserver() { @Override public void onComplete() { - checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount); + checkTargetAccountCreated(blockchainRequestsCallbacks, coinData.getResolvedPayIdAddress(), amount); } @Override @@ -622,8 +622,12 @@ public class XlmAssetEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java index ff9c7303cc..cc8d377184 100644 --- a/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java +++ b/app/src/main/java/com/tangem/wallet/xlm/XlmEngine.java @@ -565,7 +565,7 @@ public class XlmEngine extends CoinEngine { CompletableObserver payIdObserver = new DisposableCompletableObserver() { @Override public void onComplete() { - checkTargetAccountCreated(blockchainRequestsCallbacks, targetAddress, amount); + checkTargetAccountCreated(blockchainRequestsCallbacks, coinData.getResolvedPayIdAddress(), amount); } @Override @@ -598,8 +598,12 @@ public class XlmEngine extends CoinEngine { } } if (validateAddress(resolvedAddress)) { - coinData.setResolvedPayIdAddress(resolvedAddress); - observer.onComplete(); + if (!resolvedAddress.equals(coinData.getWallet())) { + coinData.setResolvedPayIdAddress(resolvedAddress); + observer.onComplete(); + } else { + observer.onError(new Exception("Resolved PayID address equals source address")); + } } else { observer.onError(new Exception("Unknown address format in PayID response")); } diff --git a/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java b/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java index 29a57b9457..6ea70b9d81 100644 --- a/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java +++ b/app/src/main/java/com/tangem/wallet/xrp/XrpEngine.java @@ -635,14 +635,14 @@ public class XrpEngine extends CoinEngine { XrpXAddressDecoded xAddressDecoded = XrpXAddressService.Companion.decode(resolvedAddress); if (xAddressDecoded == null) { // classic address if (resolvedAddress.equals(coinData.getWallet())) { - ctx.setError(R.string.prepare_transaction_error_same_address); + ctx.setError("Resolved PayID address equals source address"); blockchainRequestsCallbacks.onComplete(false); } else { serverApiRipple.requestData(ServerApiRipple.RIPPLE_ACCOUNT_INFO, resolvedAddress, ""); } } else { // X-address if (xAddressDecoded.getAddress().equals(coinData.getWallet())) { - ctx.setError(R.string.prepare_transaction_error_same_address); + ctx.setError("Resolved PayID address equals source address"); blockchainRequestsCallbacks.onComplete(false); } else { serverApiRipple.requestData(ServerApiRipple.RIPPLE_ACCOUNT_INFO, xAddressDecoded.getAddress(), ""); diff --git a/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt b/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt index ed9371767b..a858e25318 100644 --- a/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt +++ b/server-android/src/main/java/com/tangem/server_android/data/LocalStorage.kt @@ -47,7 +47,7 @@ class LocalStorage artworks = HashMap() } - if (artworks.count() < 44) { + if (artworks.count() < 45) { // forceSave=true only on the last one putResourceArtworkToCatalog(R.drawable.card_default, false) putResourceArtworkToCatalog(R.drawable.card_default_nft, false) @@ -90,6 +90,7 @@ class LocalStorage putResourceArtworkToCatalog(R.drawable.card_tg061, false) putResourceArtworkToCatalog(R.drawable.card_tg062, false) putResourceArtworkToCatalog(R.drawable.card_tg063, false) + putResourceArtworkToCatalog(R.drawable.card_tg073, false) putResourceArtworkToCatalog(R.drawable.card_tgslix, false) putResourceArtworkToCatalog(R.drawable.card_bc00, false) putResourceArtworkToCatalog(R.drawable.card_ff32, true) @@ -305,6 +306,7 @@ class LocalStorage card.batch == "0050" -> R.drawable.card_tg061 card.batch == "0051" -> R.drawable.card_tg062 card.batch == "0052" -> R.drawable.card_tg063 + card.batch == "0060" -> R.drawable.card_tg073 card.batch == "FF32" -> R.drawable.card_ff32 else -> null diff --git a/server-android/src/main/res/drawable/card_tg073.png b/server-android/src/main/res/drawable/card_tg073.png new file mode 100644 index 0000000000..205f99d631 Binary files /dev/null and b/server-android/src/main/res/drawable/card_tg073.png differ