diff --git a/loc/sl_SI.json b/loc/sl_SI.json
index 9c9b3de32..528f7590d 100644
--- a/loc/sl_SI.json
+++ b/loc/sl_SI.json
@@ -12,6 +12,9 @@
"dont_allow": "Ne dovoli",
"yes": "Da",
"no": "Ne",
+ "save": "Shrani",
+ "seed": "Seme",
+ "wallet_key": "Ključ denarnice",
"invalid_animated_qr_code_fragment" : "Neveljaven del animirane QR kode, prosimo poskusite ponovno",
"file_saved": "Datoteka ({filePath}) je bila shranjena v mapo Prenosi."
},
@@ -317,7 +320,7 @@
"transactions_count": "število transakcij"
},
"wallets": {
- "add_bitcoin_explain": "Simple and powerful Bitcoin wallet",
+ "add_bitcoin_explain": "Preprosta in zmogljiva Bitcoin denarnica",
"add_bitcoin": "Bitcoin",
"add_create": "Ustvari",
"add_entropy_generated": "{gen} bajtov ustvarjene entropije",
@@ -326,7 +329,7 @@
"add_import_wallet": "Uvozi denarnico",
"import_file": "Uvozi datoteko",
"add_lightning": "Lightning",
- "add_lightning_explain": "For spending with instant transactions",
+ "add_lightning_explain": "Za hitre vsakodnevne transakcije",
"add_lndhub": "Povežite se s svojim LNDHub-om",
"add_lndhub_error": "Podan naslov vozlišča ni veljavno vozlišče LNDHub.",
"add_lndhub_placeholder": "naslov vašega vozlišča",
@@ -391,10 +394,11 @@
"xpub_title": "XPUB denarnice"
},
"multisig": {
- "multisig_vault": "Vault",
- "multisig_vault_explain": "Best security for large amounts",
+ "multisig_vault": "Trezor",
+ "multisig_vault_explain": "Največja varnost za višje zneske",
"provide_signature": "Vnesite podpis",
"vault_key": "Ključ trezorja {number}",
+ "required_keys_out_of_total": "Zahtevani ključi od vseh",
"fee": "Omrežnina: {number}",
"fee_btc": "{number} BTC",
"confirm": "Potrditev",
@@ -404,6 +408,41 @@
"scan_or_import_file": "Skenirajte ali uvozite datoteko",
"export_coordination_setup": "izvoz koordinacijskih nastavitev",
"cosign_this_transaction": "Sopodpis te transakcije?",
- "co_sign_transaction": "Sopodpis QR-airgapped transakcije"
+ "lets_start": "Začnimo",
+ "create": "Ustvari",
+ "provide_key": "Vnesite ključ",
+ "native_segwit_title": "Najb. praksa",
+ "wrapped_segwit_title": "Najb. združljivost",
+ "legacy_title": "Zastarelo",
+ "co_sign_transaction": "Sopodpis QR-airgapped transakcije",
+ "what_is_vault": "Trezor je",
+ "what_is_vault_numberOfWallets": " {m}-od-{n} multisig ",
+ "what_is_vault_wallet": "denarnica",
+ "vault_advanced_customize": "Nastavitve trezorja...",
+ "needs": "Zahtevana sta",
+ "what_is_vault_description_number_of_vault_keys": " {m} ključa trezorja, ",
+ "what_is_vault_description_to_spend": "tretji pa\npredstavlja rezervo.",
+ "quorum": "{m} od {n} kvorum",
+ "quorum_header": "Kvorum",
+ "of": "od",
+ "wallet_type": "Tip denarnice",
+ "view_key": "prikaži",
+ "invalid_mnemonics": "Zdi se, da to mnemonično seme ni veljavno",
+ "invalid_cosigner": "Neveljavni podatki sopodpisnika",
+ "invalid_cosigner_format": "Nepravilen sopodpisnik: to ni sopodpisnik za {format} obliko",
+ "create_new_key": "Ustvari novega",
+ "scan_or_open_file": "Skenirajte ali odprite datoteko",
+ "i_have_mnemonics": "Za ta ključ imam seme...",
+ "please_write_down_mnemonics": "Prosimo, zapišite si seznam besed (mnemonično seme) na list papirja. Lahko si zapišete tudi pozneje.",
+ "i_wrote_it_down": "V redu, sem si zapisal",
+ "type_your_mnemonics": "Vnesite seme za uvoz obstoječega ključa trezorja",
+ "this_is_cosigners_xpub": "To je xpub sopodpisnika, pripravljen za uvoz v drugo denarnico. Varno ga lahko delite.",
+ "wallet_key_created": "Ključ trezorja je bil ustvarjen. Vzemite si trenutek, ter zapišite seznam besed (mnemonično seme) na list papirja.",
+ "are_you_sure_seed_will_be_lost": "Ali ste prepričani? Če nimate varnostne kopije, bo vaše mnemonično seme izgubljeno",
+ "forget_this_seed": "Pozabi to seme in uporabi xpub",
+ "invalid_fingerprint": "Prstni odtis (fingerprint) tega semena se ne ujema s sopodpisnikovim",
+ "view_edit_cosigners": "Prikaži/uredi sopodpisnike",
+ "this_cosigner_is_already_imported": "Ta sopodpisnik je že uvožen",
+ "view_edit_cosigners_title": "Urejanje sopodpisnikov"
}
}
diff --git a/screen/send/ScanQRCode.js b/screen/send/ScanQRCode.js
index c2565d4b5..65ee2f528 100644
--- a/screen/send/ScanQRCode.js
+++ b/screen/send/ScanQRCode.js
@@ -70,6 +70,7 @@ const styles = StyleSheet.create({
position: 'absolute',
},
backdoorInputWrapper: { position: 'absolute', left: '5%', top: '0%', width: '90%', height: '70%', backgroundColor: 'white' },
+ progressWrapper: { position: 'absolute', right: '0%', top: '0%', backgroundColor: 'white' },
backdoorInput: {
height: '50%',
marginTop: 5,
@@ -95,6 +96,8 @@ const ScanQRCode = () => {
const isFocused = useIsFocused();
const [cameraStatus, setCameraStatus] = useState(RNCamera.Constants.CameraStatus.PENDING_AUTHORIZATION);
const [backdoorPressed, setBackdoorPressed] = useState(0);
+ const [urTotal, setUrTotal] = useState(0);
+ const [urHave, setUrHave] = useState(0);
const [backdoorText, setBackdoorText] = useState('');
const [backdoorVisible, setBackdoorVisible] = useState(false);
const [animatedQRCodeData, setAnimatedQRCodeData] = useState({});
@@ -111,6 +114,8 @@ const ScanQRCode = () => {
try {
const [index, total] = extractSingleWorkload(ur);
animatedQRCodeData[index + 'of' + total] = ur;
+ setUrTotal(total);
+ setUrHave(Object.values(animatedQRCodeData).length);
if (Object.values(animatedQRCodeData).length === total) {
const payload = decodeUR(Object.values(animatedQRCodeData));
// lets look inside that data
@@ -264,6 +269,14 @@ const ScanQRCode = () => {
)}
+ {urTotal > 0 && (
+
+
+ {urHave} / {urTotal}
+
+
+ )}
+
{backdoorVisible && (
Provide QR code contents manually:
@@ -291,6 +304,8 @@ const ScanQRCode = () => {
// this might be a json string (for convenience - in case there are "\n" in there)
} catch (_) {
data = backdoorText;
+ } finally {
+ setBackdoorText('');
}
if (data) onBarCodeRead({ data });
diff --git a/screen/send/confirm.js b/screen/send/confirm.js
index 7d130fea2..dc18163a0 100644
--- a/screen/send/confirm.js
+++ b/screen/send/confirm.js
@@ -9,16 +9,6 @@ import { BitcoinUnit } from '../../models/bitcoinUnits';
import PropTypes from 'prop-types';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import Biometric from '../../class/biometrics';
-import {
- HDLegacyElectrumSeedP2PKHWallet,
- HDLegacyP2PKHWallet,
- HDSegwitBech32Wallet,
- HDSegwitP2SHWallet,
- HDLegacyBreadwalletWallet,
- LegacyWallet,
- SegwitP2SHWallet,
- SegwitBech32Wallet,
-} from '../../class';
import loc, { formatBalance, formatBalanceWithoutSuffix } from '../../loc';
import { BlueCurrentTheme } from '../../components/themes';
import Notifications from '../../blue_modules/notifications';
@@ -89,21 +79,7 @@ export default class Confirm extends Component {
}
}
- // wallets that support new createTransaction() instead of deprecated createTx()
- if (
- [
- HDSegwitBech32Wallet.type,
- HDSegwitP2SHWallet.type,
- HDLegacyP2PKHWallet.type,
- HDLegacyBreadwalletWallet.type,
- HDLegacyElectrumSeedP2PKHWallet.type,
- LegacyWallet.type,
- SegwitP2SHWallet.type,
- SegwitBech32Wallet.type,
- ].includes(this.state.fromWallet.type)
- ) {
- amount = formatBalanceWithoutSuffix(amount, BitcoinUnit.BTC, false);
- }
+ amount = formatBalanceWithoutSuffix(amount, BitcoinUnit.BTC, false);
this.context.fetchAndSaveWalletTransactions(this.state.fromWallet.getID());
this.props.navigation.navigate('Success', {
diff --git a/screen/wallets/addMultisig.js b/screen/wallets/addMultisig.js
index 9f59cd0da..92e68e90d 100644
--- a/screen/wallets/addMultisig.js
+++ b/screen/wallets/addMultisig.js
@@ -42,7 +42,7 @@ const WalletsAddMultisig = () => {
color: colors.alternativeTextColor,
},
selectedItem: {
- backgroundColor: colors.buttonDisabledTextColor,
+ backgroundColor: colors.elevated,
},
deSelectedItem: {
backgroundColor: 'transparent',
@@ -146,21 +146,21 @@ const WalletsAddMultisig = () => {
onPress={setFormatP2wsh}
title={`${loc.multisig.native_segwit_title} (${MultisigHDWallet.FORMAT_P2WSH})`}
checkmark={isP2wsh()}
- containerStyle={[styles.borderRadius6, isP2wsh() ? stylesHook.selectedItem : stylesHook.deSelectedItem]}
+ containerStyle={[styles.borderRadius6, styles.item, isP2wsh() ? stylesHook.selectedItem : stylesHook.deSelectedItem]}
/>
@@ -239,6 +239,9 @@ const styles = StyleSheet.create({
justifyContent: 'flex-end',
margin: 0,
},
+ item: {
+ paddingHorizontal: 0,
+ },
descriptionContainer: {
alignContent: 'center',
justifyContent: 'center',
diff --git a/screen/wallets/addMultisigStep2.js b/screen/wallets/addMultisigStep2.js
index 80caafa29..26844d84c 100644
--- a/screen/wallets/addMultisigStep2.js
+++ b/screen/wallets/addMultisigStep2.js
@@ -1,5 +1,5 @@
/* global alert */
-import React, { useRef, useState } from 'react';
+import React, { useContext, useRef, useState } from 'react';
import {
ActivityIndicator,
FlatList,
@@ -32,7 +32,6 @@ import Modal from 'react-native-modal';
import { getSystemName } from 'react-native-device-info';
import ImagePicker from 'react-native-image-picker';
import ScanQRCode from '../send/ScanQRCode';
-import WalletImport from '../../class/wallet-import';
import QRCode from 'react-native-qrcode-svg';
import { SquareButton } from '../../components/SquareButton';
import { SafeAreaView } from 'react-native-safe-area-context';
@@ -43,13 +42,17 @@ import MultipleStepsListItem, {
import Clipboard from '@react-native-community/clipboard';
import showPopupMenu from 'react-native-popup-menu-android';
import ToolTip from 'react-native-tooltip';
+import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
+import { BlueStorageContext } from '../../blue_modules/storage-context';
+const A = require('../../blue_modules/analytics');
const fs = require('../../blue_modules/fs');
const isDesktop = getSystemName() === 'Mac OS X';
const LocalQRCode = require('@remobile/react-native-qrcode-local-image');
const staticCache = {};
const WalletsAddMultisigStep2 = () => {
+ const { addWallet, saveToDisk, setNewWalletAdded } = useContext(BlueStorageContext);
const { colors } = useTheme();
const navigation = useNavigation();
@@ -125,7 +128,7 @@ const WalletsAddMultisigStep2 = () => {
},
});
- const onCreate = () => {
+ const onCreate = async () => {
setIsLoading(true);
const w = new MultisigHDWallet();
w.setM(m);
@@ -149,7 +152,14 @@ const WalletsAddMultisigStep2 = () => {
w.addCosigner(cc[0], cc[1], cc[2]);
}
w.setLabel('Multisig Vault');
- WalletImport._saveWallet(w);
+ await w.fetchBalance();
+
+ addWallet(w);
+ await saveToDisk();
+ setNewWalletAdded(true);
+ A(A.ENUM.CREATED_WALLET);
+ ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false });
+
navigation.dangerouslyGetParent().pop();
};
diff --git a/screen/wallets/import.js b/screen/wallets/import.js
index fad69981e..ed06fcb00 100644
--- a/screen/wallets/import.js
+++ b/screen/wallets/import.js
@@ -234,7 +234,7 @@ const WalletsImport = () => {
onPress={importButtonPressed}
/>
-
+
>
{Platform.select({
diff --git a/tests/e2e/bluewallet.spec.js b/tests/e2e/bluewallet.spec.js
index 5ca8bcf45..71f813ca2 100644
--- a/tests/e2e/bluewallet.spec.js
+++ b/tests/e2e/bluewallet.spec.js
@@ -551,6 +551,41 @@ describe('BlueWallet UI Tests', () => {
expect(element(by.id('TransactionValue'))).toHaveText('0.0001');
expect(element(by.id('TransactionAddress'))).toHaveText('BC1QH6TF004TY7Z7UN2V5NTU4MKF630545GVHS45U7');
});
+
+ it('can import multisig setup from UR (ver1) QRs 2 frames', async () => {
+ await yo('WalletsList');
+ await element(by.id('WalletsList')).swipe('left', 'fast', 1); // in case emu screen is small and it doesnt fit
+ // going to Import Wallet screen and importing mnemonic
+ await element(by.id('CreateAWallet')).tap();
+ await element(by.id('ImportWallet')).tap();
+ await element(by.id('ScanImport')).tap();
+
+ const urs = [
+ 'UR:BYTES/1OF2/J8RX04F2WJ9SSY577U30R55ELM4LUCJCXJVJTD60SYV9A286Q0AQH7QXL6/TYQMJGEQGFK82E2HV9KXCET5YPXH2MR5D9EKJEEQWDJHGATSYPNXJMR9PG3JQARGD9EJQENFD3JJQCM0DE6XZ6TWWVSX7MNV0YS8QATZD35KXGRTV4UHXGRPDEJZQ6TNYPEKZEN9YP6X7Z3RYPJXJUM5WF5KYAT5V5SXZMT0DENJQCM0WD5KWMN9WFES5GC2FESK6EF6YPXH2MR5D9EKJEEQ2ESH2MR5PFGX7MRFVDUN5GPJYPHKVGPJPFZX2UNFWESHG6T0DCAZQMF0XSUZWTESYUHNQFE0XGNS53N0WFKKZAP6YPGRY46NFQ9Q53PNXAZ5Z3PC8QAZQKNSW43RWDRFDFCXV6Z92F9YU6NGGD94S5NNWP2XGNZ22C6K2M69D4F4YKNYFPC5GANS',
+ 'UR:BYTES/2OF2/J8RX04F2WJ9SSY577U30R55ELM4LUCJCXJVJTD60SYV9A286Q0AQH7QXL6/8944VARY2EZHJ62CDVMHQKRC2F3XVKN629M8X3ZXWPNYGJZ9FPT8G4NS0Q6YG73EG3R42468DCE9S6E40FRN2AF5X4G4GNTNT9FNYAN2DA5YU5G2PGCNVWZYGSMRQVE6YPD8QATZXU6K6S298PZK57TC2DAX772SD4RKUEP4G5MY672YXAQ5C36WDEJ8YA2HWC6NY7RS0F5K6KJ3FD6KKAMKG4N9S4ZGW9K5SWRWVF3XXDNRVDGR2APJV9XNXMTHWVEHQJ6E2DHYKUZTF4XHJARYVF8Y2KJX24UYK7N6W3V5VNFC2PHQ5ZSJDYL5T',
+ ];
+
+ await waitFor(element(by.id('UrProgressBar'))).toBeNotVisible();
+
+ for (const ur of urs) {
+ // tapping 10 times invisible button is a backdoor:
+ for (let c = 0; c <= 10; c++) {
+ await element(by.id('ScanQrBackdoorButton')).tap();
+ }
+ await element(by.id('scanQrBackdoorInput')).replaceText(ur);
+ await element(by.id('scanQrBackdoorOkButton')).tap();
+ await waitFor(element(by.id('UrProgressBar'))).toBeVisible();
+ }
+
+ if (process.env.TRAVIS) await sleep(60000);
+ await sup('OK', 3 * 61000); // waiting for wallet import
+ await element(by.text('OK')).tap();
+ // ok, wallet imported
+
+ // lets go inside wallet
+ const expectedWalletLabel = 'Multisig Vault';
+ await element(by.text(expectedWalletLabel)).tap();
+ });
});
async function sleep(ms) {
diff --git a/tests/integration/multisig-hd-wallet.test.js b/tests/integration/multisig-hd-wallet.test.js
index fd1be9ec8..a80bf11f0 100644
--- a/tests/integration/multisig-hd-wallet.test.js
+++ b/tests/integration/multisig-hd-wallet.test.js
@@ -46,6 +46,6 @@ describe('multisig-hd-wallet', () => {
await w.fetchBalance();
await w.fetchTransactions();
- assert.strictEqual(w.getTransactions().length, 5);
+ assert.ok(w.getTransactions().length >= 6);
});
});