1
mirror of https://github.com/m2049r/xmrwallet synced 2025-09-05 09:58:42 +02:00

Compare commits

...

6 Commits

Author SHA1 Message Date
m2049r
e56369b91a fix tests (#717) 2021-02-19 17:25:11 +01:00
m2049r
b04aa24269 bump version 2021-02-19 16:35:02 +01:00
m2049r
dda86bd5de fix URI generation (#716) 2021-02-19 16:32:15 +01:00
m2049r
a19ad7fd52 change build to docker (#715) 2021-02-19 16:31:35 +01:00
m2049r
0443fd808c bump version (consolidating with play release) 2021-02-17 00:16:24 +01:00
m2049r
faf57c96fc add more output currencies (#714) 2021-02-15 21:38:26 +01:00
122 changed files with 2547 additions and 2005 deletions

View File

@@ -13,7 +13,7 @@ set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../external-libs)
add_library(sodium STATIC IMPORTED) add_library(sodium STATIC IMPORTED)
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/libsodium/lib/${ANDROID_ABI}/libsodium.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libsodium.a)
############ ############
# OpenSSL # OpenSSL
@@ -21,11 +21,11 @@ set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
add_library(crypto STATIC IMPORTED) add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libcrypto.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libcrypto.a)
add_library(ssl STATIC IMPORTED) add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/openssl/lib/${ANDROID_ABI}/libssl.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libssl.a)
############ ############
# Boost # Boost
@@ -33,39 +33,39 @@ set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
add_library(boost_chrono STATIC IMPORTED) add_library(boost_chrono STATIC IMPORTED)
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_chrono.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_chrono.a)
add_library(boost_date_time STATIC IMPORTED) add_library(boost_date_time STATIC IMPORTED)
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_date_time.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_date_time.a)
add_library(boost_filesystem STATIC IMPORTED) add_library(boost_filesystem STATIC IMPORTED)
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_filesystem.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_filesystem.a)
add_library(boost_program_options STATIC IMPORTED) add_library(boost_program_options STATIC IMPORTED)
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_program_options.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_program_options.a)
add_library(boost_regex STATIC IMPORTED) add_library(boost_regex STATIC IMPORTED)
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_regex.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_regex.a)
add_library(boost_serialization STATIC IMPORTED) add_library(boost_serialization STATIC IMPORTED)
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_serialization.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_serialization.a)
add_library(boost_system STATIC IMPORTED) add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_system.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_system.a)
add_library(boost_thread STATIC IMPORTED) add_library(boost_thread STATIC IMPORTED)
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_thread.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_thread.a)
add_library(boost_wserialization STATIC IMPORTED) add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/boost/lib/${ANDROID_ABI}/libboost_wserialization.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libboost_wserialization.a)
############# #############
# Monero # Monero
@@ -73,99 +73,103 @@ set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
add_library(wallet_api STATIC IMPORTED) add_library(wallet_api STATIC IMPORTED)
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet_api.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet_api.a)
add_library(wallet STATIC IMPORTED) add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libwallet.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet.a)
add_library(cryptonote_core STATIC IMPORTED) add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_core.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_core.a)
add_library(cryptonote_basic STATIC IMPORTED) add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcryptonote_basic.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_basic.a)
add_library(mnemonics STATIC IMPORTED) add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmnemonics.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libmnemonics.a)
add_library(common STATIC IMPORTED) add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcommon.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcommon.a)
add_library(cncrypto STATIC IMPORTED) add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcncrypto.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcncrypto.a)
add_library(ringct STATIC IMPORTED) add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libringct.a)
add_library(ringct_basic STATIC IMPORTED) add_library(ringct_basic STATIC IMPORTED)
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libringct_basic.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libringct_basic.a)
add_library(blockchain_db STATIC IMPORTED) add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblockchain_db.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libblockchain_db.a)
add_library(lmdb STATIC IMPORTED) add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/liblmdb.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/liblmdb.a)
add_library(easylogging STATIC IMPORTED) add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libeasylogging.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libeasylogging.a)
add_library(unbound STATIC IMPORTED) add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libunbound.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libunbound.a)
add_library(epee STATIC IMPORTED) add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libepee.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libepee.a)
add_library(blocks STATIC IMPORTED) add_library(blocks STATIC IMPORTED)
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libblocks.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libblocks.a)
add_library(checkpoints STATIC IMPORTED) add_library(checkpoints STATIC IMPORTED)
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libcheckpoints.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcheckpoints.a)
add_library(device STATIC IMPORTED) add_library(device STATIC IMPORTED)
set_target_properties(device PROPERTIES IMPORTED_LOCATION set_target_properties(device PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libdevice.a)
add_library(device_trezor STATIC IMPORTED) add_library(device_trezor STATIC IMPORTED)
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libdevice_trezor.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libdevice_trezor.a)
add_library(multisig STATIC IMPORTED) add_library(multisig STATIC IMPORTED)
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libmultisig.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libmultisig.a)
add_library(version STATIC IMPORTED) add_library(version STATIC IMPORTED)
set_target_properties(version PROPERTIES IMPORTED_LOCATION set_target_properties(version PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libversion.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libversion.a)
add_library(net STATIC IMPORTED) add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION set_target_properties(net PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libnet.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libnet.a)
add_library(hardforks STATIC IMPORTED) add_library(hardforks STATIC IMPORTED)
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/libhardforks.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libhardforks.a)
add_library(randomx STATIC IMPORTED) add_library(randomx STATIC IMPORTED)
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librandomx.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/librandomx.a)
add_library(rpc_base STATIC IMPORTED) add_library(rpc_base STATIC IMPORTED)
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/monero/lib/${ANDROID_ABI}/librpc_base.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/librpc_base.a)
add_library(wallet-crypto STATIC IMPORTED)
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet-crypto.a)
############# #############
# System # System
@@ -173,10 +177,16 @@ set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
find_library( log-lib log ) find_library( log-lib log )
include_directories( ${EXTERNAL_LIBS_DIR}/monero/include ) include_directories( ${EXTERNAL_LIBS_DIR}/include )
message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR}) message(STATUS EXTERNAL_LIBS_DIR : ${EXTERNAL_LIBS_DIR})
if(${ANDROID_ABI} STREQUAL "x86_64")
set(EXTRA_LIBS "wallet-crypto")
else()
set(EXTRA_LIBS "")
endif()
target_link_libraries( monerujo target_link_libraries( monerujo
wallet_api wallet_api
@@ -203,6 +213,7 @@ target_link_libraries( monerujo
randomx randomx
hardforks hardforks
rpc_base rpc_base
${EXTRA_LIBS}
boost_chrono boost_chrono
boost_date_time boost_date_time

View File

@@ -7,8 +7,8 @@ android {
applicationId "com.m2049r.xmrwallet" applicationId "com.m2049r.xmrwallet"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 702 versionCode 707
versionName "1.17.2 'Druk'" versionName "1.17.7 'Druk'"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild { externalNativeBuild {
cmake { cmake {

View File

@@ -213,7 +213,7 @@ public class BaseActivity extends SecureActivity implements GenerateReviewFragme
if (uri == null) { if (uri == null) {
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show(); Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
} else { } else {
BarcodeData bc = BarcodeData.fromQrCode(uri.toString()); BarcodeData bc = BarcodeData.fromString(uri.toString());
if (bc == null) if (bc == null)
Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show(); Toast.makeText(this, getString(R.string.nfc_tag_read_undef), Toast.LENGTH_LONG).show();
else else

View File

@@ -58,6 +58,7 @@ import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.m2049r.xmrwallet.BuildConfig; import com.m2049r.xmrwallet.BuildConfig;
import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.ledger.LedgerProgressDialog; import com.m2049r.xmrwallet.ledger.LedgerProgressDialog;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
@@ -469,7 +470,7 @@ public class ReceiveFragment extends Fragment {
Timber.d("CLEARQR"); Timber.d("CLEARQR");
return; return;
} }
bcData = new BarcodeData(BarcodeData.Asset.XMR, address, notes, xmrAmount); bcData = new BarcodeData(Crypto.XMR, address, notes, xmrAmount);
int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight()); int size = Math.max(ivQrCode.getWidth(), ivQrCode.getHeight());
Bitmap qr = generate(bcData.getUriString(), size, size); Bitmap qr = generate(bcData.getUriString(), size, size);
if (qr != null) { if (qr != null) {

View File

@@ -73,14 +73,7 @@ public class ScannerFragment extends Fragment implements ZXingScannerView.Result
// * On older devices continuously stopping and resuming camera preview can result in freezing the app. // * On older devices continuously stopping and resuming camera preview can result in freezing the app.
// * I don't know why this is the case but I don't have the time to figure out. // * I don't know why this is the case but I don't have the time to figure out.
Handler handler = new Handler(); Handler handler = new Handler();
handler.postDelayed(new handler.postDelayed(() -> mScannerView.resumeCameraPreview(ScannerFragment.this), 2000);
Runnable() {
@Override
public void run() {
mScannerView.resumeCameraPreview(ScannerFragment.this);
}
}, 2000);
} }
@Override @Override

View File

@@ -300,7 +300,7 @@ public class TxFragment extends Fragment {
} }
tvTxXmrToKey.setText(key); tvTxXmrToKey.setText(key);
tvDestinationBtc.setText(userNotes.xmrtoDestination); tvDestinationBtc.setText(userNotes.xmrtoDestination);
tvTxAmountBtc.setText(userNotes.xmrtoAmount + " BTC"); tvTxAmountBtc.setText(userNotes.xmrtoAmount + " "+ userNotes.xmrtoCurrency);
switch (userNotes.xmrtoTag) { switch (userNotes.xmrtoTag) {
case "xmrto": case "xmrto":
tvXmrToSupport.setVisibility(View.GONE); tvXmrToSupport.setVisibility(View.GONE);

View File

@@ -921,7 +921,7 @@ public class WalletActivity extends BaseActivity implements WalletFragment.Liste
@Override @Override
public boolean onScanned(String qrCode) { public boolean onScanned(String qrCode) {
// #gurke // #gurke
BarcodeData bcData = BarcodeData.fromQrCode(qrCode); BarcodeData bcData = BarcodeData.fromString(qrCode);
if (bcData != null) { if (bcData != null) {
popFragmentStack(null); popFragmentStack(null);
Timber.d("AAA"); Timber.d("AAA");

View File

@@ -49,6 +49,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.Toolbar; import com.m2049r.xmrwallet.widget.Toolbar;
import java.text.NumberFormat; import java.text.NumberFormat;
@@ -242,7 +243,7 @@ public class WalletFragment extends Fragment
String balanceCurrency = Helper.BASE_CRYPTO; String balanceCurrency = Helper.BASE_CRYPTO;
double balanceRate = 1.0; double balanceRate = 1.0;
private final ExchangeApi exchangeApi = Helper.getExchangeApi(); private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi();
void refreshBalance() { void refreshBalance() {
double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue(); double unconfirmedXmr = Helper.getDecimalAmount(balance - unlockedBalance).doubleValue();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
package com.m2049r.xmrwallet.data;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.validator.BitcoinAddressType;
import com.m2049r.xmrwallet.util.validator.BitcoinAddressValidator;
import com.m2049r.xmrwallet.util.validator.EthAddressValidator;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public enum Crypto {
XMR("XMR", true, "monero:tx_amount:recipient_name:tx_description", R.id.ibXMR, R.drawable.ic_monero, R.drawable.ic_monero_bw, Wallet::isAddressValid),
BTC("BTC", true, "bitcoin:amount:label:message", R.id.ibBTC, R.drawable.ic_xmrto_btc, R.drawable.ic_xmrto_btc_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.BTC);
}),
DASH("DASH", true, "dash:amount:label:message", R.id.ibDASH, R.drawable.ic_xmrto_dash, R.drawable.ic_xmrto_dash_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DASH);
}),
DOGE("DOGE", true, "dogecoin:amount:label:message", R.id.ibDOGE, R.drawable.ic_xmrto_doge, R.drawable.ic_xmrto_doge_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.DOGE);
}),
ETH("ETH", false, "ethereum:amount:label:message", R.id.ibETH, R.drawable.ic_xmrto_eth, R.drawable.ic_xmrto_eth_off, EthAddressValidator::validate),
LTC("LTC", true, "litecoin:amount:label:message", R.id.ibLTC, R.drawable.ic_xmrto_ltc, R.drawable.ic_xmrto_ltc_off, address -> {
return BitcoinAddressValidator.validate(address, BitcoinAddressType.LTC);
});
@Getter
@NonNull
private final String symbol;
@Getter
private final boolean casefull;
@NonNull
private final String uriSpec;
@Getter
private final int buttonId;
@Getter
private final int iconEnabledId;
@Getter
private final int iconDisabledId;
@NonNull
private final Validator validator;
@Nullable
public static Crypto withScheme(@NonNull String scheme) {
for (Crypto crypto : values()) {
if (crypto.getUriScheme().equals(scheme)) return crypto;
}
return null;
}
@Nullable
public static Crypto withSymbol(@NonNull String symbol) {
final String upperSymbol = symbol.toUpperCase();
for (Crypto crypto : values()) {
if (crypto.symbol.equals(upperSymbol)) return crypto;
}
return null;
}
interface Validator {
boolean validate(String address);
}
// TODO maybe cache these segments
String getUriScheme() {
return uriSpec.split(":")[0];
}
String getUriAmount() {
return uriSpec.split(":")[1];
}
String getUriLabel() {
return uriSpec.split(":")[2];
}
String getUriMessage() {
return uriSpec.split(":")[3];
}
boolean validate(String address) {
return validator.validate(address);
}
}

View File

@@ -24,6 +24,9 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
public class TxDataBtc extends TxData { public class TxDataBtc extends TxData {
@Getter
@Setter
private String btcSymbol; // the actual non-XMR thing we're sending
@Getter @Getter
@Setter @Setter
private String xmrtoOrderId; // shown in success screen private String xmrtoOrderId; // shown in success screen
@@ -45,6 +48,7 @@ public class TxDataBtc extends TxData {
@Override @Override
public void writeToParcel(Parcel out, int flags) { public void writeToParcel(Parcel out, int flags) {
super.writeToParcel(out, flags); super.writeToParcel(out, flags);
out.writeString(btcSymbol);
out.writeString(xmrtoOrderId); out.writeString(xmrtoOrderId);
out.writeString(btcAddress); out.writeString(btcAddress);
out.writeDouble(btcAmount); out.writeDouble(btcAmount);
@@ -63,6 +67,7 @@ public class TxDataBtc extends TxData {
protected TxDataBtc(Parcel in) { protected TxDataBtc(Parcel in) {
super(in); super(in);
btcSymbol = in.readString();
xmrtoOrderId = in.readString(); xmrtoOrderId = in.readString();
btcAddress = in.readString(); btcAddress = in.readString();
btcAmount = in.readDouble(); btcAmount = in.readDouble();
@@ -74,10 +79,23 @@ public class TxDataBtc extends TxData {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("xmrtoOrderId:"); sb.append("xmrtoOrderId:");
sb.append(xmrtoOrderId); sb.append(xmrtoOrderId);
sb.append(",btcSymbol:");
sb.append(btcSymbol);
sb.append(",btcAddress:"); sb.append(",btcAddress:");
sb.append(btcAddress); sb.append(btcAddress);
sb.append(",btcAmount:"); sb.append(",btcAmount:");
sb.append(btcAmount); sb.append(btcAmount);
return sb.toString(); return sb.toString();
} }
public boolean validateAddress(@NonNull String address) {
if ((btcSymbol == null) || (btcAddress == null)) return false;
final Crypto crypto = Crypto.withSymbol(btcSymbol);
if (crypto == null) return false;
if (crypto.isCasefull()) { // compare as-is
return address.equals(btcAddress);
} else { // normalize & compare (e.g. ETH with and without checksum capitals
return address.toLowerCase().equals(btcAddress.toLowerCase());
}
}
} }

View File

@@ -28,6 +28,7 @@ public class UserNotes {
public String xmrtoTag = null; public String xmrtoTag = null;
public String xmrtoKey = null; public String xmrtoKey = null;
public String xmrtoAmount = null; // could be a double - but we are not doing any calculations public String xmrtoAmount = null; // could be a double - but we are not doing any calculations
public String xmrtoCurrency = null;
public String xmrtoDestination = null; public String xmrtoDestination = null;
public UserNotes(final String txNotes) { public UserNotes(final String txNotes) {
@@ -35,14 +36,15 @@ public class UserNotes {
return; return;
} }
this.txNotes = txNotes; this.txNotes = txNotes;
Pattern p = Pattern.compile("^\\{([a-z]+)-(\\w{6,}),([0-9.]*)BTC,(\\w*)\\} ?(.*)"); Pattern p = Pattern.compile("^\\{([a-z]+)-(\\w{6,}),([0-9.]*)([A-Z]+),(\\w*)\\} ?(.*)");
Matcher m = p.matcher(txNotes); Matcher m = p.matcher(txNotes);
if (m.find()) { if (m.find()) {
xmrtoTag = m.group(1); xmrtoTag = m.group(1);
xmrtoKey = m.group(2); xmrtoKey = m.group(2);
xmrtoAmount = m.group(3); xmrtoAmount = m.group(3);
xmrtoDestination = m.group(4); xmrtoCurrency = m.group(4);
note = m.group(5); xmrtoDestination = m.group(5);
note = m.group(6);
} else { } else {
note = txNotes; note = txNotes;
} }
@@ -62,6 +64,7 @@ public class UserNotes {
xmrtoTag = order.TAG; xmrtoTag = order.TAG;
xmrtoKey = order.getOrderId(); xmrtoKey = order.getOrderId();
xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount()); xmrtoAmount = Helper.getDisplayAmount(order.getBtcAmount());
xmrtoCurrency = order.getBtcCurrency();
xmrtoDestination = order.getBtcAddress(); xmrtoDestination = order.getBtcAddress();
} else { } else {
xmrtoTag = null; xmrtoTag = null;
@@ -83,7 +86,8 @@ public class UserNotes {
sb.append(xmrtoKey); sb.append(xmrtoKey);
sb.append(","); sb.append(",");
sb.append(xmrtoAmount); sb.append(xmrtoAmount);
sb.append("BTC,"); sb.append(xmrtoCurrency);
sb.append(",");
sb.append(xmrtoDestination); sb.append(xmrtoDestination);
sb.append("}"); sb.append("}");
if ((note != null) && (!note.isEmpty())) if ((note != null) && (!note.isEmpty()))

View File

@@ -42,9 +42,8 @@ public class SendAmountWizardFragment extends SendWizardFragment {
Listener sendListener; Listener sendListener;
public SendAmountWizardFragment setSendListener(Listener listener) { public void setSendListener(Listener listener) {
this.sendListener = listener; this.sendListener = listener;
return this;
} }
interface Listener { interface Listener {

View File

@@ -28,16 +28,16 @@ import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.data.TxDataBtc;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.widget.ExchangeOtherEditText;
import com.m2049r.xmrwallet.widget.SendProgressView;
import com.m2049r.xmrwallet.service.shift.ShiftError; import com.m2049r.xmrwallet.service.shift.ShiftError;
import com.m2049r.xmrwallet.service.shift.ShiftException; import com.m2049r.xmrwallet.service.shift.ShiftException;
import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters; import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.ExchangeOtherEditText;
import com.m2049r.xmrwallet.widget.SendProgressView;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Locale; import java.util.Locale;
@@ -85,6 +85,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
etAmount = view.findViewById(R.id.etAmount); etAmount = view.findViewById(R.id.etAmount);
etAmount.requestFocus(); etAmount.requestFocus();
return view; return view;
} }
@@ -130,20 +131,26 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
public void onResumeFragment() { public void onResumeFragment() {
super.onResumeFragment(); super.onResumeFragment();
Timber.d("onResumeFragment()"); Timber.d("onResumeFragment()");
final String btcSymbol = ((TxDataBtc) sendListener.getTxData()).getBtcSymbol();
if (!btcSymbol.toLowerCase().equals(ServiceHelper.ASSET))
throw new IllegalStateException("Asset Symbol is wrong!");
final long funds = getTotalFunds(); final long funds = getTotalFunds();
if (!sendListener.getActivityCallback().isStreetMode()) { if (!sendListener.getActivityCallback().isStreetMode()) {
tvFunds.setText(getString(R.string.send_available, tvFunds.setText(getString(R.string.send_available,
Wallet.getDisplayAmount(funds))); Wallet.getDisplayAmount(funds)));
//TODO
} else { } else {
tvFunds.setText(getString(R.string.send_available, tvFunds.setText(getString(R.string.send_available,
getString(R.string.unknown_amount))); getString(R.string.unknown_amount)));
} }
etAmount.setAmount("");
final BarcodeData data = sendListener.popBarcodeData(); final BarcodeData data = sendListener.popBarcodeData();
if (data != null) { if (data != null) {
if (data.amount != null) { if (data.amount != null) {
etAmount.setAmount(data.amount); etAmount.setAmount(data.amount);
} }
} }
etAmount.setBaseCurrency(btcSymbol);
callXmrTo(); callXmrTo();
} }
@@ -166,7 +173,9 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
String min = df.format(minBtc); String min = df.format(minBtc);
String max = df.format(maxBtc); String max = df.format(maxBtc);
String rate = df.format(price); String rate = df.format(price);
Spanned xmrParmText = Html.fromHtml(getString(R.string.info_send_xmrto_parms, min, max, rate)); final TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
Spanned xmrParmText = Html.fromHtml(getString(R.string.info_send_xmrto_parms,
min, max, rate, txDataBtc.getBtcSymbol()));
tvXmrToParms.setText(xmrParmText); tvXmrToParms.setText(xmrParmText);
final long funds = getTotalFunds(); final long funds = getTotalFunds();
@@ -183,7 +192,8 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
} }
tvFunds.setText(getString(R.string.send_available_btc, tvFunds.setText(getString(R.string.send_available_btc,
availXmrString, availXmrString,
availBtcString)); availBtcString,
((TxDataBtc) sendListener.getTxData()).getBtcSymbol()));
llXmrToParms.setVisibility(View.VISIBLE); llXmrToParms.setVisibility(View.VISIBLE);
evParams.hideProgress(); evParams.hideProgress();
}); });
@@ -246,7 +256,7 @@ public class SendBtcAmountWizardFragment extends SendWizardFragment {
synchronized (this) { synchronized (this) {
if (xmrToApi == null) { if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
Helper.getXmrToBaseUrl()); ServiceHelper.getXmrToBaseUrl());
} }
} }
} }

View File

@@ -29,16 +29,17 @@ import com.m2049r.xmrwallet.data.TxData;
import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.data.TxDataBtc;
import com.m2049r.xmrwallet.model.PendingTransaction; import com.m2049r.xmrwallet.model.PendingTransaction;
import com.m2049r.xmrwallet.model.Wallet; import com.m2049r.xmrwallet.model.Wallet;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.widget.SendProgressView;
import com.m2049r.xmrwallet.service.shift.ShiftError; import com.m2049r.xmrwallet.service.shift.ShiftError;
import com.m2049r.xmrwallet.service.shift.ShiftException; import com.m2049r.xmrwallet.service.shift.ShiftException;
import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder; import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder;
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote; import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import com.m2049r.xmrwallet.widget.SendProgressView;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Locale; import java.util.Locale;
@@ -67,6 +68,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
private TextView tvTxBtcAmount; private TextView tvTxBtcAmount;
private TextView tvTxBtcRate; private TextView tvTxBtcRate;
private TextView tvTxBtcAddress; private TextView tvTxBtcAddress;
private TextView tvTxBtcAddressLabel;
private TextView tvTxXmrToKey; private TextView tvTxXmrToKey;
private TextView tvTxFee; private TextView tvTxFee;
private TextView tvTxTotal; private TextView tvTxTotal;
@@ -84,6 +86,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
R.layout.fragment_send_btc_confirm, container, false); R.layout.fragment_send_btc_confirm, container, false);
tvTxBtcAddress = view.findViewById(R.id.tvTxBtcAddress); tvTxBtcAddress = view.findViewById(R.id.tvTxBtcAddress);
tvTxBtcAddressLabel = view.findViewById(R.id.tvTxBtcAddressLabel);
tvTxBtcAmount = view.findViewById(R.id.tvTxBtcAmount); tvTxBtcAmount = view.findViewById(R.id.tvTxBtcAmount);
tvTxBtcRate = view.findViewById(R.id.tvTxBtcRate); tvTxBtcRate = view.findViewById(R.id.tvTxBtcRate);
tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey); tvTxXmrToKey = view.findViewById(R.id.tvTxXmrToKey);
@@ -259,6 +262,8 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
if (sendListener.getMode() != SendFragment.Mode.BTC) { if (sendListener.getMode() != SendFragment.Mode.BTC) {
throw new IllegalStateException("Mode is not BTC!"); throw new IllegalStateException("Mode is not BTC!");
} }
if (!((TxDataBtc) sendListener.getTxData()).getBtcSymbol().toLowerCase().equals(ServiceHelper.ASSET))
throw new IllegalStateException("Asset Symbol is wrong!");
Helper.hideKeyboard(getActivity()); Helper.hideKeyboard(getActivity());
llStageA.setVisibility(View.INVISIBLE); llStageA.setVisibility(View.INVISIBLE);
evStageA.hideProgress(); evStageA.hideProgress();
@@ -392,9 +397,10 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
df.setMaximumFractionDigits(12); df.setMaximumFractionDigits(12);
final String btcAmount = df.format(xmrtoQuote.getBtcAmount()); final String btcAmount = df.format(xmrtoQuote.getBtcAmount());
final String xmrAmountTotal = df.format(xmrtoQuote.getXmrAmount()); final String xmrAmountTotal = df.format(xmrtoQuote.getXmrAmount());
tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount, btcAmount, xmrAmountTotal)); tvTxBtcAmount.setText(getString(R.string.text_send_btc_amount,
btcAmount, xmrAmountTotal, txDataBtc.getBtcSymbol()));
final String xmrPriceBtc = df.format(xmrtoQuote.getPrice()); final String xmrPriceBtc = df.format(xmrtoQuote.getPrice());
tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc)); tvTxBtcRate.setText(getString(R.string.text_send_btc_rate, xmrPriceBtc, txDataBtc.getBtcSymbol()));
hideProgress(); hideProgress();
}); });
stageB(requestQuote.getId()); stageB(requestQuote.getId());
@@ -477,13 +483,14 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData(); TxDataBtc txDataBtc = (TxDataBtc) sendListener.getTxData();
// verify amount & destination // verify amount & destination
if ((order.getBtcAmount() != txDataBtc.getBtcAmount()) if ((order.getBtcAmount() != txDataBtc.getBtcAmount())
|| (!order.getBtcAddress().equals(txDataBtc.getBtcAddress()))) { || (!txDataBtc.validateAddress(order.getBtcAddress()))) {
throw new IllegalStateException("Order does not fulfill quote!"); // something is terribly wrong - die throw new IllegalStateException("Order does not fulfill quote!"); // something is terribly wrong - die
} }
xmrtoOrder = order; xmrtoOrder = order;
getView().post(() -> { getView().post(() -> {
tvTxXmrToKey.setText(order.getOrderId()); tvTxXmrToKey.setText(order.getOrderId());
tvTxBtcAddress.setText(order.getBtcAddress()); tvTxBtcAddress.setText(order.getBtcAddress());
tvTxBtcAddressLabel.setText(getString(R.string.label_send_btc_address, txDataBtc.getBtcSymbol()));
hideProgress(); hideProgress();
Timber.d("Expires @ %s", order.getExpiresAt().toString()); Timber.d("Expires @ %s", order.getExpiresAt().toString());
final int timeout = (int) (order.getExpiresAt().getTime() - order.getCreatedAt().getTime()) / 1000 - 60; // -1 minute buffer final int timeout = (int) (order.getExpiresAt().getTime() - order.getCreatedAt().getTime()) / 1000 - 60; // -1 minute buffer
@@ -561,7 +568,7 @@ public class SendBtcConfirmWizardFragment extends SendWizardFragment implements
synchronized (this) { synchronized (this) {
if (xmrToApi == null) { if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
Helper.getXmrToBaseUrl()); ServiceHelper.getXmrToBaseUrl());
} }
} }
} }

View File

@@ -30,6 +30,7 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.data.PendingTx; import com.m2049r.xmrwallet.data.PendingTx;
import com.m2049r.xmrwallet.data.TxDataBtc; import com.m2049r.xmrwallet.data.TxDataBtc;
import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
@@ -39,6 +40,7 @@ import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl; import com.m2049r.xmrwallet.service.shift.sideshift.network.SideShiftApiImpl;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.OkHttpHelper; import com.m2049r.xmrwallet.util.OkHttpHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.Locale; import java.util.Locale;
@@ -62,10 +64,10 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
ImageButton bCopyTxId; ImageButton bCopyTxId;
private TextView tvTxId; private TextView tvTxId;
private TextView tvTxAddress; private TextView tvTxAddress;
private TextView tvTxPaymentId;
private TextView tvTxAmount; private TextView tvTxAmount;
private TextView tvTxFee; private TextView tvTxFee;
private TextView tvXmrToAmount; private TextView tvXmrToAmount;
private ImageView ivXmrToIcon;
private TextView tvXmrToStatus; private TextView tvXmrToStatus;
private ImageView ivXmrToStatus; private ImageView ivXmrToStatus;
private ImageView ivXmrToStatusBig; private ImageView ivXmrToStatusBig;
@@ -90,13 +92,13 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
}); });
tvXmrToAmount = view.findViewById(R.id.tvXmrToAmount); tvXmrToAmount = view.findViewById(R.id.tvXmrToAmount);
ivXmrToIcon = view.findViewById(R.id.ivXmrToIcon);
tvXmrToStatus = view.findViewById(R.id.tvXmrToStatus); tvXmrToStatus = view.findViewById(R.id.tvXmrToStatus);
ivXmrToStatus = view.findViewById(R.id.ivXmrToStatus); ivXmrToStatus = view.findViewById(R.id.ivXmrToStatus);
ivXmrToStatusBig = view.findViewById(R.id.ivXmrToStatusBig); ivXmrToStatusBig = view.findViewById(R.id.ivXmrToStatusBig);
tvTxId = view.findViewById(R.id.tvTxId); tvTxId = view.findViewById(R.id.tvTxId);
tvTxAddress = view.findViewById(R.id.tvTxAddress); tvTxAddress = view.findViewById(R.id.tvTxAddress);
tvTxPaymentId = view.findViewById(R.id.tvTxPaymentId);
tvTxAmount = view.findViewById(R.id.tvTxAmount); tvTxAmount = view.findViewById(R.id.tvTxAmount);
tvTxFee = view.findViewById(R.id.tvTxFee); tvTxFee = view.findViewById(R.id.tvTxFee);
@@ -150,9 +152,11 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
NumberFormat df = NumberFormat.getInstance(Locale.US); NumberFormat df = NumberFormat.getInstance(Locale.US);
df.setMaximumFractionDigits(12); df.setMaximumFractionDigits(12);
String btcAmount = df.format(btcData.getBtcAmount()); String btcAmount = df.format(btcData.getBtcAmount());
tvXmrToAmount.setText(getString(R.string.info_send_xmrto_success_btc, btcAmount)); tvXmrToAmount.setText(getString(R.string.info_send_xmrto_success_btc, btcAmount, btcData.getBtcSymbol()));
//TODO btcData.getBtcAddress(); //TODO btcData.getBtcAddress();
tvTxXmrToKey.setText(btcData.getXmrtoOrderId()); tvTxXmrToKey.setText(btcData.getXmrtoOrderId());
final Crypto crypto = Crypto.withSymbol(btcData.getBtcSymbol());
ivXmrToIcon.setImageResource(crypto.getIconEnabledId());
tvXmrToSupport.setOnClickListener(v -> { tvXmrToSupport.setOnClickListener(v -> {
Uri orderUri = getXmrToApi().getQueryOrderUri(btcData.getXmrtoOrderId()); Uri orderUri = getXmrToApi().getQueryOrderUri(btcData.getXmrtoOrderId());
Intent intent = new Intent(Intent.ACTION_VIEW, orderUri); Intent intent = new Intent(Intent.ACTION_VIEW, orderUri);
@@ -211,7 +215,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
statusResource = R.drawable.ic_error_red_24dp; statusResource = R.drawable.ic_error_red_24dp;
pbXmrto.getIndeterminateDrawable().setColorFilter(0xff8b0000, android.graphics.PorterDuff.Mode.MULTIPLY); pbXmrto.getIndeterminateDrawable().setColorFilter(0xff8b0000, android.graphics.PorterDuff.Mode.MULTIPLY);
} else if (status.isSent() || status.isPaid()) { } else if (status.isSent() || status.isPaid()) {
tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent)); tvXmrToStatus.setText(getString(R.string.info_send_xmrto_sent, btcData.getBtcSymbol()));
statusResource = R.drawable.ic_success_green_24dp; statusResource = R.drawable.ic_success_green_24dp;
pbXmrto.getIndeterminateDrawable().setColorFilter(0xFF417505, android.graphics.PorterDuff.Mode.MULTIPLY); pbXmrto.getIndeterminateDrawable().setColorFilter(0xFF417505, android.graphics.PorterDuff.Mode.MULTIPLY);
} else if (status.isWaiting()) { } else if (status.isWaiting()) {
@@ -228,6 +232,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
ivXmrToStatus.setImageResource(statusResource); ivXmrToStatus.setImageResource(statusResource);
if (status.isTerminal()) { if (status.isTerminal()) {
pbXmrto.setVisibility(View.INVISIBLE); pbXmrto.setVisibility(View.INVISIBLE);
ivXmrToIcon.setVisibility(View.GONE);
ivXmrToStatus.setVisibility(View.GONE); ivXmrToStatus.setVisibility(View.GONE);
ivXmrToStatusBig.setImageResource(statusResource); ivXmrToStatusBig.setImageResource(statusResource);
ivXmrToStatusBig.setVisibility(View.VISIBLE); ivXmrToStatusBig.setVisibility(View.VISIBLE);
@@ -241,7 +246,7 @@ public class SendBtcSuccessWizardFragment extends SendWizardFragment {
synchronized (this) { synchronized (this) {
if (xmrToApi == null) { if (xmrToApi == null) {
xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(), xmrToApi = new SideShiftApiImpl(OkHttpHelper.getOkHttpClient(),
Helper.getXmrToBaseUrl()); ServiceHelper.getXmrToBaseUrl());
} }
} }
} }

View File

@@ -29,6 +29,7 @@ import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
@@ -92,8 +93,6 @@ public class SendFragment extends Fragment
void setOnUriScannedListener(OnUriScannedListener onUriScannedListener); void setOnUriScannedListener(OnUriScannedListener onUriScannedListener);
} }
private EditText etDummy;
private View llNavBar; private View llNavBar;
private DotBar dotBar; private DotBar dotBar;
private Button bPrev; private Button bPrev;
@@ -101,7 +100,7 @@ public class SendFragment extends Fragment
private Button bDone; private Button bDone;
static private int MAX_FALLBACK = Integer.MAX_VALUE; static private final int MAX_FALLBACK = Integer.MAX_VALUE;
public static SendFragment newInstance(String uri) { public static SendFragment newInstance(String uri) {
SendFragment f = new SendFragment(); SendFragment f = new SendFragment();
@@ -166,28 +165,18 @@ public class SendFragment extends Fragment
} }
}); });
bPrev.setOnClickListener(new View.OnClickListener() { bPrev.setOnClickListener(v -> spendViewPager.previous());
public void onClick(View v) {
spendViewPager.previous();
}
});
bNext.setOnClickListener(new View.OnClickListener() { bNext.setOnClickListener(v -> spendViewPager.next());
public void onClick(View v) {
spendViewPager.next();
}
});
bDone.setOnClickListener(new View.OnClickListener() { bDone.setOnClickListener(v -> {
public void onClick(View v) { Timber.d("bDone.onClick");
Timber.d("bDone.onClick"); activityCallback.onFragmentDone();
activityCallback.onFragmentDone();
}
}); });
updatePosition(0); updatePosition(0);
etDummy = view.findViewById(R.id.etDummy); final EditText etDummy = view.findViewById(R.id.etDummy);
etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); etDummy.setRawInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
etDummy.requestFocus(); etDummy.requestFocus();
Helper.hideKeyboard(getActivity()); Helper.hideKeyboard(getActivity());
@@ -197,7 +186,7 @@ public class SendFragment extends Fragment
String uri = args.getString(WalletActivity.REQUEST_URI); String uri = args.getString(WalletActivity.REQUEST_URI);
Timber.d("URI: %s", uri); Timber.d("URI: %s", uri);
if (uri != null) { if (uri != null) {
barcodeData = BarcodeData.fromQrCode(uri); barcodeData = BarcodeData.fromString(uri);
Timber.d("barcodeData: %s", barcodeData != null ? barcodeData.toString() : "null"); Timber.d("barcodeData: %s", barcodeData != null ? barcodeData.toString() : "null");
} }
} }
@@ -236,7 +225,7 @@ public class SendFragment extends Fragment
} }
@Override @Override
public void onAttach(Context context) { public void onAttach(@NonNull Context context) {
Timber.d("onAttach %s", context); Timber.d("onAttach %s", context);
super.onAttach(context); super.onAttach(context);
if (context instanceof Listener) { if (context instanceof Listener) {
@@ -300,12 +289,7 @@ public class SendFragment extends Fragment
default: default:
throw new IllegalArgumentException("Mode " + String.valueOf(aMode) + " unknown!"); throw new IllegalArgumentException("Mode " + String.valueOf(aMode) + " unknown!");
} }
getView().post(new Runnable() { getView().post(() -> pagerAdapter.notifyDataSetChanged());
@Override
public void run() {
pagerAdapter.notifyDataSetChanged();
}
});
Timber.d("New Mode = %s", mode.toString()); Timber.d("New Mode = %s", mode.toString());
} }
} }
@@ -338,8 +322,9 @@ public class SendFragment extends Fragment
return numPages; return numPages;
} }
@NonNull
@Override @Override
public Object instantiateItem(ViewGroup container, int position) { public Object instantiateItem(@NonNull ViewGroup container, int position) {
Timber.d("instantiateItem %d", position); Timber.d("instantiateItem %d", position);
SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position); SendWizardFragment fragment = (SendWizardFragment) super.instantiateItem(container, position);
myFragments.put(position, new WeakReference<>(fragment)); myFragments.put(position, new WeakReference<>(fragment));
@@ -347,20 +332,21 @@ public class SendFragment extends Fragment
} }
@Override @Override
public void destroyItem(ViewGroup container, int position, Object object) { public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
Timber.d("destroyItem %d", position); Timber.d("destroyItem %d", position);
myFragments.remove(position); myFragments.remove(position);
super.destroyItem(container, position, object); super.destroyItem(container, position, object);
} }
public SendWizardFragment getFragment(int position) { public SendWizardFragment getFragment(int position) {
WeakReference ref = myFragments.get(position); WeakReference<SendWizardFragment> ref = myFragments.get(position);
if (ref != null) if (ref != null)
return myFragments.get(position).get(); return myFragments.get(position).get();
else else
return null; return null;
} }
@NonNull
@Override @Override
public SendWizardFragment getItem(int position) { public SendWizardFragment getItem(int position) {
Timber.d("getItem(%d) CREATE", position); Timber.d("getItem(%d) CREATE", position);
@@ -415,7 +401,7 @@ public class SendFragment extends Fragment
} }
@Override @Override
public int getItemPosition(Object object) { public int getItemPosition(@NonNull Object object) {
Timber.d("getItemPosition %s", String.valueOf(object)); Timber.d("getItemPosition %s", String.valueOf(object));
if (object instanceof SendAddressWizardFragment) { if (object instanceof SendAddressWizardFragment) {
// keep these pages // keep these pages

View File

@@ -17,18 +17,20 @@
package com.m2049r.xmrwallet.layout; package com.m2049r.xmrwallet.layout;
import android.content.Context; import android.content.Context;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.data.UserNotes;
import com.m2049r.xmrwallet.model.TransactionInfo; import com.m2049r.xmrwallet.model.TransactionInfo;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.data.UserNotes;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@@ -141,7 +143,13 @@ public class TransactionInfoAdapter extends RecyclerView.Adapter<TransactionInfo
UserNotes userNotes = new UserNotes(infoItem.notes); UserNotes userNotes = new UserNotes(infoItem.notes);
if (userNotes.xmrtoKey != null) { if (userNotes.xmrtoKey != null) {
ivTxType.setVisibility(View.VISIBLE); final Crypto crypto = Crypto.withSymbol(userNotes.xmrtoCurrency);
if (crypto != null) {
ivTxType.setImageResource(crypto.getIconEnabledId());
ivTxType.setVisibility(View.VISIBLE);
} else {// otherwirse pretend we don't know it's a shift
ivTxType.setVisibility(View.GONE);
}
} else { } else {
ivTxType.setVisibility(View.GONE); // gives us more space for the amount ivTxType.setVisibility(View.GONE); // gives us more space for the amount
} }

View File

@@ -21,6 +21,8 @@ import java.util.Date;
public interface CreateOrder { public interface CreateOrder {
String TAG = "side"; String TAG = "side";
String getBtcCurrency();
double getBtcAmount(); double getBtcAmount();
String getBtcAddress(); String getBtcAddress();

View File

@@ -23,8 +23,6 @@ import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
public interface SideShiftApi { public interface SideShiftApi {
String ASSET = "btc";
int QUERY_INTERVAL = 5000; // ms int QUERY_INTERVAL = 5000; // ms
/** /**

View File

@@ -25,6 +25,7 @@ import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder; import com.m2049r.xmrwallet.service.shift.sideshift.api.CreateOrder;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.util.DateHelper; import com.m2049r.xmrwallet.util.DateHelper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -35,6 +36,8 @@ import java.util.Date;
import lombok.Getter; import lombok.Getter;
class CreateOrderImpl implements CreateOrder { class CreateOrderImpl implements CreateOrder {
@Getter
private final String btcCurrency;
@Getter @Getter
private final double btcAmount; private final double btcAmount;
@Getter @Getter
@@ -56,9 +59,10 @@ class CreateOrderImpl implements CreateOrder {
// sanity checks // sanity checks
final String depositMethod = jsonObject.getString("depositMethodId"); final String depositMethod = jsonObject.getString("depositMethodId");
final String settleMethod = jsonObject.getString("settleMethodId"); final String settleMethod = jsonObject.getString("settleMethodId");
if (!"xmr".equals(depositMethod) || !SideShiftApi.ASSET.equals(settleMethod)) if (!"xmr".equals(depositMethod) || !ServiceHelper.ASSET.equals(settleMethod))
throw new IllegalStateException(); throw new IllegalStateException();
btcCurrency = settleMethod.toUpperCase();
btcAmount = jsonObject.getDouble("settleAmount"); btcAmount = jsonObject.getDouble("settleAmount");
JSONObject settleAddress = jsonObject.getJSONObject("settleAddress"); JSONObject settleAddress = jsonObject.getJSONObject("settleAddress");
btcAddress = settleAddress.getString("address"); btcAddress = settleAddress.getString("address");

View File

@@ -23,6 +23,7 @@ import com.m2049r.xmrwallet.service.shift.ShiftApiCall;
import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters; import com.m2049r.xmrwallet.service.shift.sideshift.api.QueryOrderParameters;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.util.ServiceHelper;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -53,7 +54,7 @@ class QueryOrderParametersImpl implements QueryOrderParameters {
public static void call(@NonNull final ShiftApiCall api, public static void call(@NonNull final ShiftApiCall api,
@NonNull final ShiftCallback<QueryOrderParameters> callback) { @NonNull final ShiftCallback<QueryOrderParameters> callback) {
api.call("pairs/xmr/" + SideShiftApi.ASSET, new NetworkCallback() { api.call("pairs/xmr/" + ServiceHelper.ASSET, new NetworkCallback() {
@Override @Override
public void onSuccess(JSONObject jsonObject) { public void onSuccess(JSONObject jsonObject) {
try { try {

View File

@@ -24,6 +24,7 @@ import com.m2049r.xmrwallet.util.DateHelper;
import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote; import com.m2049r.xmrwallet.service.shift.sideshift.api.RequestQuote;
import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi; import com.m2049r.xmrwallet.service.shift.sideshift.api.SideShiftApi;
import com.m2049r.xmrwallet.service.shift.ShiftCallback; import com.m2049r.xmrwallet.service.shift.ShiftCallback;
import com.m2049r.xmrwallet.util.ServiceHelper;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@@ -55,7 +56,7 @@ class RequestQuoteImpl implements RequestQuote {
// sanity checks // sanity checks
final String depositMethod = jsonObject.getString("depositMethod"); final String depositMethod = jsonObject.getString("depositMethod");
final String settleMethod = jsonObject.getString("settleMethod"); final String settleMethod = jsonObject.getString("settleMethod");
if (!"xmr".equals(depositMethod) || !SideShiftApi.ASSET.equals(settleMethod)) if (!"xmr".equals(depositMethod) || !ServiceHelper.ASSET.equals(settleMethod))
throw new IllegalStateException(); throw new IllegalStateException();
btcAmount = jsonObject.getDouble("settleAmount"); btcAmount = jsonObject.getDouble("settleAmount");
@@ -106,7 +107,7 @@ class RequestQuoteImpl implements RequestQuote {
static JSONObject createRequest(final double xmrAmount) throws JSONException { static JSONObject createRequest(final double xmrAmount) throws JSONException {
final JSONObject jsonObject = new JSONObject(); final JSONObject jsonObject = new JSONObject();
jsonObject.put("depositMethod", "xmr"); jsonObject.put("depositMethod", "xmr");
jsonObject.put("settleMethod", SideShiftApi.ASSET); jsonObject.put("settleMethod", ServiceHelper.ASSET);
// #sideshift is silly and likes numbers as strings // #sideshift is silly and likes numbers as strings
String amount = AmountFormatter.format(xmrAmount); String amount = AmountFormatter.format(xmrAmount);
jsonObject.put("depositAmount", amount); jsonObject.put("depositAmount", amount);

View File

@@ -323,15 +323,6 @@ public class Helper {
return ShakeAnimation; return ShakeAnimation;
} }
static public HttpUrl getXmrToBaseUrl() {
if ((WalletManager.getInstance() == null)
|| (WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet)) {
throw new IllegalStateException("Only mainnet not supported");
} else {
return HttpUrl.parse("https://sideshift.ai/api/v1/");
}
}
private final static char[] HexArray = "0123456789ABCDEF".toCharArray(); private final static char[] HexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] data) { public static String bytesToHex(byte[] data) {
@@ -639,10 +630,6 @@ public class Helper {
} }
} }
static public ExchangeApi getExchangeApi() {
return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl(OkHttpHelper.getOkHttpClient());
}
public interface Action { public interface Action {
boolean run(); boolean run();
} }

View File

@@ -21,6 +21,7 @@ package com.m2049r.xmrwallet.util;
import android.os.AsyncTask; import android.os.AsyncTask;
import com.m2049r.xmrwallet.data.BarcodeData; import com.m2049r.xmrwallet.data.BarcodeData;
import com.m2049r.xmrwallet.data.Crypto;
import org.jitsi.dnssec.validator.ValidatingResolver; import org.jitsi.dnssec.validator.ValidatingResolver;
import org.xbill.DNS.DClass; import org.xbill.DNS.DClass;
@@ -52,7 +53,6 @@ public class OpenAliasHelper {
public static final String OA1_NAME = "recipient_name"; public static final String OA1_NAME = "recipient_name";
public static final String OA1_DESCRIPTION = "tx_description"; public static final String OA1_DESCRIPTION = "tx_description";
public static final String OA1_AMOUNT = "tx_amount"; public static final String OA1_AMOUNT = "tx_amount";
public static final String OA1_PAYMENTID = "tx_payment_id";
public static final int DNS_LOOKUP_TIMEOUT = 2500; // ms public static final int DNS_LOOKUP_TIMEOUT = 2500; // ms
@@ -65,7 +65,7 @@ public class OpenAliasHelper {
} }
public interface OnResolvedListener { public interface OnResolvedListener {
void onResolved(Map<BarcodeData.Asset, BarcodeData> dataMap); void onResolved(Map<Crypto, BarcodeData> dataMap);
void onFailure(); void onFailure();
} }
@@ -138,7 +138,7 @@ public class OpenAliasHelper {
public void onPostExecute(Boolean success) { public void onPostExecute(Boolean success) {
if (resolvedListener != null) if (resolvedListener != null)
if (success) { if (success) {
Map<BarcodeData.Asset, BarcodeData> dataMap = new HashMap<>(); Map<Crypto, BarcodeData> dataMap = new HashMap<>();
for (String txt : txts) { for (String txt : txts) {
BarcodeData bc = BarcodeData.parseOpenAlias(txt, dnssec); BarcodeData bc = BarcodeData.parseOpenAlias(txt, dnssec);
if (bc != null) { if (bc != null) {

View File

@@ -0,0 +1,24 @@
package com.m2049r.xmrwallet.util;
import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import okhttp3.HttpUrl;
public class ServiceHelper {
public static String ASSET = null;
static public HttpUrl getXmrToBaseUrl() {
if ((WalletManager.getInstance() == null)
|| (WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet)) {
throw new IllegalStateException("Only mainnet not supported");
} else {
return HttpUrl.parse("https://sideshift.ai/api/v1/");
}
}
static public ExchangeApi getExchangeApi() {
return new com.m2049r.xmrwallet.service.exchange.krakenEcb.ExchangeApiImpl(OkHttpHelper.getOkHttpClient());
}
}

View File

@@ -0,0 +1,51 @@
package com.m2049r.xmrwallet.util.validator;
import lombok.Getter;
public enum BitcoinAddressType {
BTC(Type.BTC, Type.BTC_BECH32_PREFIX),
LTC(Type.LTC, Type.LTC_BECH32_PREFIX),
DASH(Type.DASH, null),
DOGE(Type.DOGE, null);
@Getter
private final byte[] production;
@Getter
private final byte[] testnet;
@Getter
private final String productionBech32Prefix;
@Getter
private final String testnetBech32Prefix;
public boolean hasBech32() {
return productionBech32Prefix != null;
}
public String getBech32Prefix(boolean testnet) {
return testnet ? testnetBech32Prefix : productionBech32Prefix;
}
BitcoinAddressType(byte[][] types, String[] bech32Prefix) {
production = types[0];
testnet = types[1];
if (bech32Prefix != null) {
productionBech32Prefix = bech32Prefix[0];
testnetBech32Prefix = bech32Prefix[1];
} else {
productionBech32Prefix = null;
testnetBech32Prefix = null;
}
}
// Java is silly and doesn't allow array initializers in the construction
private static class Type {
private static final byte[][] BTC = {{0x00, 0x05}, {0x6f, (byte) 0xc4}};
private static final String[] BTC_BECH32_PREFIX = {"bc", "tb"};
private static final byte[][] LTC = {{0x30, 0x05, 0x32}, {0x6f, (byte) 0xc4, 0x3a}};
private static final String[] LTC_BECH32_PREFIX = {"ltc", "tltc"};
private static final byte[][] DASH = {{0x4c, 0x10}, {(byte) 0x8c, 0x13}};
private static final byte[][] DOGE = {{0x1e, 0x16}, {0x71, (byte) 0xc4}};
}
}

View File

@@ -14,10 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package com.m2049r.xmrwallet.util; package com.m2049r.xmrwallet.util.validator;
// mostly based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java // mostly based on https://rosettacode.org/wiki/Bitcoin/address_validation#Java
import com.m2049r.xmrwallet.data.Crypto;
import com.m2049r.xmrwallet.model.NetworkType; import com.m2049r.xmrwallet.model.NetworkType;
import com.m2049r.xmrwallet.model.WalletManager; import com.m2049r.xmrwallet.model.WalletManager;
@@ -28,28 +29,47 @@ import java.security.NoSuchAlgorithmException;
import java.util.Arrays; import java.util.Arrays;
public class BitcoinAddressValidator { public class BitcoinAddressValidator {
private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; private static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
public static boolean validate(String addrress) { public static Crypto validate(String address) {
boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet; for (BitcoinAddressType type : BitcoinAddressType.values()) {
if (validate(addrress, testnet)) return true; if (validate(address, type))
return validateBech32Segwit(addrress, testnet); return Crypto.valueOf(type.name());
}
return null;
} }
public static boolean validate(String addrress, boolean testnet) { // just for tests
public static boolean validateBTC(String addrress, boolean testnet) {
return validate(addrress, BitcoinAddressType.BTC, testnet);
}
public static boolean validate(String addrress, BitcoinAddressType type, boolean testnet) {
if (validate(addrress, testnet ? type.getTestnet() : type.getProduction()))
return true;
if (type.hasBech32())
return validateBech32Segwit(addrress, type, testnet);
else
return false;
}
public static boolean validate(String addrress, BitcoinAddressType type) {
final boolean testnet = WalletManager.getInstance().getNetworkType() != NetworkType.NetworkType_Mainnet;
return validate(addrress, type, testnet);
}
public static boolean validate(String addrress, byte[] addressTypes) {
if (addrress.length() < 26 || addrress.length() > 35) if (addrress.length() < 26 || addrress.length() > 35)
return false; return false;
byte[] decoded = decodeBase58To25Bytes(addrress); byte[] decoded = decodeBase58To25Bytes(addrress);
if (decoded == null) if (decoded == null)
return false; return false;
int v = decoded[0] & 0xFF; int v = decoded[0] & 0xFF;
if (!testnet) { boolean nok = true;
if ((v != 0x00) && (v != 0x05)) return false; for (byte b : addressTypes) {
} else { nok = nok && (v != (b & 0xFF));
if ((v != 0x6f) && (v != 0xc4)) return false;
} }
if (nok) return false;
byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21)); byte[] hash1 = sha256(Arrays.copyOfRange(decoded, 0, 21));
byte[] hash2 = sha256(hash1); byte[] hash2 = sha256(hash1);
@@ -95,18 +115,20 @@ public class BitcoinAddressValidator {
private static final String DATA_CHARS = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"; private static final String DATA_CHARS = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
public static boolean validateBech32Segwit(String bech32, boolean testnet) { public static boolean validateBech32Segwit(String bech32, BitcoinAddressType type, boolean testnet) {
if (!bech32.equals(bech32.toLowerCase()) && !bech32.equals(bech32.toUpperCase())) { if (!bech32.equals(bech32.toLowerCase()) && !bech32.equals(bech32.toUpperCase())) {
return false; // mixing upper and lower case not allowed return false; // mixing upper and lower case not allowed
} }
bech32 = bech32.toLowerCase(); bech32 = bech32.toLowerCase();
if (testnet && !bech32.startsWith("tb1")) return false; if (!bech32.startsWith(type.getBech32Prefix(testnet))) return false;
if (!testnet && !bech32.startsWith("bc1")) return false;
if ((bech32.length() < 14) || (bech32.length() > 74)) return false; final int hrpLength = type.getBech32Prefix(testnet).length();
int mod = bech32.length() % 8;
if ((mod == 0) || (mod == 3) || (mod == 5)) return false; if ((bech32.length() < (12 + hrpLength)) || (bech32.length() > (72 + hrpLength)))
return false;
int mod = (bech32.length() - hrpLength) % 8;
if ((mod == 6) || (mod == 1) || (mod == 3)) return false;
int sep = -1; int sep = -1;
final byte[] bytes = bech32.getBytes(StandardCharsets.US_ASCII); final byte[] bytes = bech32.getBytes(StandardCharsets.US_ASCII);
@@ -117,7 +139,7 @@ public class BitcoinAddressValidator {
if (bytes[i] == 49) sep = i; // 49 := '1' in ASCII if (bytes[i] == 49) sep = i; // 49 := '1' in ASCII
} }
if (sep != 2) return false; // bech32 always has len(hrp)==2 if (sep != hrpLength) return false;
if (sep > bytes.length - 7) { if (sep > bytes.length - 7) {
return false; // min 6 bytes data return false; // min 6 bytes data
} }
@@ -158,12 +180,12 @@ public class BitcoinAddressValidator {
private static byte[] hrpExpand(byte[] hrp) { private static byte[] hrpExpand(byte[] hrp) {
final byte[] expanded = new byte[(2 * hrp.length) + 1]; final byte[] expanded = new byte[(2 * hrp.length) + 1];
int i = 0; int i = 0;
for (int j = 0; j < hrp.length; j++) { for (byte b : hrp) {
expanded[i++] = (byte) (hrp[j] >> 5); expanded[i++] = (byte) (b >> 5);
} }
expanded[i++] = 0; expanded[i++] = 0;
for (int j = 0; j < hrp.length; j++) { for (byte b : hrp) {
expanded[i++] = (byte) (hrp[j] & 0x1f); expanded[i++] = (byte) (b & 0x1f);
} }
return expanded; return expanded;
} }
@@ -195,4 +217,4 @@ public class BitcoinAddressValidator {
return true; return true;
} }
} }

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2017 m2049r er al.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.m2049r.xmrwallet.util.validator;
// mostly based on https://github.com/ognus/wallet-address-validator/blob/master/src/ethereum_validator.js
import com.theromus.sha.Keccak;
import com.theromus.sha.Parameters;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public class EthAddressValidator {
static private final Pattern ETH_ADDRESS = Pattern.compile("^0x[0-9a-fA-F]{40}$");
static private final Pattern ETH_ALLLOWER = Pattern.compile("^0x[0-9a-f]{40}$");
static private final Pattern ETH_ALLUPPER = Pattern.compile("^0x[0-9A-F]{40}$");
public static boolean validate(String address) {
// Check if it has the basic requirements of an address
if (!ETH_ADDRESS.matcher(address).matches())
return false;
// If it's all small caps or all all caps, return true
if (ETH_ALLLOWER.matcher(address).matches() || ETH_ALLUPPER.matcher(address).matches()) {
return true;
}
// Otherwise check each case
return validateChecksum(address);
}
private static boolean validateChecksum(String address) {
// Check each case
address = address.substring(2); // strip 0x
Keccak keccak = new Keccak();
final byte[] addressHash = keccak.getHash(
address.toLowerCase().getBytes(StandardCharsets.US_ASCII),
Parameters.KECCAK_256);
for (int i = 0; i < 40; i++) {
boolean upper = (addressHash[i / 2] & ((i % 2) == 0 ? 128 : 8)) != 0;
char c = address.charAt(i);
if (Character.isAlphabetic(c)) {
if (Character.isUpperCase(c) && !upper) return false;
if (Character.isLowerCase(c) && upper) return false;
}
}
return true;
}
}

View File

@@ -40,6 +40,7 @@ import com.m2049r.xmrwallet.service.exchange.api.ExchangeApi;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
import com.m2049r.xmrwallet.util.Helper; import com.m2049r.xmrwallet.util.Helper;
import com.m2049r.xmrwallet.util.ServiceHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@@ -184,6 +185,12 @@ public class ExchangeEditText extends LinearLayout {
private boolean isInitialized = false; private boolean isInitialized = false;
void postInitialize() {
setInitialSpinnerSelections(sCurrencyA, sCurrencyB);
isInitialized = true;
startExchange();
}
@Override @Override
protected void onFinishInflate() { protected void onFinishInflate() {
super.onFinishInflate(); super.onFinishInflate();
@@ -212,14 +219,7 @@ public class ExchangeEditText extends LinearLayout {
setCurrencyAdapter(sCurrencyA); setCurrencyAdapter(sCurrencyA);
setCurrencyAdapter(sCurrencyB); setCurrencyAdapter(sCurrencyB);
post(new Runnable() { post(this::postInitialize);
@Override
public void run() {
setInitialSpinnerSelections(sCurrencyA, sCurrencyB);
isInitialized = true;
startExchange();
}
});
// make progress circle gray // make progress circle gray
pbExchange.getIndeterminateDrawable(). pbExchange.getIndeterminateDrawable().
@@ -296,7 +296,7 @@ public class ExchangeEditText extends LinearLayout {
} }
} }
private final ExchangeApi exchangeApi = Helper.getExchangeApi(); private final ExchangeApi exchangeApi = ServiceHelper.getExchangeApi();
// starts exchange through exchange api // starts exchange through exchange api
void startExchange() { void startExchange() {

View File

@@ -25,6 +25,8 @@ import android.os.Looper;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.Spinner; import android.widget.Spinner;
import androidx.annotation.NonNull;
import com.m2049r.xmrwallet.R; import com.m2049r.xmrwallet.R;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback; import com.m2049r.xmrwallet.service.exchange.api.ExchangeCallback;
import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate; import com.m2049r.xmrwallet.service.exchange.api.ExchangeRate;
@@ -46,12 +48,15 @@ public class ExchangeOtherEditText extends ExchangeEditText {
public void setExchangeRate(double rate) { public void setExchangeRate(double rate) {
exchangeRate = rate; exchangeRate = rate;
post(new Runnable() { post(this::startExchange);
@Override }
public void run() {
startExchange(); public void setBaseCurrency(@NonNull String symbol) {
} if (symbol.equals(baseCurrency)) return;
}); baseCurrency = symbol;
setCurrencyAdapter(sCurrencyA);
setCurrencyAdapter(sCurrencyB);
post(this::postInitialize);
} }
private void setBaseCurrency(Context context, AttributeSet attrs) { private void setBaseCurrency(Context context, AttributeSet attrs) {
@@ -184,12 +189,7 @@ public class ExchangeOtherEditText extends ExchangeEditText {
@Override @Override
public void onError(final Exception e) { public void onError(final Exception e) {
Timber.e(e.getLocalizedMessage()); Timber.e(e.getLocalizedMessage());
new Handler(Looper.getMainLooper()).post(new Runnable() { new Handler(Looper.getMainLooper()).post(() -> exchangeFailed());
@Override
public void run() {
exchangeFailed();
}
});
} }
}); });
} }

Some files were not shown because too many files have changed in this diff Show More