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