commit
019b8d3a9b
|
@ -272,7 +272,12 @@ export class WalletRPC {
|
|||
break;
|
||||
|
||||
case "create_wallet":
|
||||
this.createWallet(params.name, params.password, params.language);
|
||||
this.createWallet(
|
||||
params.name,
|
||||
params.password,
|
||||
params.language,
|
||||
params.hardware_wallet
|
||||
);
|
||||
break;
|
||||
|
||||
case "restore_wallet":
|
||||
|
@ -509,13 +514,20 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
createWallet(filename, password, language) {
|
||||
isHardwareWallet(filename) {
|
||||
let hwfile = path.join(this.wallet_dir, filename + ".hwdev.txt");
|
||||
return fs.existsSync(hwfile);
|
||||
}
|
||||
|
||||
createWallet(filename, password, language, hardware_wallet) {
|
||||
// Reset the status error
|
||||
this.sendGateway("reset_wallet_error");
|
||||
this.sendRPC("create_wallet", {
|
||||
filename,
|
||||
password,
|
||||
language
|
||||
language,
|
||||
hardware_wallet: !!hardware_wallet,
|
||||
device_label: hardware_wallet ? "hardware_wallet" : undefined
|
||||
}).then(data => {
|
||||
if (data.hasOwnProperty("error")) {
|
||||
this.sendGateway("set_wallet_error", { status: data.error });
|
||||
|
@ -702,6 +714,14 @@ export class WalletRPC {
|
|||
errorOnExist: true
|
||||
});
|
||||
}
|
||||
|
||||
if (fs.existsSync(import_path + ".hwdev.txt")) {
|
||||
fs.copySync(
|
||||
import_path + ".hwdev.txt",
|
||||
destination + ".hwdev.txt",
|
||||
fs.constants.COPYFILE_EXCL
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
this.sendGateway("set_wallet_error", {
|
||||
status: {
|
||||
|
@ -794,6 +814,10 @@ export class WalletRPC {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.isHardwareWallet(filename)) {
|
||||
wallet.info.hardware_wallet = true;
|
||||
}
|
||||
|
||||
this.saveWallet().then(() => {
|
||||
let address_txt_path = path.join(
|
||||
this.wallet_dir,
|
||||
|
@ -810,7 +834,11 @@ export class WalletRPC {
|
|||
|
||||
this.sendGateway("set_wallet_data", wallet);
|
||||
|
||||
if (this.isHardwareWallet(filename)) {
|
||||
this.startHeartbeat(10);
|
||||
} else {
|
||||
this.startHeartbeat();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -840,6 +868,12 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
const hardware_wallet_file = path.join(
|
||||
this.wallet_dir,
|
||||
filename + ".hwdev.txt"
|
||||
);
|
||||
const hardware_wallet = fs.existsSync(hardware_wallet_file);
|
||||
|
||||
// store hash of the password so we can check against it later when requesting private keys, or for sending txs
|
||||
this.wallet_state.password_hash = crypto
|
||||
.pbkdf2Sync(password, this.auth[2], 1000, 64, "sha512")
|
||||
|
@ -847,10 +881,20 @@ export class WalletRPC {
|
|||
this.wallet_state.name = filename;
|
||||
this.wallet_state.open = true;
|
||||
|
||||
if (hardware_wallet) {
|
||||
this.startHeartbeat(10);
|
||||
} else {
|
||||
this.startHeartbeat();
|
||||
}
|
||||
|
||||
this.purchasedNames = {};
|
||||
|
||||
this.sendGateway("set_wallet_data", {
|
||||
info: {
|
||||
hardware_wallet
|
||||
}
|
||||
});
|
||||
|
||||
// Check if we have a view only wallet by querying the spend key
|
||||
this.sendRPC("query_key", { key_type: "spend_key" }).then(data => {
|
||||
if (data.hasOwnProperty("error") || !data.hasOwnProperty("result")) {
|
||||
|
@ -867,17 +911,17 @@ export class WalletRPC {
|
|||
});
|
||||
}
|
||||
|
||||
startHeartbeat() {
|
||||
startHeartbeat(multiplier = 1) {
|
||||
clearInterval(this.heartbeat);
|
||||
this.heartbeat = setInterval(() => {
|
||||
this.heartbeatAction();
|
||||
}, 5000);
|
||||
}, 5000 * multiplier);
|
||||
this.heartbeatAction(true);
|
||||
|
||||
clearInterval(this.onsHeartbeat);
|
||||
this.onsHeartbeat = setInterval(() => {
|
||||
this.updateLocalONSRecords();
|
||||
}, 30 * 1000); // Every 30 seconds
|
||||
}, 30 * 1000 * multiplier); // Every 30 seconds
|
||||
this.updateLocalONSRecords();
|
||||
}
|
||||
|
||||
|
@ -1701,6 +1745,9 @@ export class WalletRPC {
|
|||
// send address and tx fees before sending
|
||||
// isSweepAll refers to if it's the sweep from service nodes page
|
||||
transfer(password, amount, address, priority, isSweepAll) {
|
||||
console.log(
|
||||
"TODO sean remove this - wallet: " + JSON.stringify(this.wallet)
|
||||
);
|
||||
const cryptoCallback = (err, password_hash) => {
|
||||
if (err) {
|
||||
this.sendGateway("set_tx_status", {
|
||||
|
@ -2682,7 +2729,7 @@ export class WalletRPC {
|
|||
return;
|
||||
}
|
||||
|
||||
// Exclude all files without a keys extension
|
||||
// Exclude all files without keys
|
||||
if (path.extname(filename) !== ".keys") return;
|
||||
|
||||
const wallet_name = path.parse(filename).name;
|
||||
|
@ -2691,7 +2738,8 @@ export class WalletRPC {
|
|||
let wallet_data = {
|
||||
name: wallet_name,
|
||||
address: null,
|
||||
password_protected: null
|
||||
password_protected: null,
|
||||
hardware_wallet: false
|
||||
};
|
||||
|
||||
if (
|
||||
|
@ -2720,6 +2768,12 @@ export class WalletRPC {
|
|||
}
|
||||
}
|
||||
|
||||
if (
|
||||
fs.existsSync(path.join(this.wallet_dir, wallet_name + ".hwdev.txt"))
|
||||
) {
|
||||
wallet_data.hardware_wallet = true;
|
||||
}
|
||||
|
||||
wallets.list.push(wallet_data);
|
||||
} catch (e) {
|
||||
// Something went wrong
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
<template>
|
||||
<q-item @click.native="openWallet(wallet)">
|
||||
<q-item-section avatar>
|
||||
<q-icon class="wallet-icon">
|
||||
<svg
|
||||
width="48"
|
||||
viewBox="0 0 17 16"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="si-glyph si-glyph-wallet"
|
||||
>
|
||||
<defs class="si-glyph-fill"></defs>
|
||||
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g transform="translate(1.000000, 0.000000)" fill="#434343">
|
||||
<path
|
||||
d="M7.988,10.635 L7.988,8.327 C7.988,7.578 8.561,6.969 9.267,6.969 L13.964,6.969 L13.964,5.531 C13.964,4.849 13.56,4.279 13.007,4.093 L13.007,4.094 L11.356,4.08 L11.336,4.022 L3.925,4.022 L3.784,4.07 L1.17,4.068 L1.165,4.047 C0.529,4.167 0.017,4.743 0.017,5.484 L0.017,13.437 C0.017,14.269 0.665,14.992 1.408,14.992 L12.622,14.992 C13.365,14.992 13.965,14.316 13.965,13.484 L13.965,12.031 L9.268,12.031 C8.562,12.031 7.988,11.384 7.988,10.635 L7.988,10.635 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M14.996,8.061 L14.947,8.061 L9.989,8.061 C9.46,8.061 9.031,8.529 9.031,9.106 L9.031,9.922 C9.031,10.498 9.46,10.966 9.989,10.966 L14.947,10.966 L14.996,10.966 C15.525,10.966 15.955,10.498 15.955,9.922 L15.955,9.106 C15.955,8.528 15.525,8.061 14.996,8.061 L14.996,8.061 Z M12.031,10.016 L9.969,10.016 L9.969,9 L12.031,9 L12.031,10.016 L12.031,10.016 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M3.926,4.022 L10.557,1.753 L11.337,4.022 L12.622,4.022 C12.757,4.022 12.885,4.051 13.008,4.092 L11.619,0.051 L1.049,3.572 L1.166,4.048 C1.245,4.033 1.326,4.023 1.408,4.023 L3.926,4.023 L3.926,4.022 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label class="wallet-name" caption>{{ wallet.name }}</q-item-label>
|
||||
<q-item-label class="monospace ellipsis" caption>{{
|
||||
wallet.address
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<ContextMenu
|
||||
:menu-items="menuItems"
|
||||
@openWallet="openWallet(wallet)"
|
||||
@copyAddress="copyAddress(wallet.address)"
|
||||
/>
|
||||
</q-item>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
export default {
|
||||
name: "WalletListItem",
|
||||
props: {
|
||||
wallet: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
openWallet: {
|
||||
type: Function,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
info: state => state.gateway.wallet.info
|
||||
}),
|
||||
methods: {
|
||||
copyAddress() {
|
||||
event.stopPropagation();
|
||||
for (let i = 0; i < event.path.length; i++) {
|
||||
if (event.path[i].tagName == "BUTTON") {
|
||||
event.path[i].blur();
|
||||
break;
|
||||
}
|
||||
}
|
||||
clipboard.writeText(this.wallet.address);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 1000,
|
||||
message: this.$t("notification.positive.addressCopied")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
|
@ -516,6 +516,8 @@ export default {
|
|||
"Purchase or update an ONS record. If you purchase a name, it may take a minute or two for it to show up in the list.",
|
||||
onsDescription:
|
||||
"Here you can find all the ONS names owned by this wallet. Decrypting a record you own will return the name and value of that ONS record.",
|
||||
hardwareWallet: "Hardware wallet",
|
||||
hardwareWallets: "Hardware wallets",
|
||||
loadingSettings: "Loading settings",
|
||||
oxenBalance: "Balance",
|
||||
lokinetNameDescription:
|
||||
|
@ -545,6 +547,7 @@ export default {
|
|||
recentIncomingTransactionsToAddress:
|
||||
"Recent incoming transactions to this address",
|
||||
recentTransactionsWithAddress: "Recent transactions with this address",
|
||||
regularWallets: "Regular wallets",
|
||||
rescanModalDescription:
|
||||
"Select full rescan or rescan of spent outputs only.",
|
||||
saveSeedWarning: "Please copy and save these in a secure location!",
|
||||
|
|
|
@ -50,12 +50,32 @@
|
|||
/>
|
||||
</OxenField>
|
||||
|
||||
<q-field class="q-pb-sm">
|
||||
<q-checkbox
|
||||
v-model="wallet.hardware_wallet"
|
||||
:label="$t('strings.hardwareWallet')"
|
||||
/>
|
||||
</q-field>
|
||||
|
||||
<OxenField
|
||||
v-if="!wallet.hardware_wallet"
|
||||
:label="$t('fieldLabels.seedLanguage')"
|
||||
>
|
||||
<q-select
|
||||
v-model="wallet.language"
|
||||
:options="languageOptions"
|
||||
:dark="theme == 'dark'"
|
||||
hide-underline
|
||||
/>
|
||||
</OxenField>
|
||||
|
||||
<q-field>
|
||||
<q-btn
|
||||
class="submit-button"
|
||||
color="primary"
|
||||
:label="$t('buttons.createWallet')"
|
||||
@click="create"
|
||||
/>
|
||||
</q-field>
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
@ -88,7 +108,8 @@ export default {
|
|||
name: "",
|
||||
language: languageOptions[0].value,
|
||||
password: "",
|
||||
password_confirm: ""
|
||||
password_confirm: "",
|
||||
hardware_wallet: false
|
||||
},
|
||||
languageOptions
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<q-page>
|
||||
<q-list class="wallet-list" no-border :dark="theme == 'dark'">
|
||||
<template v-if="wallets.list.length">
|
||||
<q-list class="wallet-list" link no-border :dark="theme == 'dark'">
|
||||
<template v-if="wallet_list.length">
|
||||
<div class="header row justify-between items-center">
|
||||
<div class="header-title">
|
||||
{{ $t("titles.yourWallets") }}
|
||||
|
@ -30,61 +30,28 @@
|
|||
</q-btn>
|
||||
</div>
|
||||
<div class="hr-separator" />
|
||||
<q-item
|
||||
v-for="wallet in wallets.list"
|
||||
<!-- Hardware wallets -->
|
||||
<q-list-header v-if="hardware_wallets.length">{{
|
||||
$t("strings.hardwareWallets")
|
||||
}}</q-list-header>
|
||||
<WalletListItem
|
||||
v-for="wallet in hardware_wallets"
|
||||
:key="`${wallet.address}-${wallet.name}`"
|
||||
@click.native="openWallet(wallet)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon class="wallet-icon">
|
||||
<svg
|
||||
width="48"
|
||||
viewBox="0 0 17 16"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
class="si-glyph si-glyph-wallet"
|
||||
>
|
||||
<defs class="si-glyph-fill"></defs>
|
||||
<g
|
||||
stroke="none"
|
||||
stroke-width="1"
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
>
|
||||
<g transform="translate(1.000000, 0.000000)" fill="#434343">
|
||||
<path
|
||||
d="M7.988,10.635 L7.988,8.327 C7.988,7.578 8.561,6.969 9.267,6.969 L13.964,6.969 L13.964,5.531 C13.964,4.849 13.56,4.279 13.007,4.093 L13.007,4.094 L11.356,4.08 L11.336,4.022 L3.925,4.022 L3.784,4.07 L1.17,4.068 L1.165,4.047 C0.529,4.167 0.017,4.743 0.017,5.484 L0.017,13.437 C0.017,14.269 0.665,14.992 1.408,14.992 L12.622,14.992 C13.365,14.992 13.965,14.316 13.965,13.484 L13.965,12.031 L9.268,12.031 C8.562,12.031 7.988,11.384 7.988,10.635 L7.988,10.635 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M14.996,8.061 L14.947,8.061 L9.989,8.061 C9.46,8.061 9.031,8.529 9.031,9.106 L9.031,9.922 C9.031,10.498 9.46,10.966 9.989,10.966 L14.947,10.966 L14.996,10.966 C15.525,10.966 15.955,10.498 15.955,9.922 L15.955,9.106 C15.955,8.528 15.525,8.061 14.996,8.061 L14.996,8.061 Z M12.031,10.016 L9.969,10.016 L9.969,9 L12.031,9 L12.031,10.016 L12.031,10.016 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
<path
|
||||
d="M3.926,4.022 L10.557,1.753 L11.337,4.022 L12.622,4.022 C12.757,4.022 12.885,4.051 13.008,4.092 L11.619,0.051 L1.049,3.572 L1.166,4.048 C1.245,4.033 1.326,4.023 1.408,4.023 L3.926,4.023 L3.926,4.022 Z"
|
||||
class="si-glyph-fill"
|
||||
></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</q-icon>
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
<q-item-label class="wallet-name" caption>{{
|
||||
wallet.name
|
||||
}}</q-item-label>
|
||||
<q-item-label class="monospace ellipsis" caption>{{
|
||||
wallet.address
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<ContextMenu
|
||||
:menu-items="menuItems"
|
||||
@openWallet="openWallet(wallet)"
|
||||
@copyAddress="copyAddress(wallet.address)"
|
||||
:wallet="wallet"
|
||||
:open-wallet="openWallet"
|
||||
/>
|
||||
</q-item>
|
||||
<q-separator />
|
||||
<!-- Regular wallets -->
|
||||
<q-list-header v-if="hardware_wallets.length">{{
|
||||
$t("strings.regularWallets")
|
||||
}}</q-list-header>
|
||||
<WalletListItem
|
||||
v-for="wallet in regular_wallets"
|
||||
:key="`${wallet.address}-${wallet.name}`"
|
||||
:wallet="wallet"
|
||||
:open-wallet="openWallet"
|
||||
/>
|
||||
|
||||
<q-item-separator />
|
||||
</template>
|
||||
<template v-else>
|
||||
<q-item
|
||||
|
@ -102,27 +69,24 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const { clipboard } = require("electron");
|
||||
import { mapState } from "vuex";
|
||||
import ContextMenu from "components/menus/contextmenu";
|
||||
import WalletListItem from "components/wallet_list_item";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ContextMenu
|
||||
},
|
||||
data() {
|
||||
const menuItems = [
|
||||
{ action: "openWallet", i18n: "menuItems.openWallet" },
|
||||
{ action: "copyAddress", i18n: "menuItems.copyAddress" }
|
||||
];
|
||||
return {
|
||||
menuItems
|
||||
};
|
||||
WalletListItem
|
||||
},
|
||||
computed: mapState({
|
||||
theme: state => state.gateway.app.config.appearance.theme,
|
||||
wallets: state => state.gateway.wallets,
|
||||
wallet_list: state => state.gateway.wallets.list,
|
||||
status: state => state.gateway.wallet.status,
|
||||
hardware_wallets() {
|
||||
return this.wallet_list.filter(w => w.hardware_wallet);
|
||||
},
|
||||
regular_wallets() {
|
||||
return this.wallet_list.filter(w => !w.hardware_wallet);
|
||||
},
|
||||
actions() {
|
||||
// TODO: Add this in once LOKI has the functionality
|
||||
// <q-item @click.native="restoreViewWallet()">
|
||||
|
@ -245,14 +209,6 @@ export default {
|
|||
},
|
||||
importLegacyWallet() {
|
||||
this.$router.replace({ path: "wallet-select/import-legacy" });
|
||||
},
|
||||
copyAddress(address) {
|
||||
clipboard.writeText(address);
|
||||
this.$q.notify({
|
||||
type: "positive",
|
||||
timeout: 1000,
|
||||
message: this.$t("notification.positive.addressCopied")
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,9 +33,11 @@ export default {
|
|||
height: 0,
|
||||
balance: 0,
|
||||
unlocked_balance: 0,
|
||||
view_only: false,
|
||||
hardware_wallet: false,
|
||||
accrued_balance: 0,
|
||||
accrued_balance_next_payout: 0,
|
||||
view_only: false
|
||||
accrued_balance_next_payout: 0
|
||||
|
||||
},
|
||||
secret: {
|
||||
mnemonic: "",
|
||||
|
|
Loading…
Reference in New Issue