WIP: adding Lokinet name reg to gui wallet

This commit is contained in:
Kyle Zsembery 2020-10-06 14:11:17 +11:00
parent 6acbb0b650
commit 90e38c81d7
11 changed files with 234 additions and 105 deletions

View File

@ -1060,7 +1060,7 @@ export class WalletRPC {
Get a LNS record associated with the given name
*/
async getLNSRecord(type, name) {
const types = ["session"]; // We currently only support session
const types = ["session", "lokinet"]; // We currently only support session and lokinet
if (!types.includes(type)) return null;
if (!name || name.trim().length === 0) return null;
@ -1352,6 +1352,7 @@ export class WalletRPC {
// submits the transaction to the blockchain, irreversible from here
async relayTransaction(metadataList, isBlink, addressSave, note, isSweepAll) {
console.log("Relay transaction called");
// for a sweep these don't exist
let address = "";
let payment_id = "";
@ -1362,7 +1363,8 @@ export class WalletRPC {
address_book = addressSave.address_book;
}
let blink = isBlink;
console.log("metadatalist is here:");
console.log(metadataList);
let failed = false;
let errorMessage = "Failed to relay transaction";
@ -1370,13 +1372,14 @@ export class WalletRPC {
for (const hex of metadataList) {
const params = {
hex,
blink
blink: isBlink
};
// don't try submit more txs if a prev one failed
if (failed) break;
try {
const data = await this.sendRPC("relay_tx", params);
if (data.hasOwnProperty("error")) {
console.log("rpc return errored, set the error message");
errorMessage = data.error.message || errorMessage;
failed = true;
break;
@ -1386,11 +1389,13 @@ export class WalletRPC {
this.saveTxNotes(tx_hash, note);
}
} else {
console.log("invalid format of relay_tx");
errorMessage = "Invalid format of relay_tx RPC return message";
failed = true;
break;
}
} catch (e) {
console.log("Failed in teh try block of relay");
failed = true;
errorMessage = e.toString();
}

View File

@ -1,8 +1,31 @@
<template>
<div class="lns-input-form">
<!-- Type -->
<div class="col q-mt-sm">
<LokiField
:label="$t('fieldLabels.lnsType')"
:disable="disableName"
:error="$v.record.name.$error"
>
<q-select
v-model.trim="record.type"
emit-value
map-options
:options="typeOptions"
:dark="theme == 'dark'"
:disable="disableName"
borderless
dense
/>
</LokiField>
</div>
<!-- Name -->
<div class="col q-mt-sm">
<LokiField :label="$t('fieldLabels.name')" :disable="disableName" :error="$v.record.name.$error">
<LokiField
:label="$t('fieldLabels.name')"
:disable="disableName"
:error="$v.record.name.$error"
>
<q-input
v-model.trim="record.name"
:dark="theme == 'dark'"
@ -10,6 +33,7 @@
:disable="disableName"
borderless
dense
:suffix="record.type === 'session' ? '' : '.loki'"
@blur="$v.record.name.$touch"
/>
</LokiField>
@ -17,7 +41,11 @@
<!-- Value (Session ID, Wallet Address or .loki address) -->
<div class="col q-mt-sm">
<LokiField class="q-mt-md" :label="value_field_label" :error="$v.record.value.$error">
<LokiField
class="q-mt-md"
:label="value_field_label"
:error="$v.record.value.$error"
>
<q-input
v-model.trim="record.value"
:dark="theme == 'dark'"
@ -31,7 +59,12 @@
<!-- Owner -->
<div class="col q-mt-sm">
<LokiField class="q-mt-md" :label="$t('fieldLabels.owner')" :error="$v.record.owner.$error" optional>
<LokiField
class="q-mt-md"
:label="$t('fieldLabels.owner')"
:error="$v.record.owner.$error"
optional
>
<q-input
v-model.trim="record.owner"
:dark="theme == 'dark'"
@ -45,7 +78,12 @@
<!-- Backup owner -->
<div class="col q-mt-sm">
<LokiField class="q-mt-md" :label="$t('fieldLabels.backupOwner')" :error="$v.record.backup_owner.$error" optional>
<LokiField
class="q-mt-md"
:label="$t('fieldLabels.backupOwner')"
:error="$v.record.backup_owner.$error"
optional
>
<q-input
v-model.trim="record.backup_owner"
:dark="theme == 'dark'"
@ -63,7 +101,12 @@
:label="submitLabel"
@click="submit()"
/>
<q-btn v-if="showClearButton" color="secondary" :label="$t('buttons.clear')" @click="clear()" />
<q-btn
v-if="showClearButton"
color="secondary"
:label="$t('buttons.clear')"
@click="clear()"
/>
</div>
</div>
</template>
@ -71,7 +114,12 @@
<script>
import { mapState } from "vuex";
import { required, maxLength } from "vuelidate/lib/validators";
import { address, session_id, lns_name } from "src/validators/common";
import {
address,
session_id,
lns_name,
lokinet_name
} from "src/validators/common";
import LokiField from "components/loki_field";
import WalletPassword from "src/mixins/wallet_password";
@ -103,6 +151,12 @@ export default {
}
},
data() {
const typeOptions = [
{ label: "Session ID", value: "session" },
{ label: "Lokinet Name 1 Year", value: "lokinet_1y" },
{ label: "Lokinet Name 2 Years", value: "lokinet_2y" },
{ label: "Lokinet Name 5 Year", value: "lokinet_5y" }
];
const initialRecord = {
type: "session",
name: "",
@ -112,7 +166,8 @@ export default {
};
return {
record: { ...initialRecord },
initialRecord
initialRecord,
typeOptions
};
},
computed: mapState({
@ -122,10 +177,18 @@ export default {
return this.$store.getters["gateway/isAbleToSend"];
},
value_field_label() {
return this.$t("fieldLabels.sessionId");
if (this.record.type === "session") {
return this.$t("fieldLabels.sessionId");
} else {
return "LOKINET NAME";
}
},
value_placeholder() {
return this.$t("placeholders.sessionId");
if (this.record.type === "session") {
return this.$t("placeholders.sessionId");
} else {
return "LOKINET NAME PLACEHOLDER";
}
},
owner_placeholder() {
const { owner } = this.initialRecord || {};
@ -222,7 +285,11 @@ export default {
return;
}
this.$emit("onSubmit", this.record, this.initialRecord);
console.log("Sending this record and the initial record");
console.log(this.record);
console.log(this.initialRecord);
// Send up the submission with the record
// this.$emit("onSubmit", this.record, this.initialRecord);
},
clear() {
this.$emit("onClear");
@ -249,9 +316,10 @@ export default {
validate: function(value) {
if (this.record.type === "session") {
return session_id(value);
} else {
// must be a lokinet purchase if not a session purchase
return lokinet_name(value);
}
return false;
}
},
backup_owner: {

View File

@ -1,17 +0,0 @@
<template>
<div>
<LokinetInput />
</div>
</template>
<script>
import LokinetInput from "./lokinet_input";
export default {
name: "LNSLokinet",
components: {
LokinetInput
}
};
</script>
<style></style>

View File

@ -0,0 +1,29 @@
<template>
<div class="my-lns">
<div class="q-px-md q-pt-md">
<div class="q-mb-lg description">
{{ $t("strings.myLnsDescription") }}
</div>
<LNSRecordList />
</div>
</div>
</template>
<script>
import LNSRecordList from "./lns_record_list";
export default {
name: "MyLNS",
components: {
LNSRecordList
}
};
</script>
<style lang="scss">
.my-lns {
.description {
white-space: pre-line;
}
}
</style>

View File

@ -1,18 +1,15 @@
<template>
<div>
<LNSInput ref="input" />
<LNSRecordList @onUpdate="onUpdate" />
</div>
</template>
<script>
import LNSInput from "./lns_input";
import LNSRecordList from "./lns_record_list";
export default {
name: "LNSSession",
name: "LNSPurchase",
components: {
LNSInput,
LNSRecordList
LNSInput
},
methods: {
onUpdate(record) {

View File

@ -1,7 +1,14 @@
<template>
<div v-if="records.length > 0" class="lns-record-list">
<div v-if="needsDecryption" class="decrypt q-pa-md row justify-between items-end">
<LokiField :label="$t('fieldLabels.decryptRecord')" :disable="decrypting" :error="$v.name.$error">
<div
v-if="needsDecryption"
class="decrypt q-pa-md row justify-between items-end"
>
<LokiField
:label="$t('fieldLabels.decryptRecord')"
:disable="decrypting"
:error="$v.name.$error"
>
<q-input
v-model.trim="name"
:dark="theme == 'dark'"
@ -13,11 +20,20 @@
/>
</LokiField>
<div class="btn-wrapper q-ml-md row items-center">
<q-btn color="primary" :label="$t('buttons.decrypt')" :loading="decrypting" @click="decrypt()" />
<q-btn
color="primary"
:label="$t('buttons.decrypt')"
:loading="decrypting"
@click="decrypt()"
/>
</div>
</div>
<q-list link no-border :dark="theme == 'dark'" class="loki-list">
<q-item v-for="record in records" :key="record.name_hash" class="loki-list-item">
<q-item
v-for="record in records"
:key="record.name_hash"
class="loki-list-item"
>
<q-item-section class="type" avatar>
<q-icon :name="isLocked(record) ? 'lock' : 'lock_open'" size="24px" />
</q-item-section>
@ -25,7 +41,9 @@
<q-item-label :class="bindClass(record)">
{{ isLocked(record) ? record.name_hash : record.name }}
</q-item-label>
<q-item-label v-if="!isLocked(record)">{{ record.value }}</q-item-label>
<q-item-label v-if="!isLocked(record)">{{
record.value
}}</q-item-label>
</q-item-section>
<q-item-section side class="height">
<template v-if="isLocked(record)">
@ -33,7 +51,11 @@
</template>
<template v-else>
<q-item-section>
<q-btn color="secondary" :label="$t('buttons.update')" @click="onUpdate(record)" />
<q-btn
color="secondary"
:label="$t('buttons.update')"
@click="onUpdate(record)"
/>
</q-item-section>
</template>
</q-item-section>
@ -42,10 +64,17 @@
</q-item-section>
<ContextMenu
:menu-items="validMenuItems(record)"
@ownerCopy="copy(record.owner, $t('notification.positive.ownerCopied'))"
@ownerCopy="
copy(record.owner, $t('notification.positive.ownerCopied'))
"
@nameCopy="copy(record.name, $t('notification.positive.nameCopied'))"
@copyValue="copyValue(record)"
@backupOwnerCopy="copy(record.backup_owner, $t('notification.positive.backupOwnerCopied'))"
@backupOwnerCopy="
copy(
record.backup_owner,
$t('notification.positive.backupOwnerCopied')
)
"
/>
</q-item>
</q-list>
@ -90,7 +119,10 @@ export default {
const ourAddresses = this.ourAddresses;
const records = state.gateway.wallet.lnsRecords;
const ourRecords = records.filter(record => {
return ourAddresses.includes(record.owner) || ourAddresses.includes(record.backup_owner);
return (
ourAddresses.includes(record.owner) ||
ourAddresses.includes(record.backup_owner)
);
});
// Sort the records by decrypted ones first, followed by non-decrypted
@ -116,7 +148,9 @@ export default {
{ action: "copyValue", i18n: this.copyValueI18nLabel(record) }
];
let menuItems = [{ action: "ownerCopy", i18n: "menuItems.copyOwner" }];
const backupOwnerItem = [{ action: "backupOwnerCopy", i18n: "menuItems.copyBackupOwner" }];
const backupOwnerItem = [
{ action: "backupOwnerCopy", i18n: "menuItems.copyBackupOwner" }
];
if (!this.isLocked(record)) {
menuItems = [...lockedItems, ...menuItems];
@ -163,7 +197,9 @@ export default {
this.$q.notify({
type: "positive",
timeout: 2000,
message: this.$t("notification.positive.decryptedLNSRecord", { name })
message: this.$t("notification.positive.decryptedLNSRecord", {
name
})
});
this.name = "";
} else {

View File

@ -1,35 +0,0 @@
<template>
<div class="lokinet-input">
<div class="q-px-md q-pt-md">
<div class="q-mb-lg description">
{{ $t("strings.lokinetNameDescription") }}
</div>
<!-- <LNSInputForm
ref="form"
:submit-label="submit_label"
:disable-name="updating"
:show-clear-button="updating"
:disable-submit-button="disable_submit_button"
@onSubmit="onSubmit"
@onClear="onClear"
/> -->
<!-- <q-inner-loading :showing="lns_status.sending" :dark="theme == 'dark'">
<q-spinner color="primary" size="30" />
</q-inner-loading> -->
</div>
</div>
</template>
<script>
export default {
name: "LokinetInput"
};
</script>
<style lang="scss">
.lokinet-input {
.description {
white-space: pre-line;
}
}
</style>

View File

@ -319,6 +319,7 @@ export default {
}
},
onConfirmTransaction() {
console.log("start the loading spinner after confirm");
// put the loading spinner up
this.$store.commit("gateway/set_sweep_all_status", {
code: DO_NOTHING,
@ -329,12 +330,15 @@ export default {
const metadataList = this.confirmFields.metadataList;
const isBlink = this.confirmFields.isBlink;
console.log("confirming the transaction with data");
const relayTxData = {
metadataList,
isBlink,
isSweepAll: true
};
console.log(relayTxData);
// Commit the transaction
this.$gateway.send("wallet", "relay_tx", relayTxData);
},
@ -368,6 +372,8 @@ export default {
.onCancel(() => {});
},
buildDialogFieldsSweepAll(txData) {
console.log("Building the confirm box fields with data:");
console.log(txData);
this.confirmFields = this.buildDialogFields(txData);
},
areButtonsEnabled() {

View File

@ -8,7 +8,12 @@
<template v-else>
<q-infinite-scroll ref="scroller" @load="loadMore">
<q-list link no-border :dark="theme == 'dark'" class="loki-list tx-list">
<q-list
link
no-border
:dark="theme == 'dark'"
class="loki-list tx-list"
>
<q-item
v-for="tx in tx_list_paged"
:key="`${tx.txid}-${tx.type}`"
@ -27,7 +32,11 @@
</q-item-label>
<q-item-section class="meta">
<q-item-label>
<timeago :datetime="tx.timestamp * 1000" :auto-update="60" :locale="$i18n.locale" />
<timeago
:datetime="tx.timestamp * 1000"
:auto-update="60"
:locale="$i18n.locale"
/>
</q-item-label>
<q-item-label caption>{{ formatHeight(tx) }}</q-item-label>
</q-item-section>
@ -191,6 +200,8 @@ export default {
const all_in = ["in", "pool", "miner", "snode", "gov"];
const all_out = ["out", "pending", "stake"];
const all_pending = ["pending", "pool"];
// just stop logging errors due to dup txs so I can work on LNS without interruption
// this.tx_list_filtered = [];
this.tx_list_filtered = this.tx_list.filter(tx => {
let valid = true;
@ -228,7 +239,9 @@ export default {
}
if (this.toIncomingAddressIndex !== -1) {
valid = tx.hasOwnProperty("subaddr_index") && tx.subaddr_index.minor == this.toIncomingAddressIndex;
valid =
tx.hasOwnProperty("subaddr_index") &&
tx.subaddr_index.minor == this.toIncomingAddressIndex;
return valid;
}
@ -258,11 +271,17 @@ export default {
return this.address_book.find(book => book.address === address);
},
pageTxList() {
this.tx_list_paged = this.tx_list_filtered.slice(0, this.limit !== -1 ? this.limit : this.page * 24 + 24);
this.tx_list_paged = this.tx_list_filtered.slice(
0,
this.limit !== -1 ? this.limit : this.page * 24 + 24
);
},
loadMore: function(index, done) {
this.page = index;
if (this.limit !== -1 || this.tx_list_filtered.length < this.page * 24 + 24) {
if (
this.limit !== -1 ||
this.tx_list_filtered.length < this.page * 24 + 24
) {
this.$refs.scroller.stop();
}
this.pageTxList();
@ -280,8 +299,15 @@ export default {
let confirms = Math.max(0, this.wallet_height - height);
if (height == 0) return this.$t("strings.transactions.types.pending");
if (confirms < Math.max(10, tx.unlock_time - height))
return this.$t("strings.blockHeight") + `: ${height} (${confirms} confirm${confirms == 1 ? "" : "s"})`;
else return this.$t("strings.blockHeight") + `: ${height} (${this.$t("strings.transactionConfirmed")})`;
return (
this.$t("strings.blockHeight") +
`: ${height} (${confirms} confirm${confirms == 1 ? "" : "s"})`
);
else
return (
this.$t("strings.blockHeight") +
`: ${height} (${this.$t("strings.transactionConfirmed")})`
);
},
copyTxId(txid) {
clipboard.writeText(txid);

View File

@ -7,33 +7,33 @@
color="secondary"
:options="[
{
label: $t('titles.lns.sessionId'),
value: 'sessionId'
label: $t('titles.lns.purchase'),
value: 'purchase'
},
{
label: $t('titles.lns.lokinetName'),
value: 'lokinetName'
label: $t('titles.lns.myLns'),
value: 'my_lns'
}
]"
/>
</div>
<LNSSession v-if="screen === 'sessionId'" />
<LNSLokinet v-if="screen === 'lokinetName'" />
<LNSPurchase v-if="screen === 'purchase'" />
<MyLNS v-if="screen === 'my_lns'" />
</q-page>
</template>
<script>
import LNSSession from "components/lns/lns_session";
import LNSLokinet from "components/lns/lns_lokinet";
import LNSPurchase from "components/lns/lns_purchase";
import MyLNS from "components/lns/lns_mylns";
export default {
components: {
LNSSession,
LNSLokinet
MyLNS,
LNSPurchase
},
data() {
return {
screen: "sessionId"
screen: "purchase"
};
}
};

View File

@ -6,11 +6,15 @@ export const greater_than_zero = input => {
export const payment_id = input => {
// || input.length == 16 to be re-added after rpc fixed
return input.length === 0 || (/^[0-9A-Fa-f]+$/.test(input) && input.length == 64);
return (
input.length === 0 || (/^[0-9A-Fa-f]+$/.test(input) && input.length == 64)
);
};
export const privkey = input => {
return input.length === 0 || (/^[0-9A-Fa-f]+$/.test(input) && input.length == 64);
return (
input.length === 0 || (/^[0-9A-Fa-f]+$/.test(input) && input.length == 64)
);
};
export const service_node_key = input => {
@ -18,11 +22,21 @@ export const service_node_key = input => {
};
export const session_id = input => {
return input.length == 66 && /^05[0-9A-Za-z]+$/.test(input);
return input.length === 66 && /^05[0-9A-Za-z]+$/.test(input);
};
export const lokinet_name = input => {
return (
input.length === 52 &&
/^[ybndrfg8ejkmcpqxot1uwisza345h769]{51}[yo]\.loki$/.test(input)
);
};
export const lns_name = input => {
return input.length === 0 || /^[a-z0-9_]([a-z0-9-_]*[a-z0-9_])?$/.test(input.toLowerCase());
return (
input.length === 0 ||
/^[a-z0-9_]([a-z0-9-_]*[a-z0-9_])?$/.test(input.toLowerCase())
);
};
export const address = (input, gateway) => {