WIP: Polyseed. Polyseed wallets currently have offsets enforced due to a bug in ANONERO's polyseed implementation

This commit is contained in:
pokkst 2023-12-05 04:04:58 -06:00
parent f6876b866e
commit fc853dc55d
No known key found for this signature in database
GPG key ID: EC4FAAA66859FAA4
13 changed files with 358 additions and 29 deletions

View file

@ -79,6 +79,14 @@ add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libwallet.a)
add_library(polyseed STATIC IMPORTED)
set_target_properties(polyseed PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libpolyseed.a)
add_library(polyseed-wrapper STATIC IMPORTED)
set_target_properties(polyseed-wrapper PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libpolyseed_wrapper.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}/${ANDROID_ABI}/monero/libcryptonote_core.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libcryptonote_core.a)
@ -155,6 +163,10 @@ add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION set_target_properties(net PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libnet.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libnet.a)
add_library(utf8proc STATIC IMPORTED)
set_target_properties(utf8proc PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/libutf8proc.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}/${ANDROID_ABI}/monero/libhardforks.a) ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/monero/libhardforks.a)
@ -198,6 +210,9 @@ target_link_libraries( monerujo
cryptonote_core cryptonote_core
cryptonote_basic cryptonote_basic
cryptonote_format_utils_basic cryptonote_format_utils_basic
polyseed
polyseed-wrapper
utf8proc
mnemonics mnemonics
ringct ringct
ringct_basic ringct_basic

View file

@ -347,6 +347,41 @@ Java_net_mynero_wallet_model_WalletManager_createWalletJ(JNIEnv *env, jobject in
return reinterpret_cast<jlong>(wallet); return reinterpret_cast<jlong>(wallet);
} }
JNIEXPORT jlong JNICALL
Java_net_mynero_wallet_model_WalletManager_createWalletPolyseedJ(JNIEnv *env, jobject instance,
jstring path, jstring password, jstring passpharse,
jstring language,
jint networkType) {
std::string seed_words;
std::string err;
bool _polyseedCreate = Monero::Wallet::createPolyseed(seed_words, err);
if (!_polyseedCreate) {
LOGE("Failed to polyseedCreate");
}
// wallet->createPolyseed(seed_words, err);
const char *_path = env->GetStringUTFChars(path, nullptr);
const char *_password = env->GetStringUTFChars(password, nullptr);
const char *_passpharse = env->GetStringUTFChars(passpharse, nullptr);
const char *_language = env->GetStringUTFChars(language, nullptr); // NOT USED ANYMORE?????
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet =
Monero::WalletManagerFactory::getWalletManager()->createWalletFromPolyseed(
std::string(_path),
std::string(_password),
_networkType,
seed_words,
std::string(_passpharse), true);
env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(language, _language);
env->ReleaseStringUTFChars(passpharse, _passpharse);
return reinterpret_cast<jlong>(wallet);
}
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_net_mynero_wallet_model_WalletManager_openWalletJ(JNIEnv *env, jobject instance, Java_net_mynero_wallet_model_WalletManager_openWalletJ(JNIEnv *env, jobject instance,
jstring path, jstring password, jstring path, jstring password,
@ -395,6 +430,33 @@ Java_net_mynero_wallet_model_WalletManager_recoveryWalletJ(JNIEnv *env, jobject
return reinterpret_cast<jlong>(wallet); return reinterpret_cast<jlong>(wallet);
} }
JNIEXPORT jlong JNICALL
Java_net_mynero_wallet_model_WalletManager_recoveryWalletPolyseedJ(JNIEnv *env, jobject instance,
jstring path, jstring password,
jstring mnemonic, jstring offset,
jint networkType) {
const char *_path = env->GetStringUTFChars(path, nullptr);
const char *_password = env->GetStringUTFChars(password, nullptr);
const char *_mnemonic = env->GetStringUTFChars(mnemonic, nullptr);
const char *_offset = env->GetStringUTFChars(offset, nullptr);
Monero::NetworkType _networkType = static_cast<Monero::NetworkType>(networkType);
Monero::Wallet *wallet =
Monero::WalletManagerFactory::getWalletManager()->createWalletFromPolyseed(
std::string(_path),
std::string(_password),
_networkType,
std::string(_mnemonic),
std::string(_offset), false);
env->ReleaseStringUTFChars(path, _path);
env->ReleaseStringUTFChars(password, _password);
env->ReleaseStringUTFChars(mnemonic, _mnemonic);
env->ReleaseStringUTFChars(offset, _offset);
return reinterpret_cast<jlong>(wallet);
}
JNIEXPORT jlong JNICALL JNIEXPORT jlong JNICALL
Java_net_mynero_wallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance, Java_net_mynero_wallet_model_WalletManager_createWalletFromKeysJ(JNIEnv *env, jobject instance,
jstring path, jstring password, jstring path, jstring password,
@ -645,11 +707,55 @@ JNIEXPORT jstring JNICALL
Java_net_mynero_wallet_model_Wallet_getSeed(JNIEnv *env, jobject instance, jstring seedOffset) { Java_net_mynero_wallet_model_Wallet_getSeed(JNIEnv *env, jobject instance, jstring seedOffset) {
const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr); const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr);
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance); Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
jstring seed = env->NewStringUTF(wallet->seed(std::string(_seedOffset)).c_str());
std::string _seed;
std::string seedOffsetStr(_seedOffset);
bool _getPolyseed = wallet->getPolyseed(_seed, seedOffsetStr);
if (_getPolyseed) {
LOGD("_getPolyseed: true");
} else {
LOGD("_getPolyseed: false");
LOGE("wallet->getSeed() %s", wallet->errorString().c_str());
LOGD("Falling back to normal, boring, seed");
_seed = wallet->seed(std::string(_seedOffset));
}
env->ReleaseStringUTFChars(seedOffset, _seedOffset); env->ReleaseStringUTFChars(seedOffset, _seedOffset);
jstring seed = env->NewStringUTF(_seed.c_str());
return seed; return seed;
} }
JNIEXPORT jstring JNICALL
Java_net_mynero_wallet_model_Wallet_getLegacySeed(JNIEnv *env, jobject instance, jstring seedOffset) {
const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr);
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
std::string _seed;
std::string seedOffsetStr(_seedOffset);
_seed = wallet->seed(std::string(_seedOffset));
env->ReleaseStringUTFChars(seedOffset, _seedOffset);
jstring seed = env->NewStringUTF(_seed.c_str());
return seed;
}
JNIEXPORT jboolean JNICALL
Java_net_mynero_wallet_model_Wallet_isPolyseedSupported(JNIEnv *env, jobject instance, jstring seedOffset) {
const char *_seedOffset = env->GetStringUTFChars(seedOffset, nullptr);
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);
std::string _seed;
std::string seedOffsetStr(_seedOffset);
bool _getPolyseed = wallet->getPolyseed(_seed, seedOffsetStr);
env->ReleaseStringUTFChars(seedOffset, _seedOffset);
return _getPolyseed;
}
JNIEXPORT jstring JNICALL JNIEXPORT jstring JNICALL
Java_net_mynero_wallet_model_Wallet_getSeedLanguage(JNIEnv *env, jobject instance) { Java_net_mynero_wallet_model_Wallet_getSeedLanguage(JNIEnv *env, jobject instance) {
Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance); Monero::Wallet *wallet = getHandle<Monero::Wallet>(env, instance);

View file

@ -198,6 +198,17 @@ public class OnboardingFragment extends Fragment implements NodeSelectionBottomS
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
String text = editable.toString(); String text = editable.toString();
OnboardingViewModel.SeedType seedType = mViewModel.getMnemonicType(text);
if(seedType == OnboardingViewModel.SeedType.LEGACY) {
seedOffsetCheckbox.setVisibility(View.VISIBLE);
walletRestoreHeightEditText.setVisibility(View.VISIBLE);
walletPasswordEditText.setHint(getString(R.string.password_optional));
} else {
seedOffsetCheckbox.setVisibility(View.GONE);
walletRestoreHeightEditText.setVisibility(View.GONE);
walletPasswordEditText.setHint(getString(R.string.password_non_optional));
}
if (text.isEmpty()) { if (text.isEmpty()) {
createWalletButton.setText(R.string.create_wallet); createWalletButton.setText(R.string.create_wallet);
} else { } else {

View file

@ -71,6 +71,7 @@ public class OnboardingViewModel extends ViewModel {
String offset = useOffset ? walletPassword : ""; String offset = useOffset ? walletPassword : "";
if (!walletPassword.isEmpty()) { if (!walletPassword.isEmpty()) {
if(!walletPassword.equals(confirmedPassword)) { if(!walletPassword.equals(confirmedPassword)) {
_enableCreateButton.setValue(true);
mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, application.getString(R.string.invalid_confirmed_password), Toast.LENGTH_SHORT).show()); mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, application.getString(R.string.invalid_confirmed_password), Toast.LENGTH_SHORT).show());
return; return;
} }
@ -84,11 +85,21 @@ public class OnboardingViewModel extends ViewModel {
} }
if (walletSeed.isEmpty()) { if (walletSeed.isEmpty()) {
Wallet tmpWallet = createTempWallet(mainActivity.getApplicationInfo().dataDir); //we do this to get seed, then recover wallet so we can use seed offset if(offset.isEmpty()) {
wallet = WalletManager.getInstance().recoveryWallet(walletFile, walletPassword, tmpWallet.getSeed(""), offset, restoreHeight); mainActivity.runOnUiThread(() -> {
_enableCreateButton.setValue(true);
Toast.makeText(mainActivity, application.getString(R.string.invalid_empty_passphrase), Toast.LENGTH_SHORT).show();
});
return;
} else { } else {
if (!checkMnemonic(walletSeed)) { wallet = WalletManager.getInstance().createWalletPolyseed(walletFile, walletPassword, offset, Constants.MNEMONIC_LANGUAGE);
mainActivity.runOnUiThread(() -> Toast.makeText(mainActivity, application.getString(R.string.invalid_mnemonic_code), Toast.LENGTH_SHORT).show()); }
} else {
if (getMnemonicType(walletSeed) == SeedType.UNKNOWN) {
mainActivity.runOnUiThread(() -> {
_enableCreateButton.setValue(true);
Toast.makeText(mainActivity, application.getString(R.string.invalid_mnemonic_code), Toast.LENGTH_SHORT).show();
});
return; return;
} }
if (!restoreHeightText.isEmpty()) { if (!restoreHeightText.isEmpty()) {
@ -99,7 +110,7 @@ public class OnboardingViewModel extends ViewModel {
Wallet.Status walletStatus = wallet.getStatus(); Wallet.Status walletStatus = wallet.getStatus();
wallet.close(); wallet.close();
boolean ok = walletStatus.isOk(); boolean ok = walletStatus.isOk();
walletFile.delete(); // cache is broken for some reason when recovering wallets. delete the file here. this happens in monerujo too. //walletFile.delete(); // cache is broken for some reason when recovering wallets. delete the file here. this happens in monerujo too.
if (ok) { if (ok) {
((MainActivity)mainActivity).init(walletFile, walletPassword); ((MainActivity)mainActivity).init(walletFile, walletPassword);
@ -119,12 +130,20 @@ public class OnboardingViewModel extends ViewModel {
return RestoreHeight.getInstance().getHeight(restoreDate.getTime()); return RestoreHeight.getInstance().getHeight(restoreDate.getTime());
} }
private Wallet createTempWallet(String dir) { public SeedType getMnemonicType(String seed) {
File tmpWalletFile = new File(dir, Constants.WALLET_NAME + "_tmp"); String[] words = seed.split("\\s");
return WalletManager.getInstance().createWallet(tmpWalletFile, "", Constants.MNEMONIC_LANGUAGE, 0); if(words.length == 16) {
return SeedType.POLYSEED;
} else if (words.length == 25){
return SeedType.LEGACY;
} else {
return SeedType.UNKNOWN;
}
} }
private boolean checkMnemonic(String seed) { public enum SeedType {
return (seed.split("\\s").length == 25); LEGACY,
POLYSEED,
UNKNOWN
} }
} }

View file

@ -16,6 +16,7 @@
package net.mynero.wallet.model; package net.mynero.wallet.model;
import android.util.Log;
import android.util.Pair; import android.util.Pair;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
@ -94,6 +95,10 @@ public class Wallet {
public native String getSeed(String offset); public native String getSeed(String offset);
public native String getLegacySeed(String offset);
public native boolean isPolyseedSupported(String offset);
public native String getSeedLanguage(); public native String getSeedLanguage();
public native void setSeedLanguage(String language); public native void setSeedLanguage(String language);
@ -189,10 +194,42 @@ public class Wallet {
// virtual std::string keysFilename() const = 0; // virtual std::string keysFilename() const = 0;
public boolean init(long upper_transaction_size_limit) { public boolean init(long upper_transaction_size_limit) {
return initJ(WalletManager.getInstance().getDaemonAddress(), upper_transaction_size_limit, String daemon_address = WalletManager.getInstance().getDaemonAddress();
WalletManager.getInstance().getDaemonUsername(), String daemon_username = WalletManager.getInstance().getDaemonUsername();
WalletManager.getInstance().getDaemonPassword(), WalletManager.getInstance().getProxy()); String daemon_password = WalletManager.getInstance().getDaemonPassword();
String proxy_address = WalletManager.getInstance().getProxy();
Log.d("Wallet.java", "init(");
if (daemon_address != null) {
Log.d("Wallet.java", daemon_address.toString());
} else {
Log.d("Wallet.java", "daemon_address == null");
daemon_address = "";
} }
Log.d("Wallet.java", "upper_transaction_size_limit = 0 (probably)");
if (daemon_username != null) {
Log.d("Wallet.java", daemon_username.toString());
} else {
Log.d("Wallet.java", "daemon_username == null");
daemon_username = "";
}
if (daemon_password != null) {
Log.d("Wallet.java", daemon_password.toString());
} else {
Log.d("Wallet.java", "daemon_password == null");
daemon_password = "";
}
if (proxy_address != null) {
Log.d("Wallet.java", proxy_address.toString());
} else {
Log.d("Wallet.java", "proxy_address == null");
proxy_address = "";
}
Log.d("Wallet.java", ");");
return initJ(daemon_address, upper_transaction_size_limit,
daemon_username, daemon_password,
proxy_address);
}
private native boolean initJ(String daemon_address, long upper_transaction_size_limit, private native boolean initJ(String daemon_address, long upper_transaction_size_limit,
String daemon_username, String daemon_password, String proxy); String daemon_username, String daemon_password, String proxy);

View file

@ -136,6 +136,18 @@ public class WalletManager {
private native long createWalletJ(String path, String password, String language, int networkType); private native long createWalletJ(String path, String password, String language, int networkType);
public Wallet createWalletPolyseed(File aFile, String password, String passphrase, String language) {
long walletHandle = createWalletPolyseedJ(aFile.getAbsolutePath(), password, passphrase, language, getNetworkType().getValue());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
if (wallet.getStatus().isOk()) {
wallet.setPassword(password); // this rewrites the keys file (which contains the restore height)
} else
Timber.e(wallet.getStatus().toString());
return wallet;
}
private native long createWalletPolyseedJ(String path, String password, String passphrase, String language, int networkType);
public Wallet openAccount(String path, int accountIndex, String password) { public Wallet openAccount(String path, int accountIndex, String password) {
long walletHandle = openWalletJ(path, password, getNetworkType().getValue()); long walletHandle = openWalletJ(path, password, getNetworkType().getValue());
Wallet wallet = new Wallet(walletHandle, accountIndex); Wallet wallet = new Wallet(walletHandle, accountIndex);
@ -169,6 +181,20 @@ public class WalletManager {
String mnemonic, String offset, String mnemonic, String offset,
int networkType, long restoreHeight); int networkType, long restoreHeight);
public Wallet recoveryWalletPolyseed(File aFile, String password,
String mnemonic, String offset) {
long walletHandle = recoveryWalletPolyseedJ(aFile.getAbsolutePath(), password,
mnemonic, offset,
getNetworkType().getValue());
Wallet wallet = new Wallet(walletHandle);
manageWallet(wallet);
return wallet;
}
private native long recoveryWalletPolyseedJ(String path, String password,
String mnemonic, String offset,
int networkType);
public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight, public Wallet createWalletWithKeys(File aFile, String password, String language, long restoreHeight,
String addressString, String viewKeyString, String spendKeyString) { String addressString, String viewKeyString, String spendKeyString) {
long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), password, long walletHandle = createWalletFromKeysJ(aFile.getAbsolutePath(), password,

View file

@ -38,7 +38,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/edittext_bg" android:background="@drawable/edittext_bg"
android:hint="@string/password_optional" android:hint="@string/password_non_optional"
android:inputType="textPassword" android:inputType="textPassword"
android:minHeight="48dp" android:minHeight="48dp"
app:layout_constraintBottom_toTopOf="@id/wallet_password_confirm_edittext" app:layout_constraintBottom_toTopOf="@id/wallet_password_confirm_edittext"
@ -56,21 +56,12 @@
android:hint="@string/password_confirm" android:hint="@string/password_confirm"
android:inputType="textPassword" android:inputType="textPassword"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/seed_offset_checkbox" app:layout_constraintBottom_toTopOf="@id/advanced_settings_dropdown_textview"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/wallet_password_edittext" app:layout_constraintTop_toBottomOf="@id/wallet_password_edittext"
tools:visibility="gone" /> tools:visibility="gone" />
<CheckBox
android:id="@+id/seed_offset_checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/use_password_as_seed_offset"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/wallet_password_confirm_edittext"/>
<TextView <TextView
android:id="@+id/advanced_settings_dropdown_textview" android:id="@+id/advanced_settings_dropdown_textview"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -85,7 +76,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/seed_offset_checkbox" /> app:layout_constraintTop_toBottomOf="@id/wallet_password_confirm_edittext" />
<ImageView <ImageView
android:id="@+id/advanced_settings_chevron_imageview" android:id="@+id/advanced_settings_chevron_imageview"
@ -131,6 +122,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingEnd="16dp" android:paddingEnd="16dp"
tools:text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" tools:text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
@ -140,6 +132,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/wallet_seed_edittext"
app:layout_constraintTop_toBottomOf="@id/show_xmrchan_switch" app:layout_constraintTop_toBottomOf="@id/show_xmrchan_switch"
tools:ignore="SpeakableTextPresentCheck" /> tools:ignore="SpeakableTextPresentCheck" />
@ -148,7 +141,6 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layout_marginTop="32dp"
android:background="@drawable/edittext_bg" android:background="@drawable/edittext_bg"
android:hint="@string/recovery_phrase_optional" android:hint="@string/recovery_phrase_optional"
android:minHeight="48dp" android:minHeight="48dp"
@ -165,11 +157,23 @@
android:hint="@string/restore_height_optional" android:hint="@string/restore_height_optional"
android:inputType="number" android:inputType="number"
android:minHeight="48dp" android:minHeight="48dp"
app:layout_constraintBottom_toTopOf="@id/tor_onboarding_switch" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/seed_offset_checkbox"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/wallet_seed_edittext" /> app:layout_constraintTop_toBottomOf="@id/wallet_seed_edittext" />
<CheckBox
android:id="@+id/seed_offset_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dp"
android:text="@string/use_password_as_seed_offset"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/tor_onboarding_switch"
app:layout_constraintTop_toBottomOf="@id/wallet_restore_height_edittext"/>
<TextView <TextView
android:id="@+id/tor_onboarding_switch_label" android:id="@+id/tor_onboarding_switch_label"
android:layout_width="0dp" android:layout_width="0dp"
@ -189,7 +193,7 @@
android:minWidth="48dp" android:minWidth="48dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/wallet_restore_height_edittext" /> app:layout_constraintTop_toBottomOf="@id/seed_offset_checkbox" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/wallet_proxy_settings_layout" android:id="@+id/wallet_proxy_settings_layout"

View file

@ -30,6 +30,7 @@
<string name="error_creating_tx">Error creating: %1$s</string> <string name="error_creating_tx">Error creating: %1$s</string>
<string name="create_wallet">Create wallet</string> <string name="create_wallet">Create wallet</string>
<string name="invalid_mnemonic_code">Invalid mnemonic</string> <string name="invalid_mnemonic_code">Invalid mnemonic</string>
<string name="invalid_empty_passphrase">Please enter a password</string>
<string name="invalid_confirmed_password">Passwords do not match</string> <string name="invalid_confirmed_password">Passwords do not match</string>
<string name="copied_to_clipboard">Copied to clipboard</string> <string name="copied_to_clipboard">Copied to clipboard</string>
<string name="street_mode">Street mode (hide balances)</string> <string name="street_mode">Street mode (hide balances)</string>
@ -50,6 +51,7 @@
<string name="recovery_phrase_optional">Recovery phrase (optional)</string> <string name="recovery_phrase_optional">Recovery phrase (optional)</string>
<string name="restore_height_optional">Restore height (optional)</string> <string name="restore_height_optional">Restore height (optional)</string>
<string name="password_optional">Password (optional)</string> <string name="password_optional">Password (optional)</string>
<string name="password_non_optional">Enter a password</string>
<string name="password_confirm">Confirm password</string> <string name="password_confirm">Confirm password</string>
<string name="password">Password</string> <string name="password">Password</string>
<string name="label">Label</string> <string name="label">Label</string>

View file

@ -158,6 +158,27 @@ RUN set -x \
&& make -j${NPROC} \ && make -j${NPROC} \
&& make install && make install
# polyseed
RUN git clone https://github.com/tevador/polyseed.git
RUN set -x \
&& cd polyseed \
&& git reset --hard b7c35bb3c6b91e481ecb04fc235eaff69c507fa1 \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} . \
&& make \
&& make install
# utf8proc
RUN git clone https://github.com/JuliaStrings/utf8proc -b v2.8.0
RUN set -x \
&& cd utf8proc \
&& git reset --hard 1cb28a66ca79a0845e99433fd1056257456cef8b \
&& mkdir build \
&& cd build \
&& rm -rf ../CMakeCache.txt ../CMakeFiles/ \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. \
&& make \
&& make install
COPY . /src COPY . /src
RUN set -x \ RUN set -x \
&& cd /src \ && cd /src \

View file

@ -158,6 +158,27 @@ RUN set -x \
&& make -j${NPROC} \ && make -j${NPROC} \
&& make install && make install
# polyseed
RUN git clone https://github.com/tevador/polyseed.git
RUN set -x \
&& cd polyseed \
&& git reset --hard b7c35bb3c6b91e481ecb04fc235eaff69c507fa1 \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} . \
&& make \
&& make install
# utf8proc
RUN git clone https://github.com/JuliaStrings/utf8proc -b v2.8.0
RUN set -x \
&& cd utf8proc \
&& git reset --hard 1cb28a66ca79a0845e99433fd1056257456cef8b \
&& mkdir build \
&& cd build \
&& rm -rf ../CMakeCache.txt ../CMakeFiles/ \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. \
&& make \
&& make install
COPY . /src COPY . /src
RUN set -x \ RUN set -x \
&& cd /src \ && cd /src \

View file

@ -158,6 +158,27 @@ RUN set -x \
&& make -j${NPROC} \ && make -j${NPROC} \
&& make install && make install
# polyseed
RUN git clone https://github.com/tevador/polyseed.git
RUN set -x \
&& cd polyseed \
&& git reset --hard b7c35bb3c6b91e481ecb04fc235eaff69c507fa1 \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} . \
&& make \
&& make install
# utf8proc
RUN git clone https://github.com/JuliaStrings/utf8proc -b v2.8.0
RUN set -x \
&& cd utf8proc \
&& git reset --hard 1cb28a66ca79a0845e99433fd1056257456cef8b \
&& mkdir build \
&& cd build \
&& rm -rf ../CMakeCache.txt ../CMakeFiles/ \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. \
&& make \
&& make install
COPY . /src COPY . /src
RUN set -x \ RUN set -x \
&& cd /src \ && cd /src \

View file

@ -158,6 +158,27 @@ RUN set -x \
&& make -j${NPROC} \ && make -j${NPROC} \
&& make install && make install
# polyseed
RUN git clone https://github.com/tevador/polyseed.git
RUN set -x \
&& cd polyseed \
&& git reset --hard b7c35bb3c6b91e481ecb04fc235eaff69c507fa1 \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} . \
&& make \
&& make install
# utf8proc
RUN git clone https://github.com/JuliaStrings/utf8proc -b v2.8.0
RUN set -x \
&& cd utf8proc \
&& git reset --hard 1cb28a66ca79a0845e99433fd1056257456cef8b \
&& mkdir build \
&& cd build \
&& rm -rf ../CMakeCache.txt ../CMakeFiles/ \
&& CC=clang CXX=clang++ cmake -DCMAKE_INSTALL_PREFIX=${PREFIX} .. \
&& make \
&& make install
COPY . /src COPY . /src
RUN set -x \ RUN set -x \
&& cd /src \ && cd /src \

View file

@ -745,6 +745,10 @@ struct Wallet
static void warning(const std::string &category, const std::string &str); static void warning(const std::string &category, const std::string &str);
static void error(const std::string &category, const std::string &str); static void error(const std::string &category, const std::string &str);
virtual bool getPolyseed(std::string &seed, std::string &passphrase) const = 0;
static bool createPolyseed(std::string &seed_words, std::string &err, const std::string &language = "English");
static std::vector<std::pair<std::string, std::string>> getPolyseedLanguages();
/** /**
* @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds) * @brief StartRefresh - Start/resume refresh thread (refresh every 10 seconds)
*/ */
@ -1304,6 +1308,27 @@ struct WalletManager
uint64_t kdf_rounds = 1, uint64_t kdf_rounds = 1,
WalletListener * listener = nullptr) = 0; WalletListener * listener = nullptr) = 0;
/*!
* \brief creates a wallet from a polyseed mnemonic phrase
* \param path Name of the wallet file to be created
* \param password Password of wallet file
* \param nettype Network type
* \param mnemonic Polyseed mnemonic
* \param passphrase Optional seed offset passphrase
* \param newWallet Whether it is a new wallet
* \param restoreHeight Override the embedded restore height
* \param kdf_rounds Number of rounds for key derivation function
* @return
*/
virtual Wallet * createWalletFromPolyseed(const std::string &path,
const std::string &password,
NetworkType nettype,
const std::string &mnemonic,
const std::string &passphrase = "",
bool newWallet = true,
uint64_t restore_height = 0,
uint64_t kdf_rounds = 1) = 0;
/*! /*!
* \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted
* \param wallet previously opened / created wallet instance * \param wallet previously opened / created wallet instance