OSDN Git Service

update mnemonic function
authorZhiting Lin <zlin035@uottawa.ca>
Wed, 29 Jul 2020 01:55:19 +0000 (09:55 +0800)
committerZhiting Lin <zlin035@uottawa.ca>
Wed, 29 Jul 2020 01:55:19 +0000 (09:55 +0800)
src/assets/language/cn.js
src/models/account.js
src/prompt.js
src/router.js
src/store/actions.js
src/store/store.js
src/utils/Keychain.js
src/views/welcome/creation.vue
src/views/welcome/mnemonic.vue [new file with mode: 0644]
src/views/welcome/verifyMnemonic.vue [new file with mode: 0644]

index bf83683..47e4984 100644 (file)
@@ -191,8 +191,18 @@ const cn = {
     inputPass: '请输入密码',
     agreeService:'请阅读并同意使用条款。'
   },
+  mnemonic:{
+    "title":"备份助记词",
+    "hint":"请牢记助记词,一旦丢失您的资产将无法找回!"
+  },
+  verifyMnemonic:{
+    "title":"验证助记词",
+    "hint":"请按顺序输入助记词,单词中间用空格隔开",
+  },
   error:{
-    BTM0000: '必填项'
+    BTM0000: '必填项',
+    BTM0001:'请输入助记词',
+    BTM0002:'助记词验证失败,请输入正确助记词。',
   },
   help: {
     title: '帮助',
index 52b2fc6..d435b83 100644 (file)
@@ -9,31 +9,28 @@ let account = {
 
 account.create = function(accountAlias, keyAlias, passwd, context) {
   let retPromise = new Promise((resolve, reject) => {
-    if(!keyAlias){
+    if (!keyAlias) {
       keyAlias = `${accountAlias}-key-${uuid.v4()}`
     }
 
     const _bytom = context.bytom.clone();
-    bytom.keys
-      .createKey(keyAlias, passwd)
-      .then(res => {
-        _bytom.keychain.keys[keyAlias] = res
-        context[Actions.UPDATE_STORED_BYTOM](_bytom).then(() => {
-            bytom.accounts
-              .createAccountUseServer(res.xpub, accountAlias)
-              .then(ret => {
-                resolve(ret)
-              })
-              .catch(error => {
-                reject(error)
-              })
-          })
-          .catch(error => {
-            reject(error)
-          })
+    const res = bytom.keys.createKey(keyAlias, passwd)
+    bytom.accounts.createNewAccount(res.xpub).then(ret => {
+      let resultObj =  Object.assign(res, ret)
+      resultObj.alias = accountAlias
+      resultObj.keyAlias = keyAlias
+
+      _bytom.keychain.pairs[accountAlias] = resultObj
+      _bytom.currentAccount = resultObj
 
-        });
+      context[Actions.UPDATE_STORED_BYTOM](_bytom).then(() => {
+        resolve(ret)
+      })
+        .catch(error => {
+          reject(error)
+        })
 
+    })
   })
   return retPromise
 }
index 36b17d8..dfc5f5d 100644 (file)
@@ -21,7 +21,6 @@ import messages, { getLanguage } from '@/assets/language'
 import '@/assets/style.css'
 import Vuelidate from "vuelidate";
 
-
 store.dispatch(Actions.LOAD_BYTOM).then(() => {
   Vue.use(VueI18n)
   const i18n = new VueI18n({
index 721302d..5b073ec 100644 (file)
@@ -214,6 +214,22 @@ const routers = [
     }
   },
   {
+    path: '/mnemonic',
+    name: 'welcome-mnemonic',
+    meta: { title: '备份助记词' },
+    component: resolve => {
+      require(['@/views/welcome/mnemonic.vue'], resolve)
+    }
+  },
+  {
+    path: '/verify-mnemonic',
+    name: 'welcome-verify-mnemonic',
+    meta: { title: '验证助记词' },
+    component: resolve => {
+      require(['@/views/welcome/verifyMnemonic.vue'], resolve)
+    }
+  },
+  {
     path: '/import',
     name: 'welcome-import',
     meta: { title: '创建账户' },
index e41b89f..0008588 100644 (file)
@@ -59,19 +59,15 @@ export const actions = {
             const bytom = Bytom.fromJson(state.bytom);
             bytom.settings.network = network;
             account.setupNet(`${network}`)
-            account.list().then(accounts => {
-              bytom.accountList = accounts;
-              if (accounts.length > 0) {
-                bytom.currentAccount = accounts[0];
-              }
+            bytom.settings.login = true
 
-              bytom.settings.login = true
-              bytom.settings.currency = "inCny"
-              bytom.settings.netType = ''
-              dispatch(Actions.UPDATE_STORED_BYTOM, bytom).then(_bytom => {
-                  dispatch(Actions.SET_BYTOM, Bytom.fromJson(_bytom));
-                  resolve();
-              })
+            const language = bytom.settings.language
+          
+            bytom.settings.currency = language ==='en'?'inUsd':"inCny"
+            bytom.settings.netType = ''
+            dispatch(Actions.UPDATE_STORED_BYTOM, bytom).then(_bytom => {
+                dispatch(Actions.SET_BYTOM, Bytom.fromJson(_bytom));
+                resolve();
             })
 
         })
index 8526a19..e85c520 100644 (file)
@@ -26,7 +26,7 @@ const getters = {
     language:state => state.bytom.settings.language,
     login:state => state.bytom.settings.login,
     currency:state => state.bytom.settings.currency,
-    keys: state => state.bytom.keychain.keys,
+    pairs: state => state.bytom.keychain.pairs,
 
     // FOR PROMPTS ONLY
     messages:state => state.prompt.data.messages || [],
index 6189cca..f8bbe32 100644 (file)
@@ -1,15 +1,15 @@
 export default class Keychain {
 
   constructor(){
-    this.keys = {};
+    this.pairs = {};
   }
 
   static placeholder(){ return new Keychain(); }
   static fromJson(json){
     let p = Object.assign(this.placeholder(), json);
-    if(json.hasOwnProperty('keys')) p.keys = json.keys;
+    if(json.hasOwnProperty('pairs')) p.pairs = json.pairs;
     return p;
   }
 
-  findIdentity(publicKey){ return Object.values(this.keys).find(id => id.xpub === publicKey); }
+  findIdentity(publicKey){ return Object.values(this.pairs).find(id => id.xpub === publicKey); }
 }
index 4012030..a8c5e50 100644 (file)
@@ -175,13 +175,13 @@ import * as Actions from '@/store/constants';
 import { required, sameAs } from "vuelidate/lib/validators";
 
 
-let mainNet = null;
+let testNet = null;
 export default {
     name: "",
     data() {
         return {
             nets: [],
-            selected: mainNet,
+            selected: testNet,
             formItem: {
                 accAlias: "",
                 passwd1: "",
@@ -296,7 +296,7 @@ export default {
               this[Actions.CREATE_NEW_BYTOM](this.selected.value).then(() =>{
                 loader.hide();
                 this.formItem = {};
-                this.$router.push('/');
+                this.$router.push('/mnemonic');
               });
             }).catch(err => {
               loader.hide();
@@ -344,14 +344,14 @@ export default {
         }
     },
     mounted() {
-        mainNet = { label: this.$t('main.mainNet'), value: "mainnet" };
-        this.nets = [mainNet];
+        testNet = { label: this.$t('main.testNet'), value: "testnet" };
+        this.nets = [testNet];
         if (this.net != undefined) {
-            if (this.net == "mainnet") {
-                this.selected = mainNet;
+            if (this.net == "testnet") {
+                this.selected = testNet;
             }
         } else {
-            this.selected = mainNet;
+            this.selected = testNet;
         }
         account.setupNet(`${this.selected.value}`);
         this.i18n = getLanguage(this.language);
diff --git a/src/views/welcome/mnemonic.vue b/src/views/welcome/mnemonic.vue
new file mode 100644 (file)
index 0000000..60ba584
--- /dev/null
@@ -0,0 +1,108 @@
+<style scoped>
+
+.header {
+  position: relative;
+  margin:40px 0px 20px;
+  line-height: 37px;
+}
+.header p{
+  font-size: 16px;
+  color: rgba(255,255,255,0.5);
+  padding-top: 5px;
+}
+.container{
+  position: relative;
+  margin-top: 24px;
+}
+  .form-checkbox input{
+    margin-left:0px;
+  }
+  .topbar a{
+    position: fixed;
+    top: 10px;
+    right: 20px;
+  }
+  .topbar a i{
+    font-size: 25px;
+    color: white;
+  }
+  .welcome-title{
+    margin-top: 20px;
+  }
+  .btn-round{
+    padding: 15px 2px;
+  }
+
+  .mnemonic{
+    font-size: 16px;
+    width: 33%;
+    display: inline-block;
+    font-family: Roboto;
+    font-style: normal;
+    font-weight: 500;
+    text-align: center;
+    color: rgba(0, 0, 0, 0.88);
+    margin: 10px 0;
+  }
+
+  .mnemnonic-box{
+    background: #FAFAFA;
+    border: 1px solid #EBEBEB;
+    box-sizing: border-box;
+    border-radius: 8px;
+    word-break: break-all;
+    padding: 10px;
+    margin:12px 0;
+  }
+
+  .hint{
+    font-size: 14px;
+    color: rgba(0, 0, 0, 0.64);
+  }
+</style>
+
+<template>
+  <div>
+    <div class="warp bg-white">
+      <div class="header color-black">
+        <BackButton/>
+        <h1>
+          <div class="welcome-title">{{ $t('mnemonic.title')}}</div>
+        </h1>
+      </div>
+      <div class="divider"></div>
+      <div class="container">
+          <div>
+            <p class="hint">{{ $t('mnemonic.hint')}}</p>
+            <div class="mnemnonic-box">
+                <span class="mnemonic" v-for="n in mnemonic">{{ n }}</span>
+            </div>
+          </div>
+          <div>
+            <div class="btn btn-primary btn-round float-right" @click="$router.push({ name: 'welcome-verify-mnemonic' })"><i class="iconfont icon-right-arrow"></i></div>
+          </div>
+        </div>
+     </div>
+      <Footer/>
+  </div>
+</template>
+
+<script>
+import { getLanguage } from '@/assets/language'
+import { mapActions, mapGetters, mapState } from 'vuex'
+
+export default {
+    name: "",
+    computed: {
+        mnemonic: function () {
+            return this.currentAccount.mnemonic.split(' ')
+        },
+      ...mapState([
+        'bytom'
+      ]),
+      ...mapGetters([
+        'currentAccount'
+      ])
+    },
+};
+</script>
diff --git a/src/views/welcome/verifyMnemonic.vue b/src/views/welcome/verifyMnemonic.vue
new file mode 100644 (file)
index 0000000..0c47181
--- /dev/null
@@ -0,0 +1,166 @@
+<style scoped>
+
+.header {
+  position: relative;
+  margin:40px 0px 20px;
+  line-height: 37px;
+}
+.header p{
+  font-size: 16px;
+  color: rgba(255,255,255,0.5);
+  padding-top: 5px;
+}
+.container{
+  position: relative;
+  margin-top: 24px;
+}
+
+  .container{
+    position: relative;
+  }
+  .form-item{
+    margin: 10px 0;
+  }
+  .topbar a{
+    position: fixed;
+    top: 10px;
+    right: 20px;
+  }
+  .topbar a i{
+    font-size: 25px;
+    color: white;
+  }
+  .welcome-title{
+    margin-top: 20px;
+  }
+  .btn-round{
+    padding: 15px 2px;
+  }
+
+  .textarea{
+    width: calc(100% - 40px);
+    min-height: 213px;
+    background: #FAFAFA;
+    border-radius: 8px;
+    border: none;
+    padding: 20px;
+  }
+</style>
+
+<template>
+  <div>
+    <div class="warp bg-white">
+      <div class="header color-black">
+        <BackButton/>
+        <h1>
+          <div class="welcome-title">{{ $t('verifyMnemonic.title')}}</div>
+        </h1>
+      </div>
+      <div class="divider"></div>
+      <div class="container">
+          <div class="form">
+            <div class="form-item">
+                  <div :class="[formItemContent, { 'error': $v.inputMnemonic.$error }]">
+                      <textarea type="text"
+                                class="textarea"
+                             :placeholder="$t('verifyMnemonic.hint')"
+                             id="inputMnemonic"
+                             name="inputMnemonic"
+                             ref="inputMnemonic"
+                             v-model="$v.inputMnemonic.$model"
+                             autofocus />
+                  </div>
+              </div>
+          </div>
+          <div>
+            <div class="btn btn-primary btn-round float-right" @click="verify"><i class="iconfont icon-right-arrow"></i></div>
+          </div>
+        </div>
+     </div>
+      <Footer/>
+  </div>
+</template>
+
+<script>
+import account from "../../models/account";
+import { getLanguage } from '@/assets/language'
+import { mapActions, mapGetters, mapState } from 'vuex'
+import * as Actions from '@/store/constants';
+import { required } from "vuelidate/lib/validators";
+
+
+export default {
+    name: "",
+    data() {
+        return {
+            inputMnemonic:''
+        };
+    },
+  validations: {
+    inputMnemonic: {
+        required,
+    }
+  },
+    computed: {
+        formItemLabel: function () {
+            if (this.i18n == "cn") {
+                return "form-item-label form-item-label-cn";
+            } else if (this.i18n == "en") {
+                return "form-item-label";
+            }
+            return "form-item-label form-item-label-cn";
+        },
+        formItemContent: function () {
+            if (this.i18n == "cn") {
+                return "form-item-content content-cn";
+            } else if (this.i18n == "en") {
+                return "form-item-content content";
+            }
+            return "form-item-label form-item-label-cn";
+        },
+      ...mapState([
+        'bytom'
+      ]),
+      ...mapGetters([
+        'currentAccount'
+      ])
+    },
+    props: {
+        i18n: {
+            type: String,
+            default: 'cn',
+        }
+    },
+    methods: {
+        verify: function () {
+          this.$v.$touch();
+          if (this.$v.$invalid) {
+            const inputMnemonic = this.$v.inputMnemonic
+              if (inputMnemonic.$error) {
+
+                this.$toast.error(
+                  this.$t("error.BTM0001")
+                );
+                this.$refs['inputMnemonic'].focus();
+              }
+          } else {
+            const formMnemonic = this.inputMnemonic.trim()
+
+            if (formMnemonic !== this.currentAccount.mnemonic) {
+              this.$toast.error(
+                this.$t("error.BTM0002")
+              );
+              return;
+            }
+
+            this.$router.push('/');
+          }
+        },
+        ...mapActions([
+          Actions.CREATE_NEW_BYTOM,
+          Actions.IMPORT_BYTOM,
+          Actions.UPDATE_STORED_BYTOM
+        ])
+    }
+};
+</script>