Browse Source

support BTCPay

btcpay
ZhangJun 4 years ago
parent
commit
0ab2873301
  1. 5
      app/src/main/java/com/cobo/cold/ui/fragment/main/AssetFragment.java
  2. 42
      app/src/main/java/com/cobo/cold/ui/fragment/main/FeeAttackChecking.java
  3. 14
      app/src/main/java/com/cobo/cold/ui/fragment/main/PsbtSignedTxFragment.java
  4. 4
      app/src/main/java/com/cobo/cold/ui/fragment/main/QRCodeScanFragment.java
  5. 2
      app/src/main/java/com/cobo/cold/ui/fragment/main/TxConfirmFragment.java
  6. 28
      app/src/main/java/com/cobo/cold/ui/fragment/main/TxListFragment.java
  7. 9
      app/src/main/java/com/cobo/cold/ui/fragment/main/WalletInfoFragment.java
  8. 37
      app/src/main/java/com/cobo/cold/ui/fragment/main/electrum/ExportXpubGuideFragment.java
  9. 33
      app/src/main/java/com/cobo/cold/ui/fragment/setting/ChooseWatchWalletFragment.java
  10. 22
      app/src/main/java/com/cobo/cold/ui/fragment/setup/SetupWatchWalletFragment.java
  11. 9
      app/src/main/java/com/cobo/cold/viewmodel/ElectrumViewModel.java
  12. 4
      app/src/main/java/com/cobo/cold/viewmodel/PsbtViewModel.java
  13. 28
      app/src/main/java/com/cobo/cold/viewmodel/TxConfirmViewModel.java
  14. 60
      app/src/main/java/com/cobo/cold/viewmodel/WatchWallet.java
  15. 2
      app/src/main/res/layout/electrum_tx_detail.xml
  16. 38
      app/src/main/res/values-zh-rCN/strings.xml
  17. 36
      app/src/main/res/values/strings.xml

5
app/src/main/java/com/cobo/cold/ui/fragment/main/AssetFragment.java

@ -60,6 +60,7 @@ import java.util.stream.IntStream;
import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT; import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;
import static com.cobo.cold.ui.fragment.Constants.KEY_COIN_ID; import static com.cobo.cold.ui.fragment.Constants.KEY_COIN_ID;
import static com.cobo.cold.viewmodel.GlobalViewModel.getAddressType; import static com.cobo.cold.viewmodel.GlobalViewModel.getAddressType;
import static com.cobo.cold.viewmodel.WatchWallet.getWatchWallet;
public class AssetFragment extends BaseFragment<AssetFragmentBinding> public class AssetFragment extends BaseFragment<AssetFragmentBinding>
implements NumberPickerCallback { implements NumberPickerCallback {
@ -78,7 +79,7 @@ public class AssetFragment extends BaseFragment<AssetFragmentBinding>
@Override @Override
protected void init(View view) { protected void init(View view) {
coinId = Coins.BTC.coinId(); coinId = Coins.BTC.coinId();
watchWallet = WatchWallet.getWatchWallet(mActivity); watchWallet = getWatchWallet(mActivity);
mActivity.setSupportActionBar(mBinding.toolbar); mActivity.setSupportActionBar(mBinding.toolbar);
mBinding.toolbar.setNavigationOnClickListener(((MainActivity) mActivity)::toggleDrawer); mBinding.toolbar.setNavigationOnClickListener(((MainActivity) mActivity)::toggleDrawer);
String walletName = watchWallet.getWalletName(mActivity); String walletName = watchWallet.getWalletName(mActivity);
@ -195,6 +196,7 @@ public class AssetFragment extends BaseFragment<AssetFragmentBinding>
navigate(R.id.action_to_txnListFragment); navigate(R.id.action_to_txnListFragment);
break; break;
case WASABI: case WASABI:
case BTCPAY:
case GENERIC: case GENERIC:
navigate(R.id.action_to_psbtListFragment); navigate(R.id.action_to_psbtListFragment);
break; break;
@ -226,6 +228,7 @@ public class AssetFragment extends BaseFragment<AssetFragmentBinding>
case COBO: case COBO:
navigate(R.id.export_xpub_cobo); navigate(R.id.export_xpub_cobo);
break; break;
case BTCPAY:
case WASABI: case WASABI:
navigate(R.id.action_to_export_xpub_guide); navigate(R.id.action_to_export_xpub_guide);
break; break;

42
app/src/main/java/com/cobo/cold/ui/fragment/main/FeeAttackChecking.java

@ -1,24 +1,15 @@
package com.cobo.cold.ui.fragment.main; package com.cobo.cold.ui.fragment.main;
import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import androidx.databinding.DataBindingUtil; import androidx.databinding.DataBindingUtil;
import androidx.navigation.Navigation;
import com.cobo.cold.R; import com.cobo.cold.R;
import com.cobo.cold.databinding.CommonModalBinding; import com.cobo.cold.databinding.CommonModalBinding;
import com.cobo.cold.db.entity.TxEntity;
import com.cobo.cold.ui.fragment.BaseFragment; import com.cobo.cold.ui.fragment.BaseFragment;
import com.cobo.cold.ui.modal.ModalDialog; import com.cobo.cold.ui.modal.ModalDialog;
import java.util.Objects;
import static com.cobo.cold.ui.fragment.main.TxFragment.KEY_TX_ID;
import static com.cobo.cold.viewmodel.ElectrumViewModel.ELECTRUM_SIGN_ID;
import static com.cobo.cold.viewmodel.PsbtViewModel.WASABI_SIGN_ID;
public class FeeAttackChecking { public class FeeAttackChecking {
public static final String KEY_DUPLICATE_TX = "key_duplicate_tx"; public static final String KEY_DUPLICATE_TX = "key_duplicate_tx";
@ -47,37 +38,4 @@ public class FeeAttackChecking {
binding.confirm.setOnClickListener(v -> modalDialog.dismiss()); binding.confirm.setOnClickListener(v -> modalDialog.dismiss());
modalDialog.show(fragment.getHostActivity().getSupportFragmentManager(),""); modalDialog.show(fragment.getHostActivity().getSupportFragmentManager(),"");
} }
private void navigateToSignedTx(String txId, String signId) {
Bundle bundle = new Bundle();
bundle.putString(KEY_TX_ID, txId);
bundle.putBoolean(KEY_DUPLICATE_TX,true);
if (ELECTRUM_SIGN_ID.equals(signId)) {
Navigation.findNavController(Objects.requireNonNull(fragment.getView()))
.navigate(R.id.action_to_electrumTxFragment, bundle);
} else if(WASABI_SIGN_ID.equals(signId)){
Navigation.findNavController(Objects.requireNonNull(fragment.getView()))
.navigate(R.id.action_to_psbtSignedTxFragment, bundle);
} else {
Navigation.findNavController(Objects.requireNonNull(fragment.getView()))
.navigate(R.id.action_to_txFragment, bundle);
}
}
public void showDuplicateTx(TxEntity tx) {
ModalDialog modalDialog = ModalDialog.newInstance();
CommonModalBinding binding = DataBindingUtil.inflate(
LayoutInflater.from(fragment.getHostActivity()), R.layout.common_modal,
null, false);
modalDialog.setBinding(binding);
binding.title.setText(R.string.broadcast_tx);
binding.close.setVisibility(View.GONE);
binding.subTitle.setText(R.string.already_signed);
binding.confirm.setText(R.string.broadcast_tx);
binding.confirm.setOnClickListener(v -> {
modalDialog.dismiss();
navigateToSignedTx(tx.getTxId(), tx.getSignId());
});
modalDialog.show(fragment.getHostActivity().getSupportFragmentManager(),"");
}
} }

14
app/src/main/java/com/cobo/cold/ui/fragment/main/PsbtSignedTxFragment.java

@ -39,9 +39,10 @@ import static com.cobo.cold.ui.fragment.main.PsbtTxConfirmFragment.showExportPsb
public class PsbtSignedTxFragment extends SignedTxFragment { public class PsbtSignedTxFragment extends SignedTxFragment {
@Override @Override
protected void displaySignResult(TxEntity txEntity) { protected void displaySignResult(TxEntity txEntity) {
if (watchWallet == WatchWallet.WASABI) { if (watchWallet == WatchWallet.WASABI || watchWallet == WatchWallet.BTCPAY) {
mBinding.txDetail.qr.setVisibility(View.GONE); mBinding.txDetail.qr.setVisibility(View.GONE);
mBinding.txDetail.broadcastGuide.setVisibility(View.GONE); mBinding.txDetail.broadcastGuide.setGravity(Gravity.START);
mBinding.txDetail.broadcastGuide.setText(getBroadcastGuideText());
} else if (watchWallet == WatchWallet.BLUE || watchWallet == WatchWallet.GENERIC) { } else if (watchWallet == WatchWallet.BLUE || watchWallet == WatchWallet.GENERIC) {
if (watchWallet == WatchWallet.BLUE) { if (watchWallet == WatchWallet.BLUE) {
mBinding.txDetail.info.setOnClickListener(v -> showBlueWalletInfo()); mBinding.txDetail.info.setOnClickListener(v -> showBlueWalletInfo());
@ -75,6 +76,15 @@ public class PsbtSignedTxFragment extends SignedTxFragment {
} }
} }
private int getBroadcastGuideText() {
if (watchWallet == WatchWallet.WASABI) {
return R.string.wasabi_broadcast_guide;
} else if (watchWallet == WatchWallet.BTCPAY) {
return R.string.btcpay_broadcast_guide;
}
return 0;
}
private void showBlueWalletInfo() { private void showBlueWalletInfo() {
ModalDialog modalDialog = ModalDialog.newInstance(); ModalDialog modalDialog = ModalDialog.newInstance();
CommonModalBinding binding = DataBindingUtil.inflate( CommonModalBinding binding = DataBindingUtil.inflate(

4
app/src/main/java/com/cobo/cold/ui/fragment/main/QRCodeScanFragment.java

@ -104,7 +104,7 @@ public class QRCodeScanFragment extends BaseFragment<QrcodeScanFragmentBinding>
} }
} }
public String getScanhint() { private String getScanhint() {
switch (watchWallet){ switch (watchWallet){
case ELECTRUM: case ELECTRUM:
return getString(R.string.scan_electrum_hint); return getString(R.string.scan_electrum_hint);
@ -112,6 +112,8 @@ public class QRCodeScanFragment extends BaseFragment<QrcodeScanFragmentBinding>
return getString(R.string.scan_blue_hint); return getString(R.string.scan_blue_hint);
case WASABI: case WASABI:
return getString(R.string.scan_wasabi_hint); return getString(R.string.scan_wasabi_hint);
case BTCPAY:
return getString(R.string.btcpay_scan_hint);
} }
return ""; return "";

2
app/src/main/java/com/cobo/cold/ui/fragment/main/TxConfirmFragment.java

@ -60,7 +60,7 @@ import static com.cobo.cold.ui.fragment.main.BroadcastTxFragment.KEY_TXID;
import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.NORMAL; import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.NORMAL;
import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.SAME_OUTPUTS; import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.SAME_OUTPUTS;
public class TxConfirmFragment<T> extends BaseFragment<TxConfirmFragmentBinding> { public class TxConfirmFragment extends BaseFragment<TxConfirmFragmentBinding> {
public static final String KEY_TX_DATA = "tx_data"; public static final String KEY_TX_DATA = "tx_data";
private final Runnable forgetPassword = () -> { private final Runnable forgetPassword = () -> {

28
app/src/main/java/com/cobo/cold/ui/fragment/main/TxListFragment.java

@ -41,10 +41,8 @@ import java.util.stream.Collectors;
import static com.cobo.cold.ui.fragment.Constants.KEY_COIN_ID; import static com.cobo.cold.ui.fragment.Constants.KEY_COIN_ID;
import static com.cobo.cold.ui.fragment.main.TxFragment.KEY_TX_ID; import static com.cobo.cold.ui.fragment.main.TxFragment.KEY_TX_ID;
import static com.cobo.cold.viewmodel.ElectrumViewModel.ELECTRUM_SIGN_ID; import static com.cobo.cold.viewmodel.WatchWallet.ELECTRUM_SIGN_ID;
import static com.cobo.cold.viewmodel.PsbtViewModel.BLUE_WALLET_SIGN_ID; import static com.cobo.cold.viewmodel.WatchWallet.getWatchWallet;
import static com.cobo.cold.viewmodel.PsbtViewModel.GENERIC_WALLET_SIGN_ID;
import static com.cobo.cold.viewmodel.PsbtViewModel.WASABI_SIGN_ID;
public class TxListFragment extends BaseFragment<TxListBinding> { public class TxListFragment extends BaseFragment<TxListBinding> {
@ -69,9 +67,7 @@ public class TxListFragment extends BaseFragment<TxListBinding> {
txCallback = tx -> { txCallback = tx -> {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString(KEY_TX_ID, tx.getTxId()); bundle.putString(KEY_TX_ID, tx.getTxId());
if (WASABI_SIGN_ID.equals(tx.getSignId()) if (getWatchWallet(mActivity).supportPsbt()) {
|| BLUE_WALLET_SIGN_ID.equals(tx.getSignId())
|| GENERIC_WALLET_SIGN_ID.equals(tx.getSignId())) {
navigate(R.id.action_to_psbtSignedTxFragment, bundle); navigate(R.id.action_to_psbtSignedTxFragment, bundle);
} else if(ELECTRUM_SIGN_ID.equals(tx.getSignId())){ } else if(ELECTRUM_SIGN_ID.equals(tx.getSignId())){
navigate(R.id.action_to_electrumTxFragment, bundle); navigate(R.id.action_to_electrumTxFragment, bundle);
@ -132,20 +128,12 @@ public class TxListFragment extends BaseFragment<TxListBinding> {
} }
private boolean filterByMode(TxEntity txEntity) { private boolean filterByMode(TxEntity txEntity) {
WatchWallet watchWallet = WatchWallet.getWatchWallet(mActivity); WatchWallet watchWallet = getWatchWallet(mActivity);
switch (watchWallet) { if (watchWallet == WatchWallet.COBO) {
case COBO: return !txEntity.getSignId().endsWith("_sign_id");
return !txEntity.getSignId().endsWith("_sign_id"); } else {
case ELECTRUM: return watchWallet.getSignId().equals(txEntity.getSignId());
return ELECTRUM_SIGN_ID.equals(txEntity.getSignId());
case WASABI:
return WASABI_SIGN_ID.equals(txEntity.getSignId());
case BLUE:
return BLUE_WALLET_SIGN_ID.equals(txEntity.getSignId());
case GENERIC:
return GENERIC_WALLET_SIGN_ID.equals(txEntity.getSignId());
} }
return false;
} }
private boolean shouldShow(TxEntity tx) { private boolean shouldShow(TxEntity tx) {

9
app/src/main/java/com/cobo/cold/ui/fragment/main/WalletInfoFragment.java

@ -34,6 +34,7 @@ import com.cobo.cold.viewmodel.WalletInfoViewModel;
import static com.cobo.cold.ui.fragment.Constants.KEY_TITLE; import static com.cobo.cold.ui.fragment.Constants.KEY_TITLE;
import static com.cobo.cold.ui.fragment.setup.SelectAddressFormatFragment.KEY_NEED_CONFIRM; import static com.cobo.cold.ui.fragment.setup.SelectAddressFormatFragment.KEY_NEED_CONFIRM;
import static com.cobo.cold.viewmodel.WatchWallet.getWatchWallet;
public class WalletInfoFragment extends BaseFragment<WalletInfoBinding> { public class WalletInfoFragment extends BaseFragment<WalletInfoBinding> {
private Coins.Account account; private Coins.Account account;
@ -48,8 +49,8 @@ public class WalletInfoFragment extends BaseFragment<WalletInfoBinding> {
mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp()); mBinding.toolbar.setNavigationOnClickListener(v -> navigateUp());
mBinding.switchAddress.setOnClickListener(v -> switchAddressFormat()); mBinding.switchAddress.setOnClickListener(v -> switchAddressFormat());
account = GlobalViewModel.getAccount(mActivity); account = GlobalViewModel.getAccount(mActivity);
WatchWallet watchOnly = WatchWallet.getWatchWallet(mActivity); WatchWallet watchWallet = getWatchWallet(mActivity);
if (watchOnly != WatchWallet.GENERIC) { if (!watchWallet.supportSwitchAccount()) {
mBinding.switchAddress.setVisibility(View.GONE); mBinding.switchAddress.setVisibility(View.GONE);
} }
mBinding.addressFormat.setText(getAddressFormat()); mBinding.addressFormat.setText(getAddressFormat());
@ -67,9 +68,9 @@ public class WalletInfoFragment extends BaseFragment<WalletInfoBinding> {
viewModel.getXpub(account).observe(this, xpub -> { viewModel.getXpub(account).observe(this, xpub -> {
if (!TextUtils.isEmpty(xpub)) { if (!TextUtils.isEmpty(xpub)) {
if (watchOnly == WatchWallet.BLUE) { if (watchWallet == WatchWallet.BLUE) {
xpub = Util.convertXpubToZpub(xpub); xpub = Util.convertXpubToZpub(xpub);
} else if(watchOnly == WatchWallet.ELECTRUM) { } else if(watchWallet == WatchWallet.ELECTRUM) {
xpub = Util.convertXpubToYpub(xpub); xpub = Util.convertXpubToYpub(xpub);
} }
mBinding.xpub.setText(xpub); mBinding.xpub.setText(xpub);

37
app/src/main/java/com/cobo/cold/ui/fragment/main/electrum/ExportXpubGuideFragment.java

@ -43,8 +43,9 @@ import static com.cobo.cold.viewmodel.GlobalViewModel.writeToSdcard;
public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding> { public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding> {
private WatchWallet watchWallet; private WatchWallet watchWallet;
private JSONObject wasabiXpubJson; private JSONObject xpubJson;
private static final String WASABI_XPUB_FILENAME = "CoboVault-Wasabi.json"; private static final String WASABI_XPUB_FILENAME = "CoboVault-Wasabi.json";
private static final String BTCPAY_XPUB_FILENAME = "CoboVault-BTCPay.json";
@Override @Override
protected int setView() { protected int setView() {
return R.layout.export_xpub_guide; return R.layout.export_xpub_guide;
@ -66,7 +67,7 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
mBinding.text1.setText(getText1()); mBinding.text1.setText(getText1());
mBinding.text2.setText(getText2()); mBinding.text2.setText(getText2());
mBinding.export.setText(getButtonText()); mBinding.export.setText(getButtonText());
wasabiXpubJson = GlobalViewModel.getXpubInfo(mActivity); xpubJson = GlobalViewModel.getXpubInfo(mActivity);
} }
private void export() { private void export() {
@ -77,19 +78,17 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
case COBO: case COBO:
navigate(R.id.export_xpub_cobo); navigate(R.id.export_xpub_cobo);
break; break;
case BTCPAY:
case WASABI: case WASABI:
exportXpub(); exportXpub(watchWallet);
break; break;
case BLUE: case BLUE:
navigate(R.id.action_to_export_xpub_blue); navigate(R.id.action_to_export_xpub_blue);
break; break;
case GENERIC:
//navigate(R.id.export_electrum_ypub);
break;
} }
} }
public void exportXpub() { private void exportXpub(WatchWallet watchWallet) {
Storage storage = Storage.createByEnvironment(mActivity); Storage storage = Storage.createByEnvironment(mActivity);
if (storage == null || storage.getExternalDir() == null) { if (storage == null || storage.getExternalDir() == null) {
showNoSdcardModal(mActivity); showNoSdcardModal(mActivity);
@ -97,14 +96,16 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
ModalDialog modalDialog = ModalDialog.newInstance(); ModalDialog modalDialog = ModalDialog.newInstance();
ExportSdcardModalBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mActivity), ExportSdcardModalBinding binding = DataBindingUtil.inflate(LayoutInflater.from(mActivity),
R.layout.export_sdcard_modal, null, false); R.layout.export_sdcard_modal, null, false);
String fileName = getExportFileName(watchWallet);
binding.title.setText(R.string.export_xpub_text_file); binding.title.setText(R.string.export_xpub_text_file);
binding.fileName.setText(WASABI_XPUB_FILENAME); binding.fileName.setText(fileName);
binding.actionHint.setVisibility(View.GONE); binding.actionHint.setVisibility(View.GONE);
binding.cancel.setOnClickListener(vv -> modalDialog.dismiss()); binding.cancel.setOnClickListener(vv -> modalDialog.dismiss());
binding.confirm.setOnClickListener(vv -> { binding.confirm.setOnClickListener(vv -> {
modalDialog.dismiss(); modalDialog.dismiss();
if (writeToSdcard(storage, wasabiXpubJson.toString(), WASABI_XPUB_FILENAME)) { if (writeToSdcard(storage, xpubJson.toString(), fileName)) {
Runnable runnable = null; Runnable runnable;
if (mActivity instanceof SetupVaultActivity) { if (mActivity instanceof SetupVaultActivity) {
runnable = () -> navigate(R.id.action_to_setupCompleteFragment); runnable = () -> navigate(R.id.action_to_setupCompleteFragment);
} else { } else {
@ -118,10 +119,20 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
} }
} }
private String getExportFileName(WatchWallet watchWallet) {
if (watchWallet == WatchWallet.WASABI) {
return WASABI_XPUB_FILENAME;
} else if(watchWallet == WatchWallet.BTCPAY) {
return BTCPAY_XPUB_FILENAME;
}
return "";
}
private int getButtonText() { private int getButtonText() {
switch (watchWallet) { switch (watchWallet) {
case ELECTRUM: case ELECTRUM:
return R.string.show_master_public_key_qrcode; return R.string.show_master_public_key_qrcode;
case BTCPAY:
case WASABI: case WASABI:
return R.string.export_wallet; return R.string.export_wallet;
case COBO: case COBO:
@ -137,6 +148,8 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
return R.string.export_xpub_guide_title_electrum; return R.string.export_xpub_guide_title_electrum;
case WASABI: case WASABI:
return R.string.export_xpub_guide_title_wasabi; return R.string.export_xpub_guide_title_wasabi;
case BTCPAY:
return R.string.export_xpub_guide_title_btcpay;
case COBO: case COBO:
return R.string.export_xpub_guide_title_cobo; return R.string.export_xpub_guide_title_cobo;
case BLUE: case BLUE:
@ -149,6 +162,8 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
switch (watchWallet) { switch (watchWallet) {
case ELECTRUM: case ELECTRUM:
return R.string.export_xpub_guide_text1_electrum; return R.string.export_xpub_guide_text1_electrum;
case BTCPAY:
return R.string.export_xpub_guide_text1_btcpay;
case WASABI: case WASABI:
return R.string.export_xpub_guide_text1_wasabi; return R.string.export_xpub_guide_text1_wasabi;
case COBO: case COBO:
@ -165,6 +180,8 @@ public class ExportXpubGuideFragment extends BaseFragment<ExportXpubGuideBinding
return R.string.export_xpub_guide_text2_electrum; return R.string.export_xpub_guide_text2_electrum;
case WASABI: case WASABI:
return R.string.export_xpub_guide_text2_wasabi; return R.string.export_xpub_guide_text2_wasabi;
case BTCPAY:
return R.string.export_xpub_guide_text2_btcpay;
case COBO: case COBO:
return R.string.export_xpub_guide_text2_cobo; return R.string.export_xpub_guide_text2_cobo;
case BLUE: case BLUE:

33
app/src/main/java/com/cobo/cold/ui/fragment/setting/ChooseWatchWalletFragment.java

@ -64,21 +64,14 @@ public class ChooseWatchWalletFragment extends ListPreferenceFragment {
} }
private void next() { private void next() {
int navId = 0; int navId;
Bundle data = new Bundle(); Bundle data = new Bundle();
WatchWallet selectWatchOnlyWallet = getWatchWallet(mActivity); WatchWallet selectWatchOnlyWallet = getWatchWallet(mActivity);
switch (selectWatchOnlyWallet) { if (selectWatchOnlyWallet.supportSwitchAccount()) {
case GENERIC: data.putInt(KEY_TITLE, R.string.select_address_format);
data.putInt(KEY_TITLE, R.string.select_address_format); navId = R.id.action_to_selectAddressFormatFragment;
navId = R.id.action_to_selectAddressFormatFragment; } else {
break; navId = R.id.action_to_export_xpub_guide;
case COBO:
case WASABI:
case ELECTRUM:
case BLUE:
navId = R.id.action_to_export_xpub_guide;
break;
} }
navigate(navId, data); navigate(navId, data);
} }
@ -114,13 +107,13 @@ public class ChooseWatchWalletFragment extends ListPreferenceFragment {
} }
private void setWatchWallet() { private void setWatchWallet() {
prefs.edit().putString(SETTING_CHOOSE_WATCH_WALLET, value).apply(); if (prefs.edit().putString(SETTING_CHOOSE_WATCH_WALLET, value).commit()) {
if (value.equals(WatchWallet.COBO.getWalletId()) WatchWallet wallet = getWatchWallet(mActivity);
|| value.equals(WatchWallet.ELECTRUM.getWalletId())) { if (wallet.supportNativeSegwit()) {
prefs.edit().putString(SETTING_ADDRESS_FORMAT, Coins.Account.P2SH.getType()).apply(); prefs.edit().putString(SETTING_ADDRESS_FORMAT, Coins.Account.SegWit.getType()).apply();
} else if (value.equals(WatchWallet.WASABI.getWalletId()) } else if (wallet.supportNestedSegwit()) {
|| value.equals(WatchWallet.BLUE.getWalletId())) { prefs.edit().putString(SETTING_ADDRESS_FORMAT, Coins.Account.P2SH.getType()).apply();
prefs.edit().putString(SETTING_ADDRESS_FORMAT, Coins.Account.SegWit.getType()).apply(); }
} }
} }
} }

22
app/src/main/java/com/cobo/cold/ui/fragment/setup/SetupWatchWalletFragment.java

@ -17,15 +17,10 @@
package com.cobo.cold.ui.fragment.setup; package com.cobo.cold.ui.fragment.setup;
import android.os.Bundle;
import android.view.View; import android.view.View;
import com.cobo.cold.R; import com.cobo.cold.R;
import com.cobo.cold.databinding.SetupWatchWalletBinding; import com.cobo.cold.databinding.SetupWatchWalletBinding;
import com.cobo.cold.viewmodel.WatchWallet;
import static com.cobo.cold.ui.fragment.Constants.KEY_TITLE;
import static com.cobo.cold.viewmodel.WatchWallet.getWatchWallet;
public class SetupWatchWalletFragment extends SetupVaultBaseFragment<SetupWatchWalletBinding> { public class SetupWatchWalletFragment extends SetupVaultBaseFragment<SetupWatchWalletBinding> {
@ -37,21 +32,6 @@ public class SetupWatchWalletFragment extends SetupVaultBaseFragment<SetupWatchW
@Override @Override
protected void init(View view) { protected void init(View view) {
super.init(view); super.init(view);
mBinding.complete.setOnClickListener(v -> complete()); mBinding.complete.setOnClickListener(v -> navigate(R.id.action_to_export_xpub_guide));
}
private void complete() {
int navId = 0;
Bundle data = new Bundle();
WatchWallet selectWatchOnlyWallet = getWatchWallet(mActivity);
switch (selectWatchOnlyWallet) {
case ELECTRUM:
case COBO:
case WASABI:
case BLUE:
navId = R.id.action_to_export_xpub_guide;
break;
}
navigate(navId, data);
} }
} }

9
app/src/main/java/com/cobo/cold/viewmodel/ElectrumViewModel.java

@ -28,8 +28,6 @@ import com.cobo.coinlib.coins.BTC.Electrum.ElectrumTx;
import com.cobo.coinlib.coins.BTC.Electrum.TransactionInput; import com.cobo.coinlib.coins.BTC.Electrum.TransactionInput;
import com.cobo.coinlib.coins.BTC.Electrum.TransactionOutput; import com.cobo.coinlib.coins.BTC.Electrum.TransactionOutput;
import com.cobo.cold.AppExecutors; import com.cobo.cold.AppExecutors;
import com.cobo.cold.DataRepository;
import com.cobo.cold.MainApplication;
import com.cobo.cold.update.utils.FileUtils; import com.cobo.cold.update.utils.FileUtils;
import com.cobo.cold.update.utils.Storage; import com.cobo.cold.update.utils.Storage;
@ -46,20 +44,15 @@ import java.util.regex.Pattern;
public class ElectrumViewModel extends AndroidViewModel { public class ElectrumViewModel extends AndroidViewModel {
public static final String ELECTRUM_SIGN_ID = "electrum_sign_id";
private static Pattern signedTxnPattern = Pattern.compile("^signed_[0-9a-fA-F]{8}.txn$"); private static Pattern signedTxnPattern = Pattern.compile("^signed_[0-9a-fA-F]{8}.txn$");
private final DataRepository mRepo;
private MutableLiveData<String> exPub = new MutableLiveData<>();
private Storage storage; private Storage storage;
public ElectrumViewModel(@NonNull Application application) { public ElectrumViewModel(@NonNull Application application) {
super(application); super(application);
mRepo = MainApplication.getApplication().getRepository();
storage = Storage.createByEnvironment(application); storage = Storage.createByEnvironment(application);
} }
public static JSONObject adapt(ElectrumTx tx) throws JSONException { static JSONObject adapt(ElectrumTx tx) throws JSONException {
JSONObject object = new JSONObject(); JSONObject object = new JSONObject();
JSONArray inputs = new JSONArray(); JSONArray inputs = new JSONArray();
JSONArray outputs = new JSONArray(); JSONArray outputs = new JSONArray();

4
app/src/main/java/com/cobo/cold/viewmodel/PsbtViewModel.java

@ -45,10 +45,6 @@ import static com.cobo.cold.viewmodel.GlobalViewModel.getAccount;
public class PsbtViewModel extends AndroidViewModel { public class PsbtViewModel extends AndroidViewModel {
public static final String WASABI_SIGN_ID = "wasabi_sign_id";
public static final String BLUE_WALLET_SIGN_ID = "blue_wallet_sign_id";
public static final String GENERIC_WALLET_SIGN_ID = "generic_wallet_sign_id";
private static Pattern signedTxnPattern = Pattern.compile("^signed_[0-9a-fA-F]{8}.psbt$"); private static Pattern signedTxnPattern = Pattern.compile("^signed_[0-9a-fA-F]{8}.psbt$");
private Storage storage; private Storage storage;

28
app/src/main/java/com/cobo/cold/viewmodel/TxConfirmViewModel.java

@ -82,12 +82,9 @@ import static com.cobo.cold.viewmodel.AddAddressViewModel.AddAddressTask.getAddr
import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.DUPLICATE_TX; import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.DUPLICATE_TX;
import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.NORMAL; import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.NORMAL;
import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.SAME_OUTPUTS; import static com.cobo.cold.ui.fragment.main.FeeAttackChecking.FeeAttackCheckingResult.SAME_OUTPUTS;
import static com.cobo.cold.viewmodel.ElectrumViewModel.ELECTRUM_SIGN_ID;
import static com.cobo.cold.viewmodel.ElectrumViewModel.adapt; import static com.cobo.cold.viewmodel.ElectrumViewModel.adapt;
import static com.cobo.cold.viewmodel.GlobalViewModel.getAccount; import static com.cobo.cold.viewmodel.GlobalViewModel.getAccount;
import static com.cobo.cold.viewmodel.PsbtViewModel.BLUE_WALLET_SIGN_ID; import static com.cobo.cold.viewmodel.WatchWallet.ELECTRUM_SIGN_ID;
import static com.cobo.cold.viewmodel.PsbtViewModel.GENERIC_WALLET_SIGN_ID;
import static com.cobo.cold.viewmodel.PsbtViewModel.WASABI_SIGN_ID;
public class TxConfirmViewModel extends AndroidViewModel { public class TxConfirmViewModel extends AndroidViewModel {
@ -105,8 +102,6 @@ public class TxConfirmViewModel extends AndroidViewModel {
private String coinCode; private String coinCode;
private final MutableLiveData<String> signState = new MutableLiveData<>(); private final MutableLiveData<String> signState = new MutableLiveData<>();
private AuthenticateModal.OnVerify.VerifyToken token; private AuthenticateModal.OnVerify.VerifyToken token;
private TxEntity previousSignedTx;
public TxConfirmViewModel(@NonNull Application application) { public TxConfirmViewModel(@NonNull Application application) {
super(application); super(application);
@ -151,10 +146,6 @@ public class TxConfirmViewModel extends AndroidViewModel {
}); });
} }
public TxEntity getPreviousSignTx() {
return previousSignedTx;
}
private void feeAttackChecking(TxEntity txEntity) { private void feeAttackChecking(TxEntity txEntity) {
AppExecutors.getInstance().diskIO().execute(() -> { AppExecutors.getInstance().diskIO().execute(() -> {
String inputs = txEntity.getFrom(); String inputs = txEntity.getFrom();
@ -162,7 +153,6 @@ public class TxConfirmViewModel extends AndroidViewModel {
List<TxEntity> txs = mRepository.loadAllTxSync(Coins.BTC.coinId()); List<TxEntity> txs = mRepository.loadAllTxSync(Coins.BTC.coinId());
for (TxEntity tx : txs) { for (TxEntity tx : txs) {
if (inputs.equals(tx.getFrom()) && outputs.equals(tx.getTo())) { if (inputs.equals(tx.getFrom()) && outputs.equals(tx.getTo())) {
previousSignedTx = tx;
feeAttachCheckingResult.postValue(DUPLICATE_TX); feeAttachCheckingResult.postValue(DUPLICATE_TX);
break; break;
} else if (outputs.equals(tx.getTo())) { } else if (outputs.equals(tx.getTo())) {
@ -270,7 +260,7 @@ public class TxConfirmViewModel extends AndroidViewModel {
private JSONObject parsePsbtTx(JSONObject adaptTx) throws JSONException { private JSONObject parsePsbtTx(JSONObject adaptTx) throws JSONException {
TransactionProtoc.SignTransaction.Builder builder = TransactionProtoc.SignTransaction.newBuilder(); TransactionProtoc.SignTransaction.Builder builder = TransactionProtoc.SignTransaction.newBuilder();
builder.setCoinCode(Coins.BTC.coinCode()) builder.setCoinCode(Coins.BTC.coinCode())
.setSignId(getSignId()) .setSignId(WatchWallet.getWatchWallet(getApplication()).getSignId())
.setTimestamp(generateAutoIncreaseId()) .setTimestamp(generateAutoIncreaseId())
.setDecimal(8); .setDecimal(8);
String signTransaction = new JsonFormat().printToString(builder.build()); String signTransaction = new JsonFormat().printToString(builder.build());
@ -279,20 +269,6 @@ public class TxConfirmViewModel extends AndroidViewModel {
return signTx; return signTx;
} }
private String getSignId() {
switch (WatchWallet.getWatchWallet(getApplication())) {
case BLUE:
return BLUE_WALLET_SIGN_ID;
case WASABI:
return WASABI_SIGN_ID;
case GENERIC:
return GENERIC_WALLET_SIGN_ID;
case ELECTRUM:
return ELECTRUM_SIGN_ID;
}
return null;
}
private long generateAutoIncreaseId() { private long generateAutoIncreaseId() {
List<TxEntity> txEntityList = mRepository.loadElectrumTxsSync(Coins.BTC.coinId()); List<TxEntity> txEntityList = mRepository.loadElectrumTxsSync(Coins.BTC.coinId());
if (txEntityList == null || txEntityList.isEmpty()) { if (txEntityList == null || txEntityList.isEmpty()) {

60
app/src/main/java/com/cobo/cold/viewmodel/WatchWallet.java

@ -29,7 +29,14 @@ public enum WatchWallet {
ELECTRUM("1"), ELECTRUM("1"),
WASABI("2"), WASABI("2"),
BLUE("3"), BLUE("3"),
GENERIC("4"); BTCPAY("4"),
GENERIC("100");
public static final String ELECTRUM_SIGN_ID = "electrum_sign_id";
public static final String WASABI_SIGN_ID = "wasabi_sign_id";
public static final String BLUE_WALLET_SIGN_ID = "blue_wallet_sign_id";
public static final String BTCPAY_SIGN_ID = "blue_wallet_sign_id";
public static final String GENERIC_WALLET_SIGN_ID = "generic_wallet_sign_id";
private String walletId; private String walletId;
WatchWallet(String walletId) { WatchWallet(String walletId) {
@ -41,8 +48,12 @@ public enum WatchWallet {
} }
public String getWalletName(Context context) { public String getWalletName(Context context) {
return context.getResources() String[] wallets = context.getResources().getStringArray(R.array.watch_wallet_list);
.getStringArray(R.array.watch_wallet_list)[Integer.parseInt(walletId)]; if (walletId.equals(GENERIC.getWalletId())) {
return wallets[wallets.length - 1];
} else {
return wallets[Integer.parseInt(walletId)];
}
} }
public static WatchWallet getWatchWallet(Context context) { public static WatchWallet getWatchWallet(Context context) {
@ -62,6 +73,7 @@ public enum WatchWallet {
switch (this) { switch (this) {
case GENERIC: case GENERIC:
case BLUE: case BLUE:
case BTCPAY:
case WASABI: case WASABI:
return true; return true;
default:return false; default:return false;
@ -92,9 +104,51 @@ public enum WatchWallet {
switch (this) { switch (this) {
case ELECTRUM: case ELECTRUM:
case GENERIC: case GENERIC:
case BTCPAY:
case WASABI: case WASABI:
return true; return true;
default:return false; default:return false;
} }
} }
public String getSignId() {
switch (this) {
case BLUE:
return BLUE_WALLET_SIGN_ID;
case WASABI:
return WASABI_SIGN_ID;
case GENERIC:
return GENERIC_WALLET_SIGN_ID;
case ELECTRUM:
return ELECTRUM_SIGN_ID;
case BTCPAY:
return BTCPAY_SIGN_ID;
}
return "";
}
public boolean supportSwitchAccount() {
return this == WatchWallet.GENERIC;
}
public boolean supportNativeSegwit() {
switch (this) {
case GENERIC:
case BTCPAY:
case BLUE:
case WASABI:
return true;
}
return false;
}
public boolean supportNestedSegwit() {
switch (this) {
case COBO:
case ELECTRUM:
case GENERIC:
return true;
}
return false;
}
} }

2
app/src/main/res/layout/electrum_tx_detail.xml

@ -354,7 +354,7 @@
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:text="@string/export_signed_txn_file"/> android:text="@string/export_signed_txn_file"/>
<TextView <com.cobo.cold.ui.views.SpanedTextView
android:id="@+id/broadcast_guide" android:id="@+id/broadcast_guide"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

38
app/src/main/res/values-zh-rCN/strings.xml

@ -269,12 +269,12 @@
</string-array> </string-array>
<string name="export_to_electrum">在 Electrum 创建观察钱包</string> <string name="export_to_electrum">在 Electrum 创建观察钱包</string>
<string name="export_to_electrum_guide"><![CDATA[ <string name="export_to_electrum_guide"><![CDATA[
1. 打开 Electrum,新建钱包 <br> 1. 打开 Electrum,新建钱包 <br>
2. 选择“标准钱包” <br> 2. 选择“标准钱包” <br>
3. 选择“使用主公钥” <br> 3. 选择“使用主公钥” <br>
4. 在输入主公钥页面点击照相机按钮,扫描主公钥二维码(点击下方按钮查看二维码)<br> 4. 在输入主公钥页面点击照相机按钮,扫描主公钥二维码(点击下方按钮查看二维码)<br>
5. 设置钱包密码 <br> 5. 设置钱包密码 <br>
6. 进入观察钱包 6. 进入观察钱包
]]></string> ]]></string>
<string name="export_xpub">查看主公钥二维码</string> <string name="export_xpub">查看主公钥二维码</string>
<string name="export_to_electrum_guide_hint">Electrum 创建指引</string> <string name="export_to_electrum_guide_hint">Electrum 创建指引</string>
@ -338,11 +338,13 @@
<string name="change_address">找零地址</string> <string name="change_address">找零地址</string>
<string name="export_xpub_guide_title_electrum">导出到Electrum</string> <string name="export_xpub_guide_title_electrum">导出到Electrum</string>
<string name="export_xpub_guide_title_wasabi">导出到Wasabi Wallet</string> <string name="export_xpub_guide_title_wasabi">导出到Wasabi Wallet</string>
<string name="export_xpub_guide_title_btcpay">导出到BTCPay</string>
<string name="export_xpub_guide_title_cobo">导出到Cobo金库移动端</string> <string name="export_xpub_guide_title_cobo">导出到Cobo金库移动端</string>
<string name="export_xpub_guide_title_blue">导出到BlueWallet</string> <string name="export_xpub_guide_title_blue">导出到BlueWallet</string>
<string name="export_xpub_guide_text1_electrum">Electrum 导入指引:</string> <string name="export_xpub_guide_text1_electrum">Electrum 导入指引:</string>
<string name="export_xpub_guide_text1_cobo">Cobo 金库移动端导入指引:</string> <string name="export_xpub_guide_text1_cobo">Cobo 金库移动端导入指引:</string>
<string name="export_xpub_guide_text1_wasabi">Wasabi Wallet 导入指引:</string> <string name="export_xpub_guide_text1_wasabi">Wasabi Wallet 导入指引:</string>
<string name="export_xpub_guide_text1_btcpay">BTCPay Server 导入指引:</string>
<string name="export_xpub_guide_text1_blue">BlueWallet 导入指引:</string> <string name="export_xpub_guide_text1_blue">BlueWallet 导入指引:</string>
<string name="export_xpub_guide_text2_electrum"><![CDATA[ <string name="export_xpub_guide_text2_electrum"><![CDATA[
1. 打开 Electrum,新建钱包 <br> 1. 打开 Electrum,新建钱包 <br>
@ -371,6 +373,15 @@
<font color="#808080">请确保 Cobo 金库装有TF卡后再进行导出(仅支持FAT32格式,容量不能超过32G)<font/> <font color="#808080">请确保 Cobo 金库装有TF卡后再进行导出(仅支持FAT32格式,容量不能超过32G)<font/>
]]></string> ]]></string>
<string name="export_xpub_guide_text2_btcpay"><![CDATA[
1. 打开 BTCPay Server,前往【Store 设置--General--Derivation Scheme--Import from…】<br>
2. 选择“…a wallet file (Electrum, wasabi, Cobo Vault, ColdCard)”<br>
3. 打开 Cobo 金库导出的钱包文件(点击下方按钮导出)<br>
4. 点击<font color="#00cdc3">“Submit”<font/><br>
5. 点击<font color="#00cdc3">“Confirm”<font/><br><br>
<font color="#808080">请确保 Cobo 金库装有TF卡后再进行导出(仅支持FAT32格式,容量不能超过32G)<font/>
]]></string>
<string name="export_xpub_guide_text2_blue"><![CDATA[ <string name="export_xpub_guide_text2_blue"><![CDATA[
1. 打开 BlueWallet,添加新钱包<br> 1. 打开 BlueWallet,添加新钱包<br>
2. 选择“导入钱包”<br> 2. 选择“导入钱包”<br>
@ -400,6 +411,19 @@
3. 扫描 Cobo 金库二维码<br> 3. 扫描 Cobo 金库二维码<br>
]]></string> ]]></string>
<string name="wasabi_broadcast_guide"><![CDATA[
导出后,用Wasabi进行广播<br>
前往【wasabi--Tools--Transactions Broadcaster--Import transaction】,打开该文件
]]></string>
<string name="btcpay_broadcast_guide"><![CDATA[
导出后,用 BTCPay Server 进行广播<br>
1. 前往【BTCPay--PSBT】,打开该文件<br>
2. 点击“Decode”<br>
3. 点击“Other Actions” 选择“Review”<br>
4. 检查交易无误后点击“Broadcast”<br>
]]></string>
<string name="show_master_public_key_qrcode">查看主公钥二维码</string> <string name="show_master_public_key_qrcode">查看主公钥二维码</string>
<string name="show_qrcode">查看二维码</string> <string name="show_qrcode">查看二维码</string>
<string name="export_wallet">导出钱包</string> <string name="export_wallet">导出钱包</string>
@ -432,6 +456,7 @@
<item>Electrum</item> <item>Electrum</item>
<item>Wasabi Wallet</item> <item>Wasabi Wallet</item>
<item>BlueWallet</item> <item>BlueWallet</item>
<item>BTCPay Server</item>
<item>通用钱包</item> <item>通用钱包</item>
</string-array> </string-array>
@ -457,5 +482,6 @@
<string name="reboot_hint">请重新启动机器,多次重试未果请联系客服:support@cobo.com\n 状态码:%s</string> <string name="reboot_hint">请重新启动机器,多次重试未果请联系客服:support@cobo.com\n 状态码:%s</string>
<string name="reboot">重新启动</string> <string name="reboot">重新启动</string>
<string name="clear_and_power_off">删除所有信息并关机</string> <string name="clear_and_power_off">删除所有信息并关机</string>
<string name="btcpay_scan_hint">BTCPay Server 暂不支持将交易导成二维码,您可将待签交易导出成文件</string>
</resources> </resources>

36
app/src/main/res/values/strings.xml

@ -84,6 +84,7 @@
<item>Electrum</item> <item>Electrum</item>
<item>Wasabi Wallet</item> <item>Wasabi Wallet</item>
<item>BlueWallet</item> <item>BlueWallet</item>
<item>BTCPay Server</item>
<item>Generic Wallet</item> <item>Generic Wallet</item>
</string-array> </string-array>
@ -93,6 +94,7 @@
<item>2</item> <item>2</item>
<item>3</item> <item>3</item>
<item>4</item> <item>4</item>
<item>100</item>
</string-array> </string-array>
@ -324,8 +326,11 @@
</string-array> </string-array>
<string name="export_to_electrum">Create Watch-Only Wallet in Electrum</string> <string name="export_to_electrum">Create Watch-Only Wallet in Electrum</string>
<string name="export_to_electrum_guide"><![CDATA[ <string name="export_to_electrum_guide"><![CDATA[
1. Open Electrum and create a new wallet. <br>2. Choose “Standard wallet”. <br>3. Choose “Use a master key”. <br>4. Touch “Show Master Public Key” below then click the camera icon in the “Create keystore from a master key” window in Electrum to scan the QR code that displays on Cobo Vault. 1. Open Electrum and create a new wallet. <br>
<br>5. Set a password. <br>6. Enter the watch-only wallet. 2. Choose “Standard wallet”. <br>
3. Choose “Use a master key”. <br>
4. Touch “Show Master Public Key” below then click the camera icon in the “Create keystore from a master key” window in Electrum to scan the QR code that displays on Cobo Vault.<br>
5. Set a password. <br>6. Enter the watch-only wallet.
]]></string> ]]></string>
<string name="export_xpub">Show Master Public Key</string> <string name="export_xpub">Show Master Public Key</string>
<string name="export_to_electrum_guide_hint">How to create a watch-only wallet with Electrum:</string> <string name="export_to_electrum_guide_hint">How to create a watch-only wallet with Electrum:</string>
@ -389,11 +394,13 @@
<string name="change_address">Change Address</string> <string name="change_address">Change Address</string>
<string name="export_xpub_guide_title_electrum">Export to Electrum Watch-Only</string> <string name="export_xpub_guide_title_electrum">Export to Electrum Watch-Only</string>
<string name="export_xpub_guide_title_wasabi">Export to Wasabi Watch-Only</string> <string name="export_xpub_guide_title_wasabi">Export to Wasabi Watch-Only</string>
<string name="export_xpub_guide_title_btcpay">Export to BTCPay Watch-Only</string>
<string name="export_xpub_guide_title_cobo">Export to Cobo Vault Watch-Only</string> <string name="export_xpub_guide_title_cobo">Export to Cobo Vault Watch-Only</string>
<string name="export_xpub_guide_title_blue">Export to BlueWallet Watch-Only</string> <string name="export_xpub_guide_title_blue">Export to BlueWallet Watch-Only</string>
<string name="export_xpub_guide_text1_electrum">How to create a watch-only wallet with Electrum:</string> <string name="export_xpub_guide_text1_electrum">How to create a watch-only wallet with Electrum:</string>
<string name="export_xpub_guide_text1_cobo">How to create a watch-only wallet with the Cobo Vault mobile app:</string> <string name="export_xpub_guide_text1_cobo">How to create a watch-only wallet with the Cobo Vault mobile app:</string>
<string name="export_xpub_guide_text1_wasabi">How to create a watch-only wallet with Wasabi Wallet:</string> <string name="export_xpub_guide_text1_wasabi">How to create a watch-only wallet with Wasabi Wallet:</string>
<string name="export_xpub_guide_text1_btcpay">How to create a watch-only wallet with BTCPay Server:</string>
<string name="export_xpub_guide_text1_blue">How to create a watch-only wallet with BlueWallet:</string> <string name="export_xpub_guide_text1_blue">How to create a watch-only wallet with BlueWallet:</string>
<string name="export_xpub_guide_text2_electrum"><![CDATA[ <string name="export_xpub_guide_text2_electrum"><![CDATA[
1. Open Electrum and create a new wallet. <br> 1. Open Electrum and create a new wallet. <br>
@ -424,6 +431,15 @@
<font color="#808080">Please make sure you have inserted a FAT32 format microSD card with capacity 32GB or less before exporting.<br> <font color="#808080">Please make sure you have inserted a FAT32 format microSD card with capacity 32GB or less before exporting.<br>
Wasabi requires the xPub, hardware wallet fingerprint, and firmware version to be used as a watch-only wallet. This information will be exported if you touch “Export with MicroSD” below.<font/> Wasabi requires the xPub, hardware wallet fingerprint, and firmware version to be used as a watch-only wallet. This information will be exported if you touch “Export with MicroSD” below.<font/>
]]></string> ]]></string>
<string name="export_xpub_guide_text2_btcpay"><![CDATA[
1. In BTCPay Server, Store Settings > General > Derivation Scheme > Import from… <br>
2. Choose "…a wallet file (Electrum, wasabi, Cobo Vault, ColdCard)"<br>
3. Touch <font color="#00cdc3">"Export Wallet"<font/> below then open the file in BTCPay<br>
4. Click <font color="#00cdc3">"Submit"<font/><br>
5. Click <font color="#00cdc3">"Confirm"<font/>.<br>
<font color="#808080">Please make sure you have inserted a FAT32 format microSD card with capacity 32GB or less before exporting.<br>
Wasabi requires the xPub, hardware wallet fingerprint, and firmware version to be used as a watch-only wallet. This information will be exported if you touch “Export with MicroSD” below.<font/>
]]></string>
<string name="export_xpub_guide_text2_blue"><![CDATA[ <string name="export_xpub_guide_text2_blue"><![CDATA[
1. Open BlueWallet and add a new wallet.<br> 1. Open BlueWallet and add a new wallet.<br>
@ -455,6 +471,18 @@
6. Enter the watch-only wallet. 6. Enter the watch-only wallet.
]]></string> ]]></string>
<string name="wasabi_broadcast_guide"><![CDATA[
Broadcast with Wasabi<br>
go to [wasabi--Tools--Transactions Broadcaster--Import transaction] open this file to broadcast
]]></string>
<string name="btcpay_broadcast_guide"><![CDATA[
导出后,用 BTCPay Server 进行广播<br>
1. In BTCPay, go to PSBT tab of the wallet and upload the signed PSBT file<br>
2. Click "Decode"<br>
3. Click "Other Actions" and select "Review"<br>
4. Review your transactions and click "Broadcast" to broadcast it on the network
]]></string>
<string name="show_master_public_key_qrcode">Display Master Public Key QR Code</string> <string name="show_master_public_key_qrcode">Display Master Public Key QR Code</string>
<string name="show_qrcode">Display QR Code</string> <string name="show_qrcode">Display QR Code</string>
<string name="export_wallet">Export Wallet</string> <string name="export_wallet">Export Wallet</string>
@ -474,8 +502,7 @@
<string name="script_type">Script Type:</string> <string name="script_type">Script Type:</string>
<string name="address_path">Account Key Path:</string> <string name="address_path">Account Key Path:</string>
<string name="xpub">Account Extended Public Key:</string> <string name="xpub">Account Extended Public Key:</string>
<string name="wallet_info_hint">* Do not share this public key with anyone. Account extended public keys can be used to identify your addresses and cryptocurrency amounts. <string name="wallet_info_hint">* Do not share this public key with anyone. Account extended public keys can be used to identify your addresses and cryptocurrency amounts.</string>
</string>
<string name="confirm_add_address">Confirm</string> <string name="confirm_add_address">Confirm</string>
<string name="watch_wallet_not_match">Please use %s generate unsigned transaction</string> <string name="watch_wallet_not_match">Please use %s generate unsigned transaction</string>
<string name="scan_qrcode_with_generic_wallet">Please scan the QR code with the wallet you wish to use as a watch-only wallet.</string> <string name="scan_qrcode_with_generic_wallet">Please scan the QR code with the wallet you wish to use as a watch-only wallet.</string>
@ -496,5 +523,6 @@
<string name="reboot_hint">Please restart or contact us at support@cobo.com\n Status Code:%s</string> <string name="reboot_hint">Please restart or contact us at support@cobo.com\n Status Code:%s</string>
<string name="reboot">Restart</string> <string name="reboot">Restart</string>
<string name="clear_and_power_off">Erase all Information and Power off</string> <string name="clear_and_power_off">Erase all Information and Power off</string>
<string name="btcpay_scan_hint">BTCPay Server does not support exporting transactions by QR code. Please export transactions using microSD.</string>
</resources> </resources>

Loading…
Cancel
Save