├── .babelrc ├── .electron-vue ├── build.js ├── dev-client.js ├── dev-runner.js ├── webpack.main.config.js ├── webpack.renderer.config.js └── webpack.web.config.js ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── appveyor.yml ├── build └── icons │ ├── 256x256.png │ ├── icon.icns │ └── icon.ico ├── dist ├── electron │ └── .gitkeep └── web │ └── .gitkeep ├── package.json ├── public.js ├── screenshot ├── branches.png ├── eosforce1.png ├── eosforce2.png └── releases1.png ├── src ├── index.ejs ├── main │ ├── index.dev.js │ └── index.js └── renderer │ ├── App.vue │ ├── assets │ ├── .gitkeep │ ├── assets.png │ ├── assets_w.png │ ├── border.png │ ├── eosforce-qrcode.png │ ├── exchange.png │ ├── exchange_w.png │ ├── export.png │ ├── kefu.png │ ├── lace.png │ ├── laternode.png │ ├── laternode_w.png │ ├── loader │ │ └── producing.svg │ ├── logo.png │ ├── node.png │ ├── node_w.png │ ├── refresh.png │ ├── select_drop_arrow.svg │ ├── token.png │ ├── token_w.png │ ├── user_head.png │ ├── vote.png │ ├── vote │ │ ├── avaliable.png │ │ ├── redeem.png │ │ ├── reward.png │ │ ├── transform.png │ │ └── vote.png │ └── vote_w.png │ ├── components │ ├── ConfirmModal.vue │ ├── Message.js │ ├── PromptModal.vue │ └── select_pane.vue │ ├── constants │ ├── config.constants.js │ └── types.constants.js │ ├── main.js │ ├── menu.js │ ├── messages.js │ ├── router │ └── index.js │ ├── services │ ├── Eos.js │ └── Storage.js │ ├── store │ ├── index.js │ └── modules │ │ ├── AccountOverview.js │ │ ├── account.js │ │ ├── app.js │ │ ├── index.js │ │ └── wallet.js │ ├── styles │ ├── bulma.scss │ ├── common.scss │ ├── index.scss │ └── main.scss │ ├── updater.js │ ├── utils │ ├── filter.js │ ├── rules.js │ └── util.js │ └── views │ ├── account │ ├── AccountDetail.vue │ ├── AccountNew.vue │ ├── AccountOverview.vue │ ├── AccountTransfer.vue │ ├── AlternateNode.vue │ ├── BpList.vue │ ├── Claim.vue │ ├── Freeze.vue │ ├── MyFixVote.vue │ ├── Myvote.vue │ ├── NetCpu.vue │ ├── RateInstructions.vue │ ├── TokenList.vue │ ├── Transfer.vue │ ├── TransferRecord.vue │ ├── Unfreeze.vue │ ├── Unfreeze4ram.vue │ ├── UnfreezeCpuNet.vue │ ├── Vote.vue │ ├── Vote4ram.vue │ └── Vote4ramList.vue │ ├── components │ ├── CreateWalletForm.vue │ ├── ImportWalletForm.vue │ ├── concat_form.vue │ ├── os_uri.vue │ └── select.vue │ ├── entry │ └── Entry.vue │ ├── layout │ ├── PageHeader.vue │ └── PageMenu.vue │ └── wallet │ ├── CreateKey.vue │ ├── Dashboard.vue │ ├── ImportKey.vue │ ├── ImportWalletFile.vue │ ├── WalletDetail.vue │ ├── WalletImport.vue │ ├── WalletNew.vue │ └── config_node_list.vue ├── static ├── .gitkeep └── term.html ├── upgrade.md ├── yarn-error.log └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false, 3 | "env": { 4 | "main": { 5 | "presets": [ 6 | [ 7 | "env", 8 | { 9 | "targets": { "node": 7 } 10 | } 11 | ], 12 | "stage-0" 13 | ] 14 | }, 15 | "renderer": { 16 | "presets": [ 17 | [ 18 | "env", 19 | { 20 | "modules": false 21 | } 22 | ], 23 | "stage-0" 24 | ], 25 | "plugins": [ 26 | [ 27 | "component", 28 | { 29 | "libraryName": "element-ui", 30 | "styleLibraryName": "theme-chalk" 31 | } 32 | ] 33 | ] 34 | }, 35 | "web": { 36 | "presets": [ 37 | [ 38 | "env", 39 | { 40 | "modules": false 41 | } 42 | ], 43 | "stage-0" 44 | ] 45 | } 46 | }, 47 | "plugins": ["transform-runtime"] 48 | } 49 | -------------------------------------------------------------------------------- /.electron-vue/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | const { say } = require('cfonts') 6 | const chalk = require('chalk') 7 | const del = require('del') 8 | const { spawn } = require('child_process') 9 | const webpack = require('webpack') 10 | const Multispinner = require('multispinner') 11 | 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const webConfig = require('./webpack.web.config') 16 | 17 | const doneLog = chalk.bgGreen.white(' DONE ') + ' ' 18 | const errorLog = chalk.bgRed.white(' ERROR ') + ' ' 19 | const okayLog = chalk.bgBlue.white(' OKAY ') + ' ' 20 | const isCI = process.env.CI || false 21 | 22 | if (process.env.BUILD_TARGET === 'clean') clean() 23 | else if (process.env.BUILD_TARGET === 'web') web() 24 | else build() 25 | 26 | function clean () { 27 | del.sync(['build/*', '!build/icons', '!build/icons/icon.*']) 28 | console.log(`\n${doneLog}\n`) 29 | process.exit() 30 | } 31 | 32 | function build () { 33 | greeting() 34 | 35 | del.sync(['dist/electron/*', '!.gitkeep']) 36 | 37 | const tasks = ['main', 'renderer'] 38 | const m = new Multispinner(tasks, { 39 | preText: 'building', 40 | postText: 'process' 41 | }) 42 | 43 | let results = '' 44 | 45 | m.on('success', () => { 46 | process.stdout.write('\x1B[2J\x1B[0f') 47 | console.log(`\n\n${results}`) 48 | console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`) 49 | process.exit() 50 | }) 51 | 52 | pack(mainConfig).then(result => { 53 | results += result + '\n\n' 54 | m.success('main') 55 | }).catch(err => { 56 | m.error('main') 57 | console.log(`\n ${errorLog}failed to build main process`) 58 | console.error(`\n${err}\n`) 59 | process.exit(1) 60 | }) 61 | 62 | pack(rendererConfig).then(result => { 63 | results += result + '\n\n' 64 | m.success('renderer') 65 | }).catch(err => { 66 | m.error('renderer') 67 | console.log(`\n ${errorLog}failed to build renderer process`) 68 | console.error(`\n${err}\n`) 69 | process.exit(1) 70 | }) 71 | } 72 | 73 | function pack (config) { 74 | return new Promise((resolve, reject) => { 75 | webpack(config, (err, stats) => { 76 | if (err) reject(err.stack || err) 77 | else if (stats.hasErrors()) { 78 | let err = '' 79 | 80 | stats.toString({ 81 | chunks: false, 82 | colors: true 83 | }) 84 | .split(/\r?\n/) 85 | .forEach(line => { 86 | err += ` ${line}\n` 87 | }) 88 | 89 | reject(err) 90 | } else { 91 | resolve(stats.toString({ 92 | chunks: false, 93 | colors: true 94 | })) 95 | } 96 | }) 97 | }) 98 | } 99 | 100 | function web () { 101 | del.sync(['dist/web/*', '!.gitkeep']) 102 | webpack(webConfig, (err, stats) => { 103 | if (err || stats.hasErrors()) console.log(err) 104 | 105 | console.log(stats.toString({ 106 | chunks: false, 107 | colors: true 108 | })) 109 | 110 | process.exit() 111 | }) 112 | } 113 | 114 | function greeting () { 115 | const cols = process.stdout.columns 116 | let text = '' 117 | 118 | if (cols > 85) text = 'lets-build' 119 | else if (cols > 60) text = 'lets-|build' 120 | else text = false 121 | 122 | if (text && !isCI) { 123 | say(text, { 124 | colors: ['yellow'], 125 | font: 'simple3d', 126 | space: false 127 | }) 128 | } else console.log(chalk.yellow.bold('\n lets-build')) 129 | console.log() 130 | } 131 | -------------------------------------------------------------------------------- /.electron-vue/dev-client.js: -------------------------------------------------------------------------------- 1 | const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 2 | 3 | hotClient.subscribe(event => { 4 | /** 5 | * Reload browser when HTMLWebpackPlugin emits a new index.html 6 | * 7 | * Currently disabled until jantimon/html-webpack-plugin#680 is resolved. 8 | * https://github.com/SimulatedGREG/electron-vue/issues/437 9 | * https://github.com/jantimon/html-webpack-plugin/issues/680 10 | */ 11 | // if (event.action === 'reload') { 12 | // window.location.reload() 13 | // } 14 | 15 | /** 16 | * Notify `mainWindow` when `main` process is compiling, 17 | * giving notice for an expected reload of the `electron` process 18 | */ 19 | if (event.action === 'compiling') { 20 | document.body.innerHTML += ` 21 | 34 | 35 |
36 | Compiling Main Process... 37 |
38 | ` 39 | } 40 | }) 41 | -------------------------------------------------------------------------------- /.electron-vue/dev-runner.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const chalk = require('chalk') 4 | const electron = require('electron') 5 | const path = require('path') 6 | const { say } = require('cfonts') 7 | const { spawn } = require('child_process') 8 | const webpack = require('webpack') 9 | const WebpackDevServer = require('webpack-dev-server') 10 | const webpackHotMiddleware = require('webpack-hot-middleware') 11 | 12 | const mainConfig = require('./webpack.main.config') 13 | const rendererConfig = require('./webpack.renderer.config') 14 | 15 | let electronProcess = null 16 | let manualRestart = false 17 | let hotMiddleware 18 | 19 | function logStats (proc, data) { 20 | let log = '' 21 | 22 | log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`) 23 | log += '\n\n' 24 | 25 | if (typeof data === 'object') { 26 | data.toString({ 27 | colors: true, 28 | chunks: false 29 | }).split(/\r?\n/).forEach(line => { 30 | log += ' ' + line + '\n' 31 | }) 32 | } else { 33 | log += ` ${data}\n` 34 | } 35 | 36 | log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n' 37 | 38 | console.log(log) 39 | } 40 | 41 | function startRenderer () { 42 | return new Promise((resolve, reject) => { 43 | rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer) 44 | 45 | const compiler = webpack(rendererConfig) 46 | hotMiddleware = webpackHotMiddleware(compiler, { 47 | log: false, 48 | heartbeat: 2500 49 | }) 50 | 51 | compiler.plugin('compilation', compilation => { 52 | compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => { 53 | hotMiddleware.publish({ action: 'reload' }) 54 | cb() 55 | }) 56 | }) 57 | 58 | compiler.plugin('done', stats => { 59 | logStats('Renderer', stats) 60 | }) 61 | 62 | const server = new WebpackDevServer( 63 | compiler, 64 | { 65 | contentBase: path.join(__dirname, '../'), 66 | quiet: true, 67 | before (app, ctx) { 68 | app.use(hotMiddleware) 69 | ctx.middleware.waitUntilValid(() => { 70 | resolve() 71 | }) 72 | } 73 | } 74 | ) 75 | 76 | server.listen(9081) 77 | }) 78 | } 79 | 80 | function startMain () { 81 | return new Promise((resolve, reject) => { 82 | mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main) 83 | 84 | const compiler = webpack(mainConfig) 85 | 86 | compiler.plugin('watch-run', (compilation, done) => { 87 | logStats('Main', chalk.white.bold('compiling...')) 88 | hotMiddleware.publish({ action: 'compiling' }) 89 | done() 90 | }) 91 | 92 | compiler.watch({}, (err, stats) => { 93 | if (err) { 94 | console.log(err) 95 | return 96 | } 97 | 98 | logStats('Main', stats) 99 | 100 | if (electronProcess && electronProcess.kill) { 101 | manualRestart = true 102 | process.kill(electronProcess.pid) 103 | electronProcess = null 104 | startElectron() 105 | 106 | setTimeout(() => { 107 | manualRestart = false 108 | }, 5000) 109 | } 110 | 111 | resolve() 112 | }) 113 | }) 114 | } 115 | 116 | function startElectron () { 117 | electronProcess = spawn(electron, ['--inspect=5858', path.join(__dirname, '../dist/electron/main.js')]) 118 | 119 | electronProcess.stdout.on('data', data => { 120 | electronLog(data, 'blue') 121 | }) 122 | electronProcess.stderr.on('data', data => { 123 | electronLog(data, 'red') 124 | }) 125 | 126 | electronProcess.on('close', () => { 127 | if (!manualRestart) process.exit() 128 | }) 129 | } 130 | 131 | function electronLog (data, color) { 132 | let log = '' 133 | data = data.toString().split(/\r?\n/) 134 | data.forEach(line => { 135 | log += ` ${line}\n` 136 | }) 137 | if (/[0-9A-z]+/.test(log)) { 138 | console.log( 139 | chalk[color].bold('┏ Electron -------------------') + 140 | '\n\n' + 141 | log + 142 | chalk[color].bold('┗ ----------------------------') + 143 | '\n' 144 | ) 145 | } 146 | } 147 | 148 | function greeting () { 149 | const cols = process.stdout.columns 150 | let text = '' 151 | 152 | if (cols > 104) text = 'electron-vue' 153 | else if (cols > 76) text = 'electron-|vue' 154 | else text = false 155 | 156 | if (text) { 157 | say(text, { 158 | colors: ['yellow'], 159 | font: 'simple3d', 160 | space: false 161 | }) 162 | } else console.log(chalk.yellow.bold('\n electron-vue')) 163 | console.log(chalk.blue(' getting ready...') + '\n') 164 | } 165 | 166 | function init () { 167 | greeting() 168 | 169 | Promise.all([startRenderer(), startMain()]) 170 | .then(() => { 171 | startElectron() 172 | }) 173 | .catch(err => { 174 | console.error(err) 175 | }) 176 | } 177 | 178 | init() 179 | -------------------------------------------------------------------------------- /.electron-vue/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'main' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | 11 | let mainConfig = { 12 | entry: { 13 | main: path.join(__dirname, '../src/main/index.js') 14 | }, 15 | externals: [ 16 | ...Object.keys(dependencies || {}) 17 | ], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.js$/, 22 | use: 'babel-loader', 23 | exclude: /node_modules/ 24 | }, 25 | { 26 | test: /\.node$/, 27 | use: 'node-loader' 28 | } 29 | ] 30 | }, 31 | node: { 32 | __dirname: process.env.NODE_ENV !== 'production', 33 | __filename: process.env.NODE_ENV !== 'production' 34 | }, 35 | output: { 36 | filename: '[name].js', 37 | libraryTarget: 'commonjs2', 38 | path: path.join(__dirname, '../dist/electron') 39 | }, 40 | plugins: [ 41 | new webpack.NoEmitOnErrorsPlugin() 42 | ], 43 | resolve: { 44 | extensions: ['.js', '.json', '.node'] 45 | }, 46 | target: 'electron-main' 47 | } 48 | 49 | /** 50 | * Adjust mainConfig for development settings 51 | */ 52 | if (process.env.NODE_ENV !== 'production') { 53 | mainConfig.plugins.push( 54 | new webpack.DefinePlugin({ 55 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 56 | }) 57 | ) 58 | } 59 | 60 | /** 61 | * Adjust mainConfig for production settings 62 | */ 63 | if (process.env.NODE_ENV === 'production') { 64 | mainConfig.plugins.push( 65 | new BabiliWebpackPlugin(), 66 | new webpack.DefinePlugin({ 67 | 'process.env.NODE_ENV': '"production"' 68 | }) 69 | ) 70 | } 71 | 72 | module.exports = mainConfig 73 | -------------------------------------------------------------------------------- /.electron-vue/webpack.renderer.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'renderer' 4 | 5 | const path = require('path') 6 | const { dependencies } = require('../package.json') 7 | const webpack = require('webpack') 8 | 9 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 10 | const CopyWebpackPlugin = require('copy-webpack-plugin') 11 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 12 | const HtmlWebpackPlugin = require('html-webpack-plugin') 13 | 14 | /** 15 | * List of node_modules to include in webpack bundle 16 | * 17 | * Required for specific packages like Vue UI libraries 18 | * that provide pure *.vue files that need compiling 19 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals 20 | */ 21 | let whiteListedModules = ['vue', 'element-ui'] 22 | 23 | let rendererConfig = { 24 | devtool: '#cheap-module-eval-source-map', 25 | entry: { 26 | renderer: path.join(__dirname, '../src/renderer/main.js') 27 | }, 28 | externals: [ 29 | ...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d)) 30 | ], 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.css$/, 35 | use: ExtractTextPlugin.extract({ 36 | fallback: 'style-loader', 37 | use: 'css-loader' 38 | }) 39 | }, 40 | { 41 | test: /\.html$/, 42 | use: 'vue-html-loader' 43 | }, 44 | { 45 | test: /\.js$/, 46 | use: 'babel-loader', 47 | exclude: /node_modules/ 48 | }, 49 | { 50 | test: /\.node$/, 51 | use: 'node-loader' 52 | }, 53 | { 54 | test: /\.vue$/, 55 | use: { 56 | loader: 'vue-loader', 57 | options: { 58 | extractCSS: process.env.NODE_ENV === 'production', 59 | loaders: { 60 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 61 | scss: 'vue-style-loader!css-loader!sass-loader' 62 | } 63 | } 64 | } 65 | }, 66 | { 67 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 68 | use: { 69 | loader: 'url-loader', 70 | query: { 71 | limit: 10000, 72 | name: 'imgs/[name]--[folder].[ext]' 73 | } 74 | } 75 | }, 76 | { 77 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 78 | loader: 'url-loader', 79 | options: { 80 | limit: 10000, 81 | name: 'media/[name]--[folder].[ext]' 82 | } 83 | }, 84 | { 85 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 86 | use: { 87 | loader: 'url-loader', 88 | query: { 89 | limit: 10000, 90 | name: 'fonts/[name]--[folder].[ext]' 91 | } 92 | } 93 | } 94 | ] 95 | }, 96 | node: { 97 | __dirname: process.env.NODE_ENV !== 'production', 98 | __filename: process.env.NODE_ENV !== 'production' 99 | }, 100 | plugins: [ 101 | new ExtractTextPlugin('styles.css'), 102 | new HtmlWebpackPlugin({ 103 | filename: 'index.html', 104 | template: path.resolve(__dirname, '../src/index.ejs'), 105 | minify: { 106 | collapseWhitespace: true, 107 | removeAttributeQuotes: true, 108 | removeComments: true 109 | }, 110 | nodeModules: process.env.NODE_ENV !== 'production' 111 | ? path.resolve(__dirname, '../node_modules') 112 | : false 113 | }), 114 | new webpack.HotModuleReplacementPlugin(), 115 | new webpack.NoEmitOnErrorsPlugin() 116 | ], 117 | output: { 118 | filename: '[name].js', 119 | libraryTarget: 'commonjs2', 120 | path: path.join(__dirname, '../dist/electron') 121 | }, 122 | resolve: { 123 | alias: { 124 | '@': path.join(__dirname, '../src/renderer'), 125 | 'vue$': 'vue/dist/vue.esm.js' 126 | }, 127 | extensions: ['.js', '.vue', '.json', '.css', '.node'] 128 | }, 129 | target: 'electron-renderer' 130 | } 131 | 132 | /** 133 | * Adjust rendererConfig for development settings 134 | */ 135 | if (process.env.NODE_ENV !== 'production') { 136 | rendererConfig.plugins.push( 137 | new webpack.DefinePlugin({ 138 | '__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"` 139 | }) 140 | ) 141 | } 142 | 143 | /** 144 | * Adjust rendererConfig for production settings 145 | */ 146 | if (process.env.NODE_ENV === 'production') { 147 | rendererConfig.devtool = '' 148 | 149 | rendererConfig.plugins.push( 150 | new BabiliWebpackPlugin(), 151 | new CopyWebpackPlugin([ 152 | { 153 | from: path.join(__dirname, '../static'), 154 | to: path.join(__dirname, '../dist/electron/static'), 155 | ignore: ['.*'] 156 | } 157 | ]), 158 | new webpack.DefinePlugin({ 159 | 'process.env.NODE_ENV': '"production"' 160 | }), 161 | new webpack.LoaderOptionsPlugin({ 162 | minimize: true 163 | }) 164 | ) 165 | } 166 | 167 | module.exports = rendererConfig 168 | -------------------------------------------------------------------------------- /.electron-vue/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | process.env.BABEL_ENV = 'web' 4 | 5 | const path = require('path') 6 | const webpack = require('webpack') 7 | 8 | const BabiliWebpackPlugin = require('babili-webpack-plugin') 9 | const CopyWebpackPlugin = require('copy-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const HtmlWebpackPlugin = require('html-webpack-plugin') 12 | 13 | let webConfig = { 14 | devtool: '#cheap-module-eval-source-map', 15 | entry: { 16 | web: path.join(__dirname, '../src/renderer/main.js') 17 | }, 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.css$/, 22 | use: ExtractTextPlugin.extract({ 23 | fallback: 'style-loader', 24 | use: 'css-loader' 25 | }) 26 | }, 27 | { 28 | test: /\.html$/, 29 | use: 'vue-html-loader' 30 | }, 31 | { 32 | test: /\.js$/, 33 | use: 'babel-loader', 34 | include: [ path.resolve(__dirname, '../src/renderer') ], 35 | exclude: /node_modules/ 36 | }, 37 | { 38 | test: /\.vue$/, 39 | use: { 40 | loader: 'vue-loader', 41 | options: { 42 | extractCSS: true, 43 | loaders: { 44 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 45 | scss: 'vue-style-loader!css-loader!sass-loader' 46 | } 47 | } 48 | } 49 | }, 50 | { 51 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 52 | use: { 53 | loader: 'url-loader', 54 | query: { 55 | limit: 10000, 56 | name: 'imgs/[name].[ext]' 57 | } 58 | } 59 | }, 60 | { 61 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 62 | use: { 63 | loader: 'url-loader', 64 | query: { 65 | limit: 10000, 66 | name: 'fonts/[name].[ext]' 67 | } 68 | } 69 | } 70 | ] 71 | }, 72 | plugins: [ 73 | new ExtractTextPlugin('styles.css'), 74 | new HtmlWebpackPlugin({ 75 | filename: 'index.html', 76 | template: path.resolve(__dirname, '../src/index.ejs'), 77 | minify: { 78 | collapseWhitespace: true, 79 | removeAttributeQuotes: true, 80 | removeComments: true 81 | }, 82 | nodeModules: false 83 | }), 84 | new webpack.DefinePlugin({ 85 | 'process.env.IS_WEB': 'true' 86 | }), 87 | new webpack.HotModuleReplacementPlugin(), 88 | new webpack.NoEmitOnErrorsPlugin() 89 | ], 90 | output: { 91 | filename: '[name].js', 92 | path: path.join(__dirname, '../dist/web') 93 | }, 94 | resolve: { 95 | alias: { 96 | '@': path.join(__dirname, '../src/renderer'), 97 | 'vue$': 'vue/dist/vue.esm.js' 98 | }, 99 | extensions: ['.js', '.vue', '.json', '.css'] 100 | }, 101 | target: 'web' 102 | } 103 | 104 | /** 105 | * Adjust webConfig for production settings 106 | */ 107 | if (process.env.NODE_ENV === 'production') { 108 | webConfig.devtool = '' 109 | 110 | webConfig.plugins.push( 111 | new BabiliWebpackPlugin(), 112 | new CopyWebpackPlugin([ 113 | { 114 | from: path.join(__dirname, '../static'), 115 | to: path.join(__dirname, '../dist/web/static'), 116 | ignore: ['.*'] 117 | } 118 | ]), 119 | new webpack.DefinePlugin({ 120 | 'process.env.NODE_ENV': '"production"' 121 | }), 122 | new webpack.LoaderOptionsPlugin({ 123 | minimize: true 124 | }) 125 | ) 126 | } 127 | 128 | module.exports = webConfig 129 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | **/* -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module', 6 | }, 7 | env: { 8 | browser: true, 9 | node: true, 10 | }, 11 | extends: 'standard', 12 | globals: { 13 | __static: true, 14 | }, 15 | plugins: ['html'], 16 | rules: { 17 | // 语句后面必须加上分号 18 | 'semi': ['warn', 'always'], 19 | 20 | 'eqeqeq': ['warn'], 21 | // 允许换行末尾逗号 22 | 'comma-dangle': ['warn', 'only-multiline'], 23 | // 函数后不需要空格 24 | 'space-before-function-paren': ['warn'], 25 | // 允许空的 reject 26 | 'prefer-promise-reject-errors': ['warn', { allowEmptyReject: true }], 27 | // 驼峰 28 | 'camelcase': ['warn', { properties: 'never' }], 29 | // allow paren-less arrow functions 30 | 'arrow-parens': 0, 31 | 'no-unneeded-ternary': ['warn'], 32 | 'space-before-blocks': ['warn'], 33 | // allow async-await 34 | 'generator-star-spacing': 0, 35 | 'no-trailing-spaces': ["warn", { "skipBlankLines": true }], 36 | // console 警告 37 | 'no-console': ['warn', { allow: ['warn'] }], 38 | 'keyword-spacing': ['warn', { "overrides": { "if": { "after": true, "before": true}, "for": { "after": true, "before": true}, "while": { "after": true, "before": true} } }], 39 | // allow debugger during development 40 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 41 | }, 42 | }; 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/electron/* 3 | dist/web/* 4 | build/* 5 | !build/icons 6 | node_modules/ 7 | npm-debug.log 8 | npm-debug.log.* 9 | thumbs.db 10 | !.gitkeep 11 | env.config.md 12 | yarn.lock 13 | package-lock.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | } 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | osx_image: xcode8.3 2 | sudo: required 3 | dist: trusty 4 | language: c 5 | matrix: 6 | include: 7 | - os: osx 8 | - os: linux 9 | env: CC=clang CXX=clang++ npm_config_clang=1 10 | compiler: clang 11 | addons: 12 | apt: 13 | packages: 14 | - libgnome-keyring-dev 15 | - icnsutils 16 | before_install: 17 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install --no-install-recommends -y build-essential libudev-dev libusb-1.0-0-dev icnsutils graphicsmagick xz-utils; fi 18 | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then curl -o- -L https://yarnpkg.com/install.sh | bash; fi 19 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then curl -o- -L https://yarnpkg.com/install.sh | bash; fi 20 | 21 | install: 22 | - nvm install 7 23 | - curl -o- -L https://yarnpkg.com/install.sh | bash 24 | - source ~/.bashrc 25 | - npm install -g xvfb-maybe 26 | - yarn 27 | script: 28 | - yarn run build 29 | branches: 30 | only: 31 | - master 32 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 版本更新日志 4 | 5 | ## [1.0.3] - 2018-07-04 6 | 7 | ### Added 8 | 9 | - 新增超级节点出块标识 10 | - 由客服创建微信 11 | 12 | ### Changed 13 | 14 | - 一些细节优化 15 | 16 | ### Fixed 17 | 18 | - 一些 bug 19 | 20 | ## [0.7.0] - 2018-06-12 21 | 22 | ### Added 23 | 24 | - 新增测试网切换 25 | - 私钥的导入和导出 26 | 27 | ## [0.6.12] - 2018-06-11 28 | 29 | ### Changed 30 | 31 | - 活动页修改 32 | 33 | ## [0.6.11] - 2018-06-09 34 | 35 | ### Added 36 | 37 | - 活动页 38 | 39 | ## [0.6.8] - 2018-06-08 40 | 41 | ### Added 42 | 43 | - mac 自动更新功能 44 | 45 | ## [0.6.6] - 2018-06-08 46 | 47 | ### Fixed 48 | 49 | - 菜单错误,导致 mac 不能正常退出 50 | 51 | ## [0.6.5] - 2018-06-08 52 | 53 | ### Added 54 | 55 | - 新增 mac 构建证书 56 | - 增加 eslint 57 | - 局部刷新列表 58 | - 新增交易记录项 59 | - 节点列表从本地缓存读取 60 | 61 | ### Fixed 62 | 63 | - 修复自动获取节点信息某次失败后会停止获取的错误 64 | 65 | ## [0.6.4] - 2018-06-07 66 | 67 | ### Fixed 68 | 69 | - 修复超级节点列表一些错误 70 | 71 | ## [0.6.3] - 2018-06-07 72 | 73 | ### Added 74 | 75 | - 新增导出私钥确认提示 76 | - 项目新增更新更新日志记录 77 | 78 | ### Changed 79 | 80 | - 修改超级节点列表显示 81 | 82 | ## [0.6.2] - 2018-06-07 83 | 84 | ### Fixed 85 | 86 | - 修复自动刷新块高度失效 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # eosforcewallet 2 | 3 | > eosforce 桌面钱包 4 | 5 | ## Changelog 6 | 7 | 版本更新日志: https://github.com/eosforce/wallet-desktop/blob/master/CHANGELOG.md 8 | 9 | ## 下载 10 | 11 | 下载地址 https://github.com/eosforce/wallet-desktop/releases ,支持 macOS windows,linux 12 | 13 | ## 屏幕截图 14 | 15 | ![](./screenshot/eosforce1.png) 16 | ![](./screenshot/eosforce2.png) 17 | 18 | ## 开发 19 | 20 | ``` bash 21 | # install dependencies 22 | yarn 23 | 24 | # serve with hot reload at localhost:9081 25 | yarn dev 26 | 27 | # build electron application for production 28 | yarn build 29 | 30 | 31 | ``` 32 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.1.{build} 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | image: Visual Studio 2017 8 | platform: 9 | - x64 10 | 11 | init: 12 | - git config --global core.autocrlf input 13 | 14 | install: 15 | - ps: Install-Product node 8 x64 16 | - git reset --hard HEAD 17 | - yarn 18 | - node --version 19 | 20 | build_script: 21 | - yarn build 22 | 23 | test: off -------------------------------------------------------------------------------- /build/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/build/icons/256x256.png -------------------------------------------------------------------------------- /build/icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/build/icons/icon.icns -------------------------------------------------------------------------------- /build/icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/build/icons/icon.ico -------------------------------------------------------------------------------- /dist/electron/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/dist/electron/.gitkeep -------------------------------------------------------------------------------- /dist/web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/dist/web/.gitkeep -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eosforce", 3 | "version": "1.1.261", 4 | "author": "", 5 | "description": "eosforce wallet", 6 | "main": "./dist/electron/main.js", 7 | "scripts": { 8 | "build": "node .electron-vue/build.js && electron-builder", 9 | "build:dir": "node .electron-vue/build.js && electron-builder --dir", 10 | "build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js", 11 | "build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js", 12 | "dev": "node .electron-vue/dev-runner.js", 13 | "lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src", 14 | "lint:fix": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter --fix src", 15 | "pack": "npm run pack:main && npm run pack:renderer", 16 | "pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js", 17 | "pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js", 18 | "public": "node ./public.js" 19 | }, 20 | "build": { 21 | "productName": "eosforce", 22 | "appId": "com.electron.eosforce", 23 | "directories": { 24 | "output": "build" 25 | }, 26 | "files": ["dist/electron/**/*"], 27 | "dmg": { 28 | "contents": [{ 29 | "x": 410, 30 | "y": 150, 31 | "type": "link", 32 | "path": "/Applications" 33 | }, { 34 | "x": 130, 35 | "y": 150, 36 | "type": "file" 37 | }] 38 | }, 39 | "mac": { 40 | "icon": "build/icons/icon.icns" 41 | }, 42 | "win": { 43 | "icon": "build/icons/icon.ico", 44 | "target": ["nsis"] 45 | }, 46 | "linux": { 47 | "icon": "build/icons", 48 | "target": ["AppImage"] 49 | } 50 | }, 51 | "dependencies": { 52 | "axios": "^0.18.0", 53 | "bignumber.js": "^7.2.1", 54 | "bulma": "^0.7.1", 55 | "clipboard-copy": "^2.0.0", 56 | "dayjs": "^1.6.4", 57 | "electron-updater": "^2.21.10", 58 | "element-ui": "^2.3.8", 59 | "eosforcejs": "^1.0.5", 60 | "eosjs": "^16.0.9", 61 | "sjcl": "^1.0.7", 62 | "vue": "^2.3.3", 63 | "vue-electron": "^1.0.6", 64 | "vue-i18n": "^8.0.0", 65 | "vue-router": "^2.5.3", 66 | "vuex": "^2.3.1" 67 | }, 68 | "devDependencies": { 69 | "babel-core": "^6.25.0", 70 | "babel-eslint": "^8.2.3", 71 | "babel-loader": "^7.1.1", 72 | "babel-plugin-component": "^1.1.1", 73 | "babel-plugin-transform-runtime": "^6.23.0", 74 | "babel-preset-env": "^1.6.0", 75 | "babel-preset-stage-0": "^6.24.1", 76 | "babel-register": "^6.24.1", 77 | "babili-webpack-plugin": "^0.1.2", 78 | "cfonts": "^1.1.3", 79 | "chalk": "^2.4.1", 80 | "copy-webpack-plugin": "^4.0.1", 81 | "cross-env": "^5.0.5", 82 | "css-loader": "^0.28.4", 83 | "del": "^3.0.0", 84 | "devtron": "^1.4.0", 85 | "electron": "^2.0.5", 86 | "electron-builder": "^19.19.1", 87 | "electron-debug": "^1.4.0", 88 | "electron-devtools-installer": "^2.2.0", 89 | "eslint": "^4.4.1", 90 | "eslint-config-standard": "^10.2.1", 91 | "eslint-friendly-formatter": "^3.0.0", 92 | "eslint-loader": "^1.9.0", 93 | "eslint-plugin-html": "^3.1.1", 94 | "eslint-plugin-import": "^2.7.0", 95 | "eslint-plugin-node": "^5.1.1", 96 | "eslint-plugin-promise": "^3.5.0", 97 | "eslint-plugin-standard": "^3.0.1", 98 | "extract-text-webpack-plugin": "^3.0.0", 99 | "file-loader": "^0.11.2", 100 | "html-webpack-plugin": "^2.30.1", 101 | "multispinner": "^0.2.1", 102 | "node-loader": "^0.6.0", 103 | "node-sass": "^4.9.0", 104 | "pre-commit": "^1.2.2", 105 | "sass-loader": "^7.0.1", 106 | "style-loader": "^0.18.2", 107 | "url-loader": "^0.5.9", 108 | "vue-html-loader": "^1.2.4", 109 | "vue-loader": "^13.0.5", 110 | "vue-style-loader": "^3.0.1", 111 | "vue-template-compiler": "^2.4.2", 112 | "webpack": "^3.5.2", 113 | "webpack-dev-server": "^2.7.1", 114 | "webpack-hot-middleware": "^2.18.2" 115 | }, 116 | "pre-commit": ["lint"] 117 | } -------------------------------------------------------------------------------- /public.js: -------------------------------------------------------------------------------- 1 | const spawn = require('child_process').spawn; 2 | const git_status = spawn('git', ['status']); 3 | const fs = require('fs'); 4 | 5 | const create_cmd = (cmd, args) => { 6 | return new Promise((resolve, reject) => { 7 | var git_status = spawn(cmd, args); 8 | git_status.on('exit', function (data) { 9 | resolve(data); 10 | return ; 11 | }); 12 | }); 13 | } 14 | 15 | const read_package = () => { 16 | return new Promise((resolve, reject) => { 17 | fs.readFile(__dirname + '/package.json', {flag: 'r+', encoding: 'utf8'}, function (err, data) { 18 | if(err) { 19 | return; 20 | } 21 | console.log(data); 22 | resolve(JSON.parse(data)); 23 | }); 24 | }); 25 | } 26 | 27 | const write_package = (data) => { 28 | return new Promise((resolve, reject) => { 29 | console.log(data); 30 | fs.writeFile(__dirname + '/package.json', data, {flag: 'w'}, function (err) { 31 | if(err){ 32 | reject(); 33 | throw err; 34 | } 35 | resolve(null); 36 | }); 37 | }); 38 | } 39 | 40 | const get_comments = () => { 41 | if(process.argv.length < 3){ 42 | return ''; 43 | } 44 | return process.argv[2]; 45 | } 46 | 47 | const main = async () => { 48 | let package = await read_package(), 49 | version = package.version, 50 | version_arr = version.split('.').map(item => parseInt(item)), 51 | new_version = null; 52 | 53 | version_arr[version_arr.length - 1] += 1; 54 | new_version = version_arr.join('.'); 55 | console.log(new_version); 56 | package.version = new_version; 57 | let res = await write_package(JSON.stringify(package)); 58 | await create_cmd('git', [`tag`, '-a', `v${new_version}`, `-m`, `${ get_comments() }`]); 59 | await create_cmd('git', ['push', '--delete', 'origin', `v${new_version}`]); 60 | await create_cmd('git', [`push`, `origin`, `v${new_version}`]); 61 | await create_cmd('git', [`tag`, `--delete`, `v${new_version}`]); 62 | console.log('update tag successfull') 63 | } 64 | 65 | main(); 66 | 67 | 68 | -------------------------------------------------------------------------------- /screenshot/branches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/screenshot/branches.png -------------------------------------------------------------------------------- /screenshot/eosforce1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/screenshot/eosforce1.png -------------------------------------------------------------------------------- /screenshot/eosforce2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/screenshot/eosforce2.png -------------------------------------------------------------------------------- /screenshot/releases1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/screenshot/releases1.png -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | EOSForce钱包 7 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 8 | 9 | 12 | <% } %> 13 | 14 | 15 | 16 |
17 | 18 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/index.dev.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used specifically and only for development. It installs 3 | * `electron-debug` & `vue-devtools`. There shouldn't be any need to 4 | * modify this file, but it can be used to extend your development 5 | * environment. 6 | */ 7 | 8 | /* eslint-disable */ 9 | 10 | // Set environment for development 11 | process.env.NODE_ENV = 'development'; 12 | 13 | // Install `electron-debug` with `devtron` 14 | require('electron-debug')({ showDevTools: true }); 15 | 16 | // Install `vue-devtools` 17 | require('electron').app.on('ready', () => { 18 | let installExtension = require('electron-devtools-installer'); 19 | installExtension 20 | .default(installExtension.VUEJS_DEVTOOLS) 21 | .then(() => {}) 22 | .catch(err => { 23 | console.log('Unable to install `vue-devtools`: \n', err); 24 | }); 25 | }); 26 | 27 | // Require `main` process to boot app 28 | require('./index'); 29 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow } from 'electron'; 2 | /** 3 | * Set `__static` path to static files in production 4 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html 5 | */ 6 | if (process.env.NODE_ENV !== 'development') { 7 | global.__static = require('path') 8 | .join(__dirname, '/static') 9 | .replace(/\\/g, '\\\\'); 10 | } 11 | 12 | let mainWindow; 13 | const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:9081` : `file://${__dirname}/index.html`; 14 | 15 | function createWindow() { 16 | /** 17 | * Initial window options 18 | */ 19 | mainWindow = new BrowserWindow({ 20 | height: 800, 21 | useContentSize: true, 22 | width: 1200 23 | }); 24 | 25 | mainWindow.loadURL(winURL); 26 | 27 | mainWindow.on('closed', () => { 28 | mainWindow = null; 29 | }); 30 | } 31 | 32 | app.on('ready', createWindow); 33 | 34 | app.on('window-all-closed', () => { 35 | if (process.platform !== 'darwin') { 36 | app.quit(); 37 | } 38 | }); 39 | 40 | app.on('activate', () => { 41 | if (mainWindow === null) { 42 | createWindow(); 43 | } 44 | }); 45 | 46 | /** 47 | * Auto Updater 48 | * 49 | * Uncomment the following code below and install `electron-updater` to 50 | * support auto updating. Code Signing with a valid certificate is required. 51 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 52 | */ 53 | 54 | // autoUpdater.on('update-downloaded', () => { 55 | // autoUpdater.quitAndInstall() 56 | // }) 57 | 58 | // app.on('ready', () => { 59 | // autoUpdater.checkForUpdatesAndNotify(); 60 | // }); 61 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 55 | 56 | 66 | -------------------------------------------------------------------------------- /src/renderer/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/.gitkeep -------------------------------------------------------------------------------- /src/renderer/assets/assets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/assets.png -------------------------------------------------------------------------------- /src/renderer/assets/assets_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/assets_w.png -------------------------------------------------------------------------------- /src/renderer/assets/border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/border.png -------------------------------------------------------------------------------- /src/renderer/assets/eosforce-qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/eosforce-qrcode.png -------------------------------------------------------------------------------- /src/renderer/assets/exchange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/exchange.png -------------------------------------------------------------------------------- /src/renderer/assets/exchange_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/exchange_w.png -------------------------------------------------------------------------------- /src/renderer/assets/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/export.png -------------------------------------------------------------------------------- /src/renderer/assets/kefu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/kefu.png -------------------------------------------------------------------------------- /src/renderer/assets/lace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/lace.png -------------------------------------------------------------------------------- /src/renderer/assets/laternode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/laternode.png -------------------------------------------------------------------------------- /src/renderer/assets/laternode_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/laternode_w.png -------------------------------------------------------------------------------- /src/renderer/assets/loader/producing.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/renderer/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/logo.png -------------------------------------------------------------------------------- /src/renderer/assets/node.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/node.png -------------------------------------------------------------------------------- /src/renderer/assets/node_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/node_w.png -------------------------------------------------------------------------------- /src/renderer/assets/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/refresh.png -------------------------------------------------------------------------------- /src/renderer/assets/select_drop_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/renderer/assets/token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/token.png -------------------------------------------------------------------------------- /src/renderer/assets/token_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/token_w.png -------------------------------------------------------------------------------- /src/renderer/assets/user_head.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/user_head.png -------------------------------------------------------------------------------- /src/renderer/assets/vote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote.png -------------------------------------------------------------------------------- /src/renderer/assets/vote/avaliable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote/avaliable.png -------------------------------------------------------------------------------- /src/renderer/assets/vote/redeem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote/redeem.png -------------------------------------------------------------------------------- /src/renderer/assets/vote/reward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote/reward.png -------------------------------------------------------------------------------- /src/renderer/assets/vote/transform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote/transform.png -------------------------------------------------------------------------------- /src/renderer/assets/vote/vote.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote/vote.png -------------------------------------------------------------------------------- /src/renderer/assets/vote_w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/src/renderer/assets/vote_w.png -------------------------------------------------------------------------------- /src/renderer/components/ConfirmModal.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 86 | 87 | 105 | -------------------------------------------------------------------------------- /src/renderer/components/Message.js: -------------------------------------------------------------------------------- 1 | import { Notification } from 'element-ui'; 2 | 3 | export default { 4 | getConfig(defaultConfig, value) { 5 | return typeof value === 'string' 6 | ? { 7 | ...defaultConfig, 8 | title: value, 9 | } 10 | : { 11 | ...defaultConfig, 12 | ...value, 13 | }; 14 | }, 15 | warning(value) { 16 | return Notification( 17 | this.getConfig( 18 | { 19 | type: 'warning', 20 | duration: 3000, 21 | position: 'top-left', 22 | }, 23 | value 24 | ) 25 | ); 26 | }, 27 | error(value) { 28 | return Notification( 29 | this.getConfig( 30 | { 31 | type: 'error', 32 | title: '错误', 33 | duration: 6000, 34 | position: 'top-left', 35 | }, 36 | value 37 | ) 38 | ); 39 | }, 40 | success(value) { 41 | return Notification( 42 | this.getConfig( 43 | { 44 | type: 'success', 45 | duration: 3000, 46 | position: 'top-left', 47 | }, 48 | value 49 | ) 50 | ); 51 | }, 52 | }; 53 | -------------------------------------------------------------------------------- /src/renderer/components/PromptModal.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 85 | 86 | 104 | -------------------------------------------------------------------------------- /src/renderer/constants/config.constants.js: -------------------------------------------------------------------------------- 1 | export const EOSFORCE_WALLET_KEY = 'storage://wallets'; 2 | 3 | export const NODE_LIST_KEY = 'storage://node/nodelist'; 4 | 5 | export const CHAIN_NET_KEY = 'storage://currentChainNet'; 6 | 7 | export const NODE_API_URL = 'https://updatewallet.oss-cn-hangzhou.aliyuncs.com/eosforce/main-net.json'; 8 | // export const NODE_TEST_NET_URL = 'https://raw.githubusercontent.com/eosforce/testnet-main/master/node-list/test-list.json'; 9 | 10 | export const CHAIN_NETS = { 11 | '1.0': '主网 1.0', 12 | // '0.7': '公测网 0.7', 13 | }; 14 | -------------------------------------------------------------------------------- /src/renderer/constants/types.constants.js: -------------------------------------------------------------------------------- 1 | export const Actions = { 2 | REFRESH_APP: 'REFRESH_APP', 3 | FETCH_NODE_INFO: 'FETCH_NODE_INFO', 4 | INIT_WALLET: 'INIT_WALLET', 5 | INIT_APP: 'INIT_APP', 6 | ADD_NODE: 'ADD_NODE', 7 | GET_CURRENT_ACCOUNT_NAME: 'GET_CURRENT_ACCOUNT_NAME', 8 | VOTE: 'VOTE', 9 | REVOTE: 'REVOTE', 10 | UNFREEZE: 'UNFREEZE', 11 | CLAIM: 'CLAIM', 12 | VOTE4RAM: 'VOTE4RAM', 13 | UNFREEZE4RAM: 'UNFREEZE4RAM', 14 | DELEGATEBW: 'DELEGATEBW', 15 | GET_BPS_TABLE: 'GET_BPS_TABLE', 16 | GET_TRANSFER_RECORD: 'GET_TRANSFER_RECORD', 17 | NEW_WALLET: 'NEW_WALLET', 18 | LOAD_EOSFORCE: 'LOAD_EOSFORCE', 19 | FETCH_WALLET: 'FETCH_WALLET', 20 | NEW_ACCOUNT: 'NEW_ACCOUNT', 21 | TRANSFER_ACCOUNT: 'TRANSFER_ACCOUNT', 22 | DELETE_ACCOUNT: 'DELETE_ACCOUNT', 23 | TRANSFER: 'TRANSFER', 24 | GETFREEZE: 'GETFREEZE', 25 | FREEZE: 'FREEZE', 26 | UNFREEZECPUNET: 'UNFREEZECPUNET', 27 | FETCH_ACCOUNT_LIST: 'FETCH_ACCOUNT_LIST', 28 | FETCH_ACCOUNT: 'FETCH_ACCOUNT', 29 | GET_ACCOUNT_INFO: 'GET_ACCOUNT_INFO', 30 | FETCH_WALLET_LIST: 'FETCH_WALLET_LIST', 31 | GET_ACCOUNT_OVERVIEW: 'GET_ACCOUNT_OVERVIEW', 32 | FETCH_NODE_LIST: 'FETCH_NODE_LIST', 33 | SYNC_NODE_LIST: 'SYNC_NODE_LIST', 34 | ADD_NODE_RPC_HOST: 'ADD_NODE_RPC_HOST', 35 | SWITCH_CHAIN_NET: 'SWITCH_CHAIN_NET', 36 | GET_TOKEN_LIST: 'GET_TOKEN_LIST', 37 | REFRESH_WALLET: 'REFRESH_WALLET', 38 | DELETE_WALLET: 'DELETE_WALLET', 39 | GET_BP_NICK: 'GET_BP_NICK', 40 | GET_GLOABLE_INFO: 'GET_GLOABLE_INFO', 41 | CHECK_TRANSACTION: 'CHECK_TRANSACTION', 42 | FETCH_BLOCK: 'FETCH_BLOCK', 43 | CHECK_INVOLED: 'CHECK_INVOLED', 44 | GET_STORE_NODE_LIST: 'GET_STORE_NODE_LIST', 45 | UPDATE_NODE_LIST: 'UPDATE_NODE_LIST', 46 | QUERY_FIX_VOTES_TABLE: 'QUERY_FIX_VOTES_TABLE', 47 | REVOTEFIX: 'REVOTEFIX', 48 | VOTEFIX: 'VOTEFIX', 49 | OUTFIXVOTE: 'OUTFIXVOTE' 50 | }; 51 | 52 | export const Getters = { 53 | CURRENT_NODE_INFO: 'CURRENT_NODE_INFO', 54 | CURRENT_BLOCK: 'CURRENT_BLOCK', 55 | PUBLIC_KEY_LIST: 'PUBLIC_KEY_LIST', 56 | ACCOUNT_LIST: 'ACCOUNT_LIST', 57 | CURRENT_ACCOUNT: 'CURRENT_ACCOUNT', 58 | CURRENT_ACCOUNT_NAME: 'CURRENT_ACCOUNT_NAME', 59 | GET_WIF: 'GET_WIF', 60 | CURRENT_NODE: 'CURRENT_NODE', 61 | GET_TRANSE_CONFIG: 'GET_TRANSE_CONFIG', 62 | ACCOUT_MAP: 'ACCOUT_MAP', 63 | GET_STORE_NODE_LIST: 'GET_STORE_NODE_LIST' 64 | }; 65 | 66 | export const Mutations = { 67 | SET_BP_NICK: 'SET_BP_NICK', 68 | SET_CURRENT_NODE_INFO: 'SET_CURRENT_NODE_INFO', 69 | SET_CUREENT_NODE: 'SET_CUREENT_NODE', 70 | SET_WALLET_LIST: 'SET_WALLET_LIST', 71 | SET_NODE_LIST: 'SET_NODE_LIST', 72 | SET_WALLET_ID_LIST: 'SET_WALLET_ID_LIST', 73 | SET_BPS_TABLE: 'SET_BPS_TABLE', 74 | SET_TRANSFER_RECORDS: 'SET_TRANSFER_RECORDS', 75 | SET_WALLET: 'SET_WALLET', 76 | SET_EOSFORCE: 'SET_EOSFORCE', 77 | SET_ACCOUNT_LIST: 'SET_ACCOUNT_LIST', 78 | SET_ACCOUNT: 'SET_ACCOUNT', 79 | SET_ACCOUNT_NAME: 'SET_ACCOUNT_NAME', 80 | SET_ACCOUNT_INFO: 'SET_ACCOUNT_INFO', 81 | RESET_ACCOUNT_INFO: 'RESET_ACCOUNT_INFO', 82 | SET_LATEST_TRANSFER_NUM: 'SET_LATEST_TRANSFER_NUM', 83 | SET_CHAIN_NET: 'SET_CHAIN_NET', 84 | SET_TOKEN_LIST: 'SET_TOKEN_LIST', 85 | SET_WRITE_NODE_LIST: 'SET_WRITE_NODE_LIST', 86 | SET_UPDATE_INFO: 'SET_UPDATE_INFO', 87 | START_LOAD_ACCOUNT_INFO: 'START_LOAD_ACCOUNT_INFO', 88 | FINISH_LOAD_ACCOUNT_INFO: 'FINISH_LOAD_ACCOUNT_INFO', 89 | START_LOAD_ACCOUNT_LIST: 'START_LOAD_ACCOUNT_LIST', 90 | FINISH_LOAD_ACCOUNT_LIST: 'FINISH_LOAD_ACCOUNT_LIST', 91 | SET_VOTES_TABLE: 'SET_VOTES_TABLE', 92 | SET_VOTES4RAM_TABLE: 'SET_VOTES4RAM_TABLE', 93 | SET_SUPER_PSAMOUNT_TABLE: 'SET_SUPER_PSAMOUNT_TABLE', 94 | SET_BASE_BPS_TABLE: 'SET_BASE_BPS_TABLE', 95 | SET_VERSION: 'SET_VERSION', 96 | SET_BLOCK: 'SET_BLOCK', 97 | UPDATE_BLOCK_LIST_STATUS: 'UPDATE_BLOCK_LIST_STATUS', 98 | }; 99 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueI18n from 'vue-i18n'; 3 | import ElementUI from 'element-ui'; 4 | import 'element-ui/lib/theme-chalk/index.css'; 5 | 6 | import App from '@/App'; 7 | import router from '@/router'; 8 | import store from '@/store'; 9 | import messages from '@/messages'; 10 | 11 | import setMenu from '@/menu'; 12 | import { formatNumber, timestamp, hostname } from '@/utils/filter'; 13 | 14 | Vue.use(ElementUI); 15 | Vue.use(VueI18n); 16 | setMenu(); 17 | 18 | if (!process.env.IS_WEB) Vue.use(require('vue-electron')); 19 | Vue.config.productionTip = false; 20 | 21 | Vue.filter('formatNumber', formatNumber); 22 | Vue.filter('timestamp', timestamp); 23 | Vue.filter('hostname', hostname); 24 | 25 | if (!localStorage.locale) { 26 | if (navigator.language === 'zh-CN') { 27 | localStorage.locale = 'zh'; 28 | } else { 29 | localStorage.locale = 'en'; 30 | } 31 | } 32 | 33 | export const i18n = new VueI18n({ 34 | locale: localStorage.locale || 'en', 35 | messages, 36 | }); 37 | 38 | /* eslint-disable no-new */ 39 | new Vue({ 40 | components: { App }, 41 | router, 42 | store, 43 | i18n, 44 | template: '', 45 | }).$mount('#app'); 46 | -------------------------------------------------------------------------------- /src/renderer/menu.js: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron'; 2 | import { checkForUpdates } from '@/updater'; 3 | const { Menu, shell, app } = remote; 4 | 5 | export default () => { 6 | const template = [ 7 | { 8 | label: 'Edit', 9 | submenu: [ 10 | { role: 'undo' }, 11 | { role: 'redo' }, 12 | { type: 'separator' }, 13 | { role: 'cut' }, 14 | { role: 'copy' }, 15 | { role: 'paste' }, 16 | { role: 'pasteandmatchstyle' }, 17 | { role: 'delete' }, 18 | { role: 'selectall' }, 19 | ], 20 | }, 21 | { 22 | label: 'View', 23 | submenu: [ 24 | { role: 'reload' }, 25 | { role: 'forcereload' }, 26 | { role: 'toggledevtools' }, 27 | { type: 'separator' }, 28 | { role: 'resetzoom' }, 29 | { role: 'zoomin' }, 30 | { role: 'zoomout' }, 31 | { type: 'separator' }, 32 | { role: 'togglefullscreen' }, 33 | ], 34 | }, 35 | { 36 | role: 'window', 37 | submenu: [{ role: 'minimize' }, { role: 'close' }], 38 | }, 39 | { 40 | role: 'help', 41 | submenu: [ 42 | { 43 | label: '反馈一个问题', 44 | click() { 45 | shell.openExternal('https://github.com/eosforce/wallet-desktop/issues/new'); 46 | }, 47 | }, 48 | { 49 | label: '检查更新', 50 | click(...arg) { 51 | checkForUpdates(...arg); 52 | }, 53 | }, 54 | ], 55 | }, 56 | ]; 57 | 58 | if (process.platform === 'darwin') { 59 | template.unshift({ 60 | label: app.getName(), 61 | submenu: [ 62 | { role: 'about' }, 63 | { type: 'separator' }, 64 | { role: 'services', submenu: [] }, 65 | { type: 'separator' }, 66 | { role: 'hide' }, 67 | { role: 'hideothers' }, 68 | { role: 'unhide' }, 69 | { type: 'separator' }, 70 | { role: 'quit' }, 71 | ], 72 | }); 73 | 74 | template[1].submenu.push( 75 | { type: 'separator' }, 76 | { 77 | label: 'Speech', 78 | submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }], 79 | } 80 | ); 81 | 82 | template[3].submenu = [ 83 | { role: 'close' }, 84 | { role: 'minimize' }, 85 | { role: 'zoom' }, 86 | { type: 'separator' }, 87 | { role: 'front' }, 88 | ]; 89 | } 90 | 91 | Menu.setApplicationMenu(Menu.buildFromTemplate(template)); 92 | }; 93 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | 4 | Vue.use(Router); 5 | 6 | const pageHeader = () => import('@/views/layout/PageHeader'); 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '/', 12 | name: 'dashboard', 13 | components: { 14 | header: pageHeader, 15 | default: () => import('@/views/wallet/Dashboard'), 16 | }, 17 | children: [ 18 | // { 19 | // path: '/config_node_list', 20 | // name: 'config_node_list', 21 | // components: { 22 | // default: () => import('@/views/wallet/config_node_list'), 23 | // }, 24 | // }, 25 | { 26 | name: 'walletDetail', 27 | path: 'wallets/:walletId', 28 | component: () => import('@/views/wallet/WalletDetail'), 29 | children: [ 30 | { 31 | name: 'accountDetail', 32 | path: 'accounts/:accountName', 33 | component: () => import('@/views/account/AccountDetail'), 34 | children: [ 35 | { 36 | name: 'accountCreateAccount', 37 | path: 'new', 38 | components: { 39 | modal: () => import('@/views/account/AccountNew'), 40 | }, 41 | }, 42 | { 43 | name: 'accountTransfer', 44 | path: 'accountTransfer', 45 | components: { 46 | modal: () => import('@/views/account/AccountTransfer'), 47 | }, 48 | }, 49 | { 50 | name: 'NetCpu', 51 | path: 'NetCpu', 52 | components: { 53 | modal: () => import('@/views/account/NetCpu'), 54 | }, 55 | }, 56 | { 57 | name: 'Freeze', 58 | path: 'Freeze', 59 | components: { 60 | modal: () => import('@/views/account/Freeze'), 61 | }, 62 | }, 63 | { 64 | name: 'transfer', 65 | path: 'transfer', 66 | components: { 67 | modal: () => import('@/views/account/Transfer'), 68 | }, 69 | }, 70 | { 71 | name: 'tokenTransfer', 72 | path: ':symbol/transfer?precision', 73 | components: { 74 | modal: () => import('@/views/account/Transfer'), 75 | }, 76 | }, 77 | { 78 | name: 'vote', 79 | path: ':bpname/vote', 80 | components: { 81 | modal: () => import('@/views/account/Vote'), 82 | }, 83 | }, 84 | { 85 | name: 'unfreeze', 86 | path: ':bpname/unfreeze', 87 | components: { 88 | modal: () => import('@/views/account/Unfreeze'), 89 | }, 90 | }, 91 | { 92 | name: 'UnfreezeCpuNet', 93 | path: 'UnfreezeCpuNet', 94 | components: { 95 | modal: () => import('@/views/account/UnfreezeCpuNet'), 96 | }, 97 | }, 98 | { 99 | name: 'claim', 100 | path: ':bpname/claim', 101 | components: { 102 | modal: () => import('@/views/account/Claim'), 103 | }, 104 | }, 105 | { 106 | name: 'vote4ram', 107 | path: ':bpname/vote4ram', 108 | components: { 109 | modal: () => import('@/views/account/Vote4ram'), 110 | }, 111 | }, 112 | { 113 | name: 'Unfreeze4ram', 114 | path: ':bpname/Unfreeze4ram', 115 | components: { 116 | modal: () => import('@/views/account/Unfreeze4ram'), 117 | }, 118 | }, 119 | ], 120 | }, 121 | ], 122 | }, 123 | ], 124 | }, 125 | { 126 | path: '/entry', 127 | name: 'entry', 128 | components: { 129 | default: () => import('@/views/entry/Entry'), 130 | }, 131 | }, 132 | { 133 | path: '/wallet-new', 134 | name: 'walletNew', 135 | components: { 136 | default: () => import('@/views/wallet/WalletNew'), 137 | }, 138 | }, 139 | { 140 | path: '/wallet-import', 141 | name: 'walletImport', 142 | components: { 143 | default: () => import('@/views/wallet/WalletImport'), 144 | }, 145 | }, 146 | { 147 | path: './ImportKey', 148 | name: 'ImportKey', 149 | components: { 150 | default: () => import('@/views/wallet/ImportKey'), 151 | }, 152 | }, 153 | { 154 | path: './CreateKey', 155 | name: 'CreateKey', 156 | components: { 157 | default: () => import('@/views/wallet/CreateKey'), 158 | }, 159 | }, 160 | { 161 | path: './ImportWalletFile', 162 | name: 'ImportWalletFile', 163 | components: { 164 | default: () => import('@/views/wallet/ImportWalletFile'), 165 | }, 166 | }, 167 | { 168 | path: '*', 169 | redirect: '/', 170 | }, 171 | ], 172 | }); 173 | -------------------------------------------------------------------------------- /src/renderer/services/Storage.js: -------------------------------------------------------------------------------- 1 | import uuidV4 from 'uuid/v4'; 2 | 3 | import { privateToPublic, encrypt } from '@/utils/util'; 4 | import { EOSFORCE_WALLET_KEY } from '@/constants/config.constants'; 5 | import { isValidPassword, isValidPrivate } from '@/utils/rules'; 6 | import Store from '@/store'; 7 | 8 | export default class Storage { 9 | constructor(storagePath) { 10 | this.storagePath = storagePath; 11 | } 12 | 13 | static setPath(storagePath) { 14 | if (!storagePath) throw new Error('storagePath 不能为空'); 15 | return new Storage(storagePath); 16 | } 17 | 18 | async store(data) { 19 | try { 20 | localStorage.setItem(this.storagePath, JSON.stringify(data)); 21 | return data; 22 | } catch (err) { 23 | return err; 24 | } 25 | } 26 | 27 | async fetch_data () { 28 | const _data = localStorage.getItem(this.storagePath); 29 | let json_data = null; 30 | try { 31 | json_data = JSON.parse(_data); 32 | } catch (err) { 33 | json_data = err; 34 | } 35 | return json_data 36 | } 37 | 38 | async fetch() { 39 | const _data = localStorage.getItem(this.storagePath); 40 | let res = null; 41 | try { 42 | res = JSON.parse(_data); 43 | } catch (err) { 44 | res = null; 45 | } 46 | return res; 47 | } 48 | 49 | remove() { 50 | return Promise.resolve(localStorage.removeItem(this.storagePath)); 51 | } 52 | } 53 | 54 | export const getWalletIdFromKey = (key = '') => { 55 | const reg = new RegExp(`^${EOSFORCE_WALLET_KEY}/(.*)#${Store.state.app.chainNet}`); 56 | const matchResult = key.match(reg); 57 | return matchResult && matchResult[1] ? matchResult[1] : null; 58 | }; 59 | 60 | export const getWalletIdList = () => { 61 | return Object.keys(localStorage) 62 | .map(key => getWalletIdFromKey(key)) 63 | .filter(value => value); 64 | }; 65 | 66 | export const getWalletKeyFromId = id => { 67 | return `${EOSFORCE_WALLET_KEY}/${id}#${Store.state.app.chainNet}`; 68 | }; 69 | 70 | export const createWalletData = ({ privateKey, password, symbol = 'EOS' }) => { 71 | if (isValidPrivate(privateKey) && isValidPassword(password)) { 72 | const publicKey = privateToPublic(privateKey, symbol); 73 | const crypto = encrypt(password, { privateKey }); 74 | const id = uuidV4(); 75 | const data = { 76 | version: '1', 77 | id, 78 | publicKey, 79 | crypto, 80 | }; 81 | return Storage.setPath(getWalletKeyFromId(publicKey)).store(data); 82 | } else { 83 | return Promise.reject(new Error('数据格式错误')); 84 | } 85 | }; 86 | 87 | export const deleteWalletData = ({ publicKey }) => { 88 | return Storage.setPath(getWalletKeyFromId(publicKey)).remove(); 89 | }; 90 | -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | import modules from './modules'; 5 | 6 | Vue.use(Vuex); 7 | 8 | export default new Vuex.Store({ 9 | modules, 10 | strict: process.env.NODE_ENV !== 'production', 11 | }); 12 | -------------------------------------------------------------------------------- /src/renderer/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('.', false, /\.js$/); 7 | const modules = {}; 8 | 9 | files.keys().forEach(key => { 10 | if (key === './index.js') return; 11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default; 12 | }); 13 | 14 | export default modules; 15 | -------------------------------------------------------------------------------- /src/renderer/store/modules/wallet.js: -------------------------------------------------------------------------------- 1 | import { Mutations, Actions, Getters } from '@/constants/types.constants'; 2 | 3 | import Storage, { getWalletKeyFromId } from '@/services/Storage'; 4 | import { newAccount, getAccounts } from '@/services/Eos'; 5 | import { decrypt } from '@/utils/util'; 6 | 7 | const initState = { 8 | data: {}, 9 | /* 10 | eos lib, there are two eos lib , one has fee, the other has no fee 11 | */ 12 | EOS_WITH_FEE: false, 13 | wallet_symbol: 'EOS', 14 | WALLET_SHOW_SYMBOL: 'EOSC', 15 | IS_FEE_MODEL: false, 16 | // has cpu mortgage 17 | HAS_CPU: true, 18 | // has net mortgage 19 | HAS_NET: true, 20 | // minus vote of ram will be locked status 21 | RAM_BACK_STATE: false, 22 | // minus vote will be locked status 23 | VOTE_BACK_STATE: false, 24 | // share released coin from block producers 25 | HAS_CLAIM: false, 26 | // must freezed then can vote for ram and vote 27 | HAS_FREEZED: true, 28 | // core coin in which contract account 29 | CORE_COIN_CONTRACT: 'eosio.token', 30 | // vote num in which key [vote, staked] 31 | VOTE_NUM_KEY: 'vote', 32 | // has blocked 33 | HAS_LOCKED: false, 34 | 35 | 36 | // EOS_WITH_FEE: true, 37 | // eosforce config 38 | // wallet_symbol: 'EOS', 39 | wallet_show_symbol: 'EOSC', 40 | IS_FEE_MODEL: true, 41 | HAS_CPU: false, 42 | HAS_NET: false, 43 | // // 内存投票是否有赎回状态 44 | RAM_BACK_STATE: true, 45 | // // 投票是否有赎回状态 46 | VOTE_BACK_STATE: true, 47 | // // 是否有分红 48 | HAS_CLAIM: true, 49 | // // 有抵押机制 50 | HAS_FREEZED: false, 51 | // core coin in which contract account 52 | CORE_COIN_CONTRACT: 'eosio', 53 | VOTE_NUM_KEY: 'staked', 54 | HAS_LOCKED: true, 55 | 56 | accountList: [], 57 | }; 58 | 59 | const mutations = { 60 | [Mutations.SET_WALLET](state, { data }) { 61 | state.data = data; 62 | }, 63 | [Mutations.SET_ACCOUNT_LIST](state, { accountList }) { 64 | state.accountList = accountList; 65 | } 66 | }; 67 | 68 | const actions = { 69 | [Actions.REFRESH_APP]({ state, commit, dispatch }) { 70 | dispatch(Actions.FETCH_WALLET, { id: state.data.publicKey }); 71 | }, 72 | [Actions.REFRESH_WALLET]({ state, commit, dispatch }) { 73 | dispatch(Actions.FETCH_WALLET_LIST, { id: state.data.publicKey }); 74 | }, 75 | [Actions.FETCH_WALLET]({ commit, dispatch }, { id, mutation = true }) { 76 | return Storage.setPath(getWalletKeyFromId(id)) 77 | .fetch() 78 | .then(data => { 79 | if (!mutation) return data; 80 | commit(Mutations.SET_WALLET, { data }); 81 | }); 82 | }, 83 | [Actions.FETCH_ACCOUNT_LIST]({ getters, commit }, { publicKey, noset = false } = {}) { 84 | return getAccounts(getters[Getters.CURRENT_NODE])(publicKey).then(result => { 85 | if (noset) return result; 86 | commit(Mutations.SET_ACCOUNT_LIST, { accountList: result }); 87 | }); 88 | }, 89 | [Actions.NEW_ACCOUNT]({ state, getters, dispatch }, { creator, OwnerKey, ActiveKey, accountName, password, walletId, permission }) { 90 | return getters[Getters.GET_TRANSE_CONFIG](password, creator, walletId).then(config => { 91 | return newAccount(config)({creator, OwnerKey, ActiveKey, accountName, permission, wallet_symbol: state.wallet_symbol}); 92 | }); 93 | } 94 | }; 95 | 96 | const getters = { 97 | [Getters.ACCOUNT_LIST](state) { 98 | return state.accountList || []; 99 | }, 100 | [Getters.GET_WIF]: state => password => { 101 | try { 102 | const wif = decrypt(password, state.data.crypto).privateKey; 103 | return Promise.resolve(wif); 104 | } catch (err) { 105 | return Promise.reject(new Error('密码错误')); 106 | } 107 | }, 108 | wallet_symbol (state) { 109 | return state.wallet_symbol; 110 | }, 111 | CORE_COIN_CONTRACT (state) { 112 | return state.CORE_COIN_CONTRACT; 113 | }, 114 | VOTE_NUM_KEY (state) { 115 | return state.VOTE_NUM_KEY; 116 | }, 117 | HAS_FREEZED (state) { 118 | return state.HAS_FREEZED; 119 | }, 120 | HAS_LOCKED (state) { 121 | return state.HAS_LOCKED; 122 | } 123 | }; 124 | 125 | export default { 126 | state: initState, 127 | mutations, 128 | actions, 129 | getters, 130 | }; 131 | -------------------------------------------------------------------------------- /src/renderer/styles/bulma.scss: -------------------------------------------------------------------------------- 1 | @import '~bulma/sass/utilities/initial-variables'; 2 | 3 | $family-sans-serif: 'Microsoft YaHei', BlinkMacSystemFont, -apple-system, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 4 | 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 'Helvetica', sans-serif, Consolas, Monaco, monospace; 5 | 6 | $family-primary: $family-sans-serif; 7 | 8 | $tablet: 360px; 9 | $desktop: 769px; 10 | 11 | @import '~bulma/bulma'; 12 | -------------------------------------------------------------------------------- /src/renderer/styles/common.scss: -------------------------------------------------------------------------------- 1 | .menu-list a.is-active { 2 | background: inherit; 3 | color: #fff; 4 | font-weight: 500; 5 | } 6 | 7 | .label:not(:last-child) { 8 | font-weight: 400; 9 | color: #bdc2d3; 10 | color: #484848; 11 | font-size: 14px; 12 | margin-bottom: 0; 13 | } 14 | .cover-page{ 15 | .label:not(:last-child) { 16 | color: #bdc2d3; 17 | margin-bottom: 4px; 18 | } 19 | } 20 | a { 21 | color: #73b9f3; 22 | } 23 | 24 | a:hover { 25 | color: rgb(50, 115, 220); 26 | } 27 | 28 | .label-button { 29 | margin-top: -2px; 30 | margin-left: 8px; 31 | } 32 | 33 | .help { 34 | color: #ffffff; 35 | } 36 | 37 | .help.is-danger { 38 | color: #ff3d00; 39 | } 40 | .help.tips, 41 | .tips { 42 | color: #fef9e6; 43 | } 44 | 45 | .input:focus, 46 | .input.is-focused, 47 | .input:active, 48 | .input.is-active, 49 | .textarea:focus, 50 | .textarea.is-focused, 51 | .textarea:active, 52 | .textarea.is-active { 53 | border-color: rgb(64, 142, 225); 54 | background: #fff; 55 | box-shadow: 0 0 0 0.2rem rgba(64, 142, 225, 0.25); 56 | box-shadow: none; 57 | } 58 | 59 | .cover-page { 60 | background: #1e2233; 61 | min-height: 100vh; 62 | height: 100vh; 63 | width: 100%; 64 | overflow: auto; 65 | position: relative; 66 | display: flex; 67 | justify-content: center; 68 | } 69 | 70 | .cover-page__title { 71 | font-size: 24px; 72 | } 73 | 74 | .page__title{ 75 | font-size: 18px; 76 | color: #fff; 77 | } 78 | 79 | .cover-page__content { 80 | width: 640px; 81 | margin-top: 64px; 82 | } 83 | 84 | .cover-page__form { 85 | margin-top: 32px; 86 | margin-bottom: 64px; 87 | } 88 | 89 | .cover-page-close { 90 | background-color: rgba(10, 10, 10, 0.3); 91 | } 92 | 93 | .data-table { 94 | font-size: 14px; 95 | width: 100%; 96 | th, 97 | td { 98 | padding: 2px; 99 | } 100 | th.align-right, 101 | td.align-right { 102 | text-align: right; 103 | } 104 | th.align-left, 105 | td.align-left { 106 | text-align: left; 107 | } 108 | } 109 | 110 | .basic-modal.modal { 111 | .modal-content { 112 | padding: 24px 24px; 113 | background-color: white; 114 | box-shadow: 0 2px 4px rgba(54, 57, 70, 0.5), 0 0 0 1px rgba(54, 57, 70, 0.5); 115 | color: rgba(0, 0, 0, 0.8); 116 | max-width: 100%; 117 | background: #494e5f; 118 | background: #fff; 119 | position: relative; 120 | border-radius: 4px; 121 | } 122 | .modal-header { 123 | position: relative; 124 | line-height: 24px; 125 | margin-bottom: 24px; 126 | .modal-title { 127 | font-size: 20px; 128 | vertical-align: top; 129 | } 130 | .modal-close-button { 131 | outline: none; 132 | height: 14px; 133 | width: 14px; 134 | font-size: 14px; 135 | opacity: 0.7; 136 | position: absolute; 137 | right: 5px; 138 | top: 5px; 139 | cursor: pointer; 140 | .svg-icon { 141 | vertical-align: top; 142 | } 143 | } 144 | } 145 | .modal-footer { 146 | display: flex; 147 | justify-content: flex-end; 148 | margin-top: 24px; 149 | } 150 | } 151 | 152 | .modal-background { 153 | background-color: rgba(10, 10, 10, 0.3); 154 | background-color: rgba(37,40,43,0.6); 155 | } 156 | 157 | .dropdown { 158 | .button { 159 | color: #363636; 160 | background: #e0e0e0; 161 | } 162 | } 163 | 164 | .control { 165 | .select { 166 | width: 100%; 167 | select { 168 | width: 100%; 169 | background-color: #e0e0e0; 170 | } 171 | } 172 | input { 173 | background: #fff; 174 | box-shadow: none; 175 | border-radius: 2px; 176 | } 177 | } 178 | 179 | .select:not(.is-multiple):not(.is-loading)::after { 180 | border-color: #363636; 181 | right: 1.125em; 182 | z-index: 4; 183 | } 184 | 185 | .cover-page__title { 186 | color: #eff0f8; 187 | margin-bottom: 1.25rem; 188 | } 189 | 190 | .is-grouped .button.cancel-button, 191 | .button.cancel-button { 192 | background: inherit; 193 | color: #f7f9ff; 194 | width: auto; 195 | margin-right: 8px; 196 | border: none; 197 | &:hover { 198 | color: #bcbed3; 199 | } 200 | } 201 | 202 | .row { 203 | height: 40px; 204 | display: flex; 205 | align-items: center; 206 | justify-content: space-between; 207 | border-bottom: 1px solid #fff; 208 | &:hover{ 209 | border-bottom: 1px solid #eee; 210 | div { 211 | color: #409eff; 212 | } 213 | } 214 | } 215 | 216 | .row__content { 217 | max-width: 240px; 218 | overflow: hidden; 219 | text-overflow: ellipsis; 220 | color: #f5ebff; 221 | color: #151515; 222 | input { 223 | width: 240px; 224 | } 225 | } 226 | 227 | .static-label { 228 | .static-text { 229 | color: #f7f9ff; 230 | margin-left: 32px; 231 | } 232 | font-weight: 400; 233 | color: #bdc2d3; 234 | margin-bottom: 0; 235 | } 236 | 237 | .slider_select{ 238 | width: 100%; 239 | display: flex; 240 | background: rgba(251, 251, 251, 0); 241 | padding: 0px; 242 | border-radius: 3px; 243 | overflow: hidden; 244 | box-shadow: 0px 0px 3px rgba(0, 0, 0, 0); 245 | border: 1px solid rgba(49, 49, 49, 0.05); 246 | } 247 | .slider_select_item{ 248 | color: #333; 249 | /*width: 50%;*/ 250 | text-align: center; 251 | font-size: 14px; 252 | padding: 5px 10px; 253 | background: #fff; 254 | cursor: pointer; 255 | align-items: center; 256 | display: flex; 257 | white-space: nowrap; 258 | } 259 | .slider_selected_item{ 260 | background-color: #409eff; 261 | color: #fff; 262 | } 263 | -------------------------------------------------------------------------------- /src/renderer/styles/index.scss: -------------------------------------------------------------------------------- 1 | @import '~@/styles/bulma'; 2 | @import '~@/styles/common'; 3 | @import '~@/styles/main'; 4 | -------------------------------------------------------------------------------- /src/renderer/updater.js: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron'; 2 | import Store from '@/store'; 3 | 4 | const dialog = remote.dialog; 5 | const { autoUpdater } = remote.require('electron-updater'); 6 | let showNotUpdate = false; 7 | let updater; 8 | autoUpdater.autoDownload = false; 9 | 10 | if (process.env.NODE_ENV === 'production') { 11 | autoUpdater.checkForUpdates(); 12 | } 13 | 14 | autoUpdater.setFeedURL('https://updatewallet.oss-cn-hangzhou.aliyuncs.com/latest/'); 15 | 16 | autoUpdater.on('error', error => { 17 | dialog.showErrorBox('Error: ', error == null ? 'unknown' : (error.stack || error).toString()); 18 | }); 19 | 20 | // lang start 21 | import messages from '@/messages'; 22 | if (!localStorage.locale) { 23 | if (navigator.language === 'zh-CN') { 24 | localStorage.locale = 'zh'; 25 | } else { 26 | localStorage.locale = 'en'; 27 | } 28 | } 29 | 30 | const word = (word) => { 31 | return messages[localStorage.locale][word] 32 | } 33 | 34 | // lang end 35 | autoUpdater.on('update-available', () => { 36 | dialog.showMessageBox( 37 | { 38 | type: 'info', 39 | title: word('发现新版本'), 40 | message: word('是否立即更新新版本,确认后程序会在后台下载更新。'), 41 | buttons: [word('更新'), word('取消')], 42 | }, 43 | buttonIndex => { 44 | if (buttonIndex === 0) { 45 | Store.commit('SET_UPDATE_INFO', { update: { startUpdate: true } }); 46 | autoUpdater.downloadUpdate(); 47 | } else { 48 | Store.commit('SET_UPDATE_INFO', { 49 | update: { 50 | startUpdate: false, 51 | progress: 0, 52 | speed: 0, 53 | total: 0, 54 | }, 55 | }); 56 | if (updater) { 57 | updater.enabled = true; 58 | updater = null; 59 | } 60 | } 61 | } 62 | ); 63 | }); 64 | 65 | autoUpdater.on('update-not-available', () => { 66 | if (showNotUpdate) { 67 | dialog.showMessageBox({ 68 | title: word('没有更新'), 69 | message: word('你当前的版本是最新的!'), 70 | }); 71 | updater.enabled = true; 72 | updater = null; 73 | showNotUpdate = false; 74 | } 75 | }); 76 | 77 | autoUpdater.on('update-downloaded', () => { 78 | dialog.showMessageBox( 79 | { 80 | title: word('安装更新'), 81 | message: word('更新已下载完成,确认后会自动安装'), 82 | }, 83 | () => { 84 | setImmediate(() => autoUpdater.quitAndInstall()); 85 | } 86 | ); 87 | }); 88 | 89 | autoUpdater.on('download-progress', progress => { 90 | Store.commit('SET_UPDATE_INFO', { 91 | update: { 92 | progress: progress.percent && progress.percent.toFixed(2), 93 | total: (progress.total / 1000000).toFixed(2), 94 | speed: progress.bytesPerSecond && progress.bytesPerSecond / 1000, 95 | }, 96 | }); 97 | }); 98 | 99 | export const checkForUpdates = (menuItem, focusedWindow, event) => { 100 | updater = menuItem; 101 | updater.enabled = false; 102 | showNotUpdate = true; 103 | autoUpdater.checkForUpdates(); 104 | }; 105 | -------------------------------------------------------------------------------- /src/renderer/utils/filter.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | import BigNumber from 'bignumber.js'; 4 | 5 | export const hostname = value => { 6 | try { 7 | const hostname = new URL(value).hostname; 8 | const pathname = new URL(value).pathname; 9 | if (pathname === '/') { 10 | return hostname; 11 | } else { 12 | return hostname + pathname; 13 | } 14 | } catch (err) { 15 | return value; 16 | } 17 | }; 18 | 19 | export const timestamp = (value, format = 'YYYY-MM-DD HH:mm:ss') => { 20 | value = value + 'Z'; 21 | const date = dayjs(value); 22 | if (date.isValid()) { 23 | return date.format(format); 24 | } else { 25 | return value; 26 | } 27 | }; 28 | 29 | // p 精度 30 | // showSymbol 是否显示货币符号,默认不显示 31 | // symbol 货币符号,默认为 EOS 或自动获取 32 | // separator 是否使用逗号分隔数字,默认为真 33 | // sign 数字后单位,默认空 34 | // percentage 数字的倍率 35 | export const formatNumber = (value, { p, showSymbol, symbol = 'EOS', separator = true, sign, percentage } = {}) => { 36 | if (BigNumber.isBigNumber(value)) { 37 | value = value.toNumber(); 38 | } 39 | if (isNaN(value) && typeof value === 'string' && /^[0-9.-]+\s([A-Z]+)$/.test(value)) { 40 | [value, symbol] = value.split(' '); 41 | } 42 | if (typeof value === 'string' && !isNaN(value)) { 43 | if (p === undefined) { 44 | const match = value.match(/\.(\d*)/); 45 | if (match && match[1]) { 46 | p = match[1].length; 47 | } else { 48 | p = 0; 49 | } 50 | } 51 | value = Number(value); 52 | } else if (typeof value !== 'number') { 53 | return value; 54 | } 55 | if (percentage) { 56 | value = value * percentage; 57 | } 58 | if (!isNaN(p)) { 59 | value = value.toFixed(p); 60 | } else { 61 | value = String(value); 62 | } 63 | if (sign) { 64 | return value + sign; 65 | } 66 | if (separator) { 67 | const parts = value.split('.'); 68 | parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); 69 | value = parts.join('.'); 70 | } 71 | if (showSymbol) { 72 | return [value, symbol].join(' '); 73 | } 74 | return value; 75 | }; 76 | -------------------------------------------------------------------------------- /src/renderer/utils/rules.js: -------------------------------------------------------------------------------- 1 | import eos from 'eosforcejs'; 2 | 3 | const { ecc } = eos.modules; 4 | 5 | export const isValidPassword = password => { 6 | return password && password.length >= 9 && password.length <= 36; 7 | }; 8 | 9 | // @TODO 钱包名规则 10 | export const isValidWalletName = name => { 11 | return name && name.length >= 1 && name.length < 64; 12 | }; 13 | 14 | // Must be less than 13 characters 15 | // Can only contain the following symbols: .12345abcdefghijklmnopqrstuvwxyz 16 | // https://github.com/EOSIO/eos/blob/dacc1b09d2c10cc3ca4cea7821c04ea2a47487fe/libraries/chain/name.cpp#L20 17 | export const isValidAccountName = name => { 18 | if (!name) return false; 19 | return /^[.12345abcdefghijklmnopqrstuvwxyz]{1,12}$/.test(name); 20 | }; 21 | 22 | export const filter_public_key = (public_key, symbol = 'EOS') => { 23 | let reg = new RegExp('^'+symbol); 24 | return public_key.replace(reg, ''); 25 | } 26 | 27 | // 验证私钥 WIF 格式 28 | export const isValidPrivate = (...args) => ecc.isValidPrivate(...args); 29 | 30 | export const isValidPublic = (public_key, symbol = 'EOS') => { 31 | public_key = filter_public_key(public_key, symbol); 32 | return ecc.isValidPublic(public_key) 33 | } 34 | 35 | // 验证金额格式 36 | export const isValidAmount = (value, { precision = 4 } = {}) => { 37 | if (isNaN(value)) return false; 38 | const decimal = `${value}`.split('.')[1]; 39 | if (decimal) { 40 | if (decimal.length > precision) return false; 41 | } 42 | return true; 43 | }; 44 | 45 | // 验证手续费率 46 | export const isValidRate = (...args) => true; 47 | -------------------------------------------------------------------------------- /src/renderer/views/account/AccountDetail.vue: -------------------------------------------------------------------------------- 1 | 22 | 144 | -------------------------------------------------------------------------------- /src/renderer/views/account/AlternateNode.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 66 | 67 | 100 | -------------------------------------------------------------------------------- /src/renderer/views/account/BpList.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 120 | 121 | 150 | -------------------------------------------------------------------------------- /src/renderer/views/account/Claim.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 164 | 165 | 183 | 184 | -------------------------------------------------------------------------------- /src/renderer/views/account/MyFixVote.vue: -------------------------------------------------------------------------------- 1 | 49 | 50 | 152 | 153 | 185 | -------------------------------------------------------------------------------- /src/renderer/views/account/Myvote.vue: -------------------------------------------------------------------------------- 1 | 88 | 89 | 177 | 178 | 210 | -------------------------------------------------------------------------------- /src/renderer/views/account/NetCpu.vue: -------------------------------------------------------------------------------- 1 | 64 | 65 | 237 | 238 | 256 | 257 | -------------------------------------------------------------------------------- /src/renderer/views/account/RateInstructions.vue: -------------------------------------------------------------------------------- 1 | 114 | 115 | 120 | 121 | 149 | -------------------------------------------------------------------------------- /src/renderer/views/account/TokenList.vue: -------------------------------------------------------------------------------- 1 | 51 | 52 | 85 | 86 | 111 | -------------------------------------------------------------------------------- /src/renderer/views/account/TransferRecord.vue: -------------------------------------------------------------------------------- 1 | 74 | 75 | 143 | 144 | -------------------------------------------------------------------------------- /src/renderer/views/account/Unfreeze.vue: -------------------------------------------------------------------------------- 1 | 55 | 56 | 189 | 190 | 209 | 210 | -------------------------------------------------------------------------------- /src/renderer/views/account/Unfreeze4ram.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 206 | 207 | 227 | 228 | -------------------------------------------------------------------------------- /src/renderer/views/account/Vote4ramList.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 114 | 115 | 148 | -------------------------------------------------------------------------------- /src/renderer/views/components/ImportWalletForm.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 195 | -------------------------------------------------------------------------------- /src/renderer/views/components/concat_form.vue: -------------------------------------------------------------------------------- 1 | 72 | 100 | -------------------------------------------------------------------------------- /src/renderer/views/components/os_uri.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/renderer/views/components/select.vue: -------------------------------------------------------------------------------- 1 | 11 | 27 | -------------------------------------------------------------------------------- /src/renderer/views/entry/Entry.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 25 | 26 | 67 | 68 | -------------------------------------------------------------------------------- /src/renderer/views/layout/PageHeader.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 116 | 117 | 294 | -------------------------------------------------------------------------------- /src/renderer/views/layout/PageMenu.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 76 | 77 | 117 | 118 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/CreateKey.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 49 | 50 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/ImportKey.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/ImportWalletFile.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/WalletImport.vue: -------------------------------------------------------------------------------- 1 | 58 | 59 | 175 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/WalletNew.vue: -------------------------------------------------------------------------------- 1 | 36 | 81 | 82 | 121 | -------------------------------------------------------------------------------- /src/renderer/views/wallet/config_node_list.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 101 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eosforce/wallet-desktop/d00303aff73fb797f0cd380184065a281af3d734/static/.gitkeep -------------------------------------------------------------------------------- /static/term.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 用户条款 8 | 9 | 10 |
 11 |   《eosforcewallet服务协议》
 12 |   最近更新于:2018年6月20日
 13 |   尊敬的用户:
 14 |   感谢您选择eosforcewallet服务。《eosforcewallet服务协议》(以下简称“本协议”)由eosforcewallet Team(以下简称“EFWT”或“我们”)和用户(以下简称“您”或“用户”)签订,本协议在您与EFWT之间具有合同上的法律效力。
 15 |   EFWT在此特别提醒您在使用eosforcewallet之前,请认真阅读《eosforcewallet服务协议》及后文提到的相关协议,尤其是本协议规定的“免责及责任限制”等条款将以加粗的形式体现,确保您充分理解本协议中各条款,并自主考虑风险。
 16 |   一、 关于本协议的确认与接纳
 17 |   您理解本协议及有关协议适用于eosforcewallet及eosforcewallet上EFWT所自主开发和拥有的去中心化应用(简称“DApp”)(排除第三方开发的DApp)。
 18 |   您下载eosforcewallet软件并创建或导入钱包,即视为您已经充分阅读并接受本协议全部条款,本协议立即生效,对双方具有约束力。
 19 |   本协议可由EFWT随时更新,经修改的协议一经在eosforcewallet上公布,立即自动生效,恕不再另行通知。在EFWT公布修改协议条款后,如果您不接受修改后的条款,请立即停止使用eosforcewallet,您继续使用eosforcewallet将被视为接受修改后的协议。
 20 |   如果您未满18周岁,或者是无民事行为能力人或限制民事行为能力人,请在父母或监护人指导下使用eosforcewallet。
 21 |   二、 定义
 22 |   eosforcewallet:指由EFWT基于EOS单链系统开发的区块链钱包,包括其他为方便用户使用区块链系统而开发的辅助工具。
 23 |   用户:
 24 |   (1)用户必须是具备完全民事行为能力的自然人;
 25 |   (2)若您为18周岁以下的未成年人使用eosforcewallet服务,需要在您父母或监护人的指导下使用eosforcewallet。无民事行为能力人使用eosforcewallet或限制民事行为能力人超过其民事权利或行为能力范围从事交易的,造成的一切后果,eosforcewallet有权要求您及您的父母或监护人负责。
 26 |   能力测评问卷:指在您使用eosforcewallet之前(及在将来的使用过程中),需通过能力测评问卷以证明您了解区块链科技和知识,具备合理使用和管理去中心化钱包的基本能力。
 27 |   创建或导入钱包:指您使用eosforcewallet,确认履行本协议并创建或导入钱包的过程。
 28 |   钱包密码:指您在创建eosforcewallet钱包过程中,软件操作界面提示您填写的密码,该密码用于加密保护私钥。作为去中心化的应用,钱包密码不存储在您的这台移动设备或EFWT的服务器,一旦丢失你需要借助明文私钥或助记词重置新密码。
 29 |   信息提示:eosforcewallet软件操作界面涉及的信息提示内容,建议用户按照相关步骤进行操作。
 30 |   特定用户:指按照中国法律法规及政策规定必须要配合EFWT履行个人信息披露义务的用户。
 31 |   私钥:由随机字符构成,是用户拥有并使用数字代币的核心。
 32 |   公钥:由私钥借助密码学原理单向推导生成,并用以生成区块链数字钱包地址,数字钱包地址即为公开收款地址。
 33 |   助记词:符合区块链BIP39 行业标准,由随机算法生成的12(或15/18/21/24)个有序单词组成。是私钥的易记录表现形式,方便用户备份保管。
 34 |   Keystore: 是私钥或助记词经过用户设置的钱包密码加密保存的文件形式,它只存储在您的这台移动设备中,不会同步至EFWT服务器。
 35 |   数字代币:指eosforcewallet目前支持的数字代币种类,包括但不限于EOS、EOSA、EOSB等。
 36 |   三、 服务内容
 37 |   创建或导入钱包。对eosforcewallet支持的数字代币,您可以使用eosforcewallet生成新钱包或导入相关区块链系统的其它钱包工具生成的兼容钱包。
 38 |   转账、收款。您可以使用eosforcewallet的转账、收款功能进行数字代币的管理,即运用私钥进行电子签名,对相关区块链的账本进行修改。转账是指付款方利用收款方的区块链地址进行转账操作,实际的转账、收款行为均在相关区块链系统(而非eosforcewallet)发生。
 39 |   管理数字资产。您可以使用eosforcewallet添加、保管并移除eosforcewallet所支持的数字代币(EOS除外)。
 40 |   交易记录。我们将通过区块链系统拷贝您全部或部分的交易记录。但交易记录以区块链系统的记载为准。
 41 |   暂停服务。您知悉基于区块链系统交易“不可撤销”的属性,我们不能为您暂停或撤销转账交易等操作,但在一定情况下,我们可以暂停或者限制某位用户对eosforcewallet软件的操作。
 42 |   其他EFWT认为有必要提供的服务。
 43 |   用户接受EFWT提供的上述服务时应了解以下常见问题:
 44 |   秉承着区块链的去中心化特点,并为了保护用户的数字代币安全,EFWT提供的是去中心化服务,大大区别于银行业金融机构。用户了解,EFWT不提供以下服务:
 45 |   (1)存储用户的钱包密码(即用户创建/导入钱包时设置的密码)、私钥、助记词、Keystore;
 46 |   (2)找回用户的钱包密码、私钥、助记词、Keystore;
 47 |   (3)冻结钱包;
 48 |   (4)挂失钱包;
 49 |   (5)恢复钱包;
 50 |   (6)交易回滚。
 51 |   由于EFWT不提供上述服务,因此用户应当自行保管含有eosforcewallet的移动设备、备份eosforcewallet、备份钱包密码、助记词、私钥及Keystore。如用户遗失移动设备、删除且未备份eosforcewallet、删除且未备份钱包、钱包被盗或遗忘钱包密码、私钥、助记词、Keystore,EFWT均无法还原钱包或找回钱包密码、私钥、助记词、Keystore;如用户进行交易时误操作(例如输错转账地址),EFWT亦无法取消交易。
 52 |   EFWT和eosforcewallet所能够提供的数字代币管理服务并未包括所有已存在的数字代币,请勿通过eosforcewallet操作任何eosforcewallet不支持的数字代币。
 53 |   eosforcewallet仅是用户的数字代币管理工具,并非交易所或交易平台。虽然本协议将多次提及“交易”,其行为泛指用户使用eosforcewallet进行的转账和收款操作,这与交易所或交易平台上进行的“交易”有本质区别。
 54 |   eosforcewallet上集成的DApp包括EFWT自主拥有的DApp和第三方平台提供的DApp。对于第三方平台提供的DApp,eosforcewallet仅为用户进入DApp提供区块链浏览器。用户在第三方DApp上接受服务或进行交易前应自行判断和评估该第三方DApp提供的服务或交易是否存在风险。
 55 |   四、 您的权利义务
 56 |   (一)创建或导入钱包
 57 |   创建或导入钱包:您有权在您的移动设备上通过eosforcewallet创建和/或导入钱包,有权设定钱包的钱包密码等信息,并有权通过eosforcewallet应用程序,使用自己的钱包在区块链上进行转账和收款等交易。
 58 |   身份验证:按照有关法律法规和政策要求,特定用户在使用eosforcewallet提供的有关服务时,应当按照eosforcewallet的提示及时完成相关身份验证,要求您提交包括但不限于您的姓名、身份证号码、手机号码、银行卡号信息等个人信息。否则该特定用户将无法使用有关服务,因特定用户拖延造成的损失由您自行承担。
 59 |   EFWT可能为不同的终端设备开发不同的软件版本,您应当根据实际需要选择下载合适的版本进行安装。如果您从未经合法授权的第三方获取本软件或与本软件名称相同的安装程序,EFWT将无法保证该软件能否正常使用,也无法保证其安全性,因此造成的损失由您自行承担。
 60 |   本软件新版本发布后,旧版软件可能无法使用。EFWT不保证旧版软件的安全性、继续可用性及提供相应的客户服务。请您随时核对并下载最新版本。
 61 |   (二)使用
 62 |   用户应自行妥善保管移动设备、钱包密码、私钥、助记词、Keystore等信息。EFWT不负责为用户保管以上信息。因您遗失移动设备、主动或被动泄露、遗忘钱包密码、私钥、助记词、Keystore或遭受他人攻击、诈骗等所引起的一切风险、责任、损失、费用应由您自行承担。
 63 |   遵循信息提示。您了解并同意遵循eosforcewallet对您做出的信息提示,按照信息提示的内容进行操作,否则,由此引起的一切风险、责任、损失、费用等应由您自行承担。
 64 |   您知悉并理解eosforcewallet没有义务对链接的第三方DApp服务或交易履行尽职调查义务,您应当理性做出投资决策并自主承担相应的投资风险。
 65 |   积极完成身份验证。当eosforcewallet合理认为您的交易行为或交易情况出现异常的,或认为您的身份信息存在疑点的,或eosforcewallet认为应核对您身份证件或其他必要文件的情形时,请您积极配合eosforcewallet核对您的有效身份证件或其他必要文件,及时完成相关的身份验证。
 66 |   转账。
 67 |   (1)您知悉对于eosforcewallet服务中您可使用的日计转账限额和笔数,可能因为您使用该转账服务时所处的国家/地区、监管要求、转账目的、eosforcewallet风险控制、身份验证等事由而不同。
 68 |   (2)您理解基于区块链操作的“不可撤销”属性,当您使用eosforcewallet转账功能时,您应当自行承担因您操作失误而导致的后果(包括但不限于因您输错转账地址、您自身选择转账节点服务器的问题)。
 69 |   (3)您知悉eosforcewallet仅向您提供转账工具,在您使用eosforcewallet完成转账后,EFWT即完成了当次服务的所有义务,EFWT对其他纠纷争议,不负担任何义务。
 70 |   合法合规。您知悉在eosforcewallet进行操作时或利用eosforcewallet上的DApp进行交易时,您应当遵循有关法律法规、国家政策的要求。
 71 |   公告通知。eosforcewallet会以网站公告、电子邮件、发送短信、电话、消息中心信息、弹窗提示或客户端通知等方式向您发送通知,例如通知您交易进展情况,或者提示您进行相关操作,请您及时予以关注。
 72 |   五、 您合法使用EFWT服务的承诺
 73 |   您应遵守中华人民共和国相关法律法规及您所居住的国家或地区的法律法规,不得将eosforcewallet用于任何非法目的,也不得以任何非法方式使用EFWT服务。
 74 |   您不得利用eosforcewallet从事违法或犯罪的行为,包括但不限于:
 75 |   (1)反对宪法所确定的基本原则,危害国家安全、泄漏国家秘密、颠覆国家政权、破坏国家统一的;
 76 |   (2)从事任何违法犯罪行为,包括但不限于洗钱、非法集资等;
 77 |   (3)通过使用任何自动化程序、软件、引擎、网络爬虫、网页分析工具、数据挖掘工具或类似工具,接入EFWT服务、收集或处理EFWT所提供的内容,干预或试图干预任何用户或任何其他方式接入EFWT服务的行为;
 78 |   (4)提供赌博资讯或以任何方式引诱他人参与赌博;
 79 |   (5)侵入他人eosforcewallet钱包盗取数字代币;
 80 |   (6)进行与交易对方宣称的交易内容不符的交易,或不真实的交易;
 81 |   (7)从事任何侵害或可能侵害eosforcewallet服务系统、数据之行为;
 82 |   (8)其他违法以及EFWT有正当理由认为不适当的行为。
 83 |   您理解并同意,如因您违反有关法律(包括但不限于海关及税务方面的监管规定)或者本协议之规定,使EFWT遭受任何损失、受到任何第三方的索赔或任何行政管理部门的处罚,您应对EFWT进行赔偿,包括合理的律师费用。
 84 |   您承诺按时缴纳EFWT的服务费用(如有),否则EFWT有权暂停或中止对您提供的服务。
 85 |   六、 隐私条款
 86 |   EFWT十分重视对用户隐私的保护,相关隐私保护政策请参考EFWT公布并不时更新的《eosforcewallet隐私政策》。
 87 |   七、 免责及责任限制
 88 |   EFWT仅对本协议中所列明的义务承担责任。
 89 |   您理解和同意,在法律所允许的范围内,EFWT只能按照现有的技术水平和条件提供服务。因下列原因导致eosforcewallet无法正常提供服务,EFWT不承担责任:
 90 |   (1)eosforcewallet系统停机维护或升级;
 91 |   (2)因台风、地震、洪水、雷电或恐怖袭击等不可抗力原因;
 92 |   (3)您的移动设备软硬件和通信线路、供电线路出现故障的;
 93 |   (4)您操作不当或未通过EFWT授权或认可的方式使用EFWT服务的;
 94 |   (5)因病毒、木马、恶意程序攻击、网络拥堵、系统不稳定、系统或设备故障、通讯故障、电力故障、银行等原因或政府行为等原因;
 95 |   (6)非因EFWT的原因而引起的任何其它原因。
 96 |   EFWT对以下情形不承担责任:
 97 |   (1)因用户遗失移动设备、删除且未备份eosforcewallet、删除且未备份钱包、钱包被盗或遗忘钱包密码、私钥、助记词、Keystore而导致的数字代币丢失;
 98 |   (2)因用户自行泄露钱包密码、私钥、助记词、Keystore,或借用、转让或授权他人使用自己的移动设备或eosforcewallet钱包,或未通过EFWT官方渠道下载eosforcewallet应用程序或其他不安全的方式使用eosforcewallet应用程序导致的数字代币丢失;
 99 |   (3)因用户误操作(包括但不限于您输错转账地址、您自身选择转账节点服务器的问题)导致的数字代币丢失;
100 |   (4)因用户不理解区块链技术的性质而进行误操作导致的数字代币丢失;
101 |   (5)因时间滞后、区块链系统不稳定等原因导致EFWT拷贝用户在区块链上的交易记录发生偏差;
102 |   (6)用户在第三方DApp上操作产生的风险和后果。
103 |   您理解eosforcewallet仅作为您数字代币管理的工具。EFWT不能控制第三方DApp提供的产品及服务的质量、安全或合法性,信息的真实性或准确性,以及相对方履行其在与您签订的协议项下的各项义务的能力。所有您在第三方DApp进行的交易行为系您的个人行为,有约束力的合同关系在您和您的相对方之间建立,与eosforcewallet无关。EFWT提醒您应该通过自己的谨慎判断确定登录DApp及相关信息的真实性、合法性和有效性。您与任何第三方交易所产生的风险亦应由您自行承担。
104 |   EFWT可能同时为您及您的交易对手方提供服务,您同意对EFWT可能存在的该等行为予以明确豁免任何实际或潜在的利益冲突,并不得以此来主张EFWT在提供服务时存在法律上的瑕疵,也不因此而加重EFWT的责任或注意义务。
105 |   EFWT不提供以下形式的保证:
106 |   (1)EFWT服务将符合您的全部需求;
107 |   (2)您经由EFWT服务取得的任何技术、产品、服务、资讯将符合您的期望;
108 |   (3)EFWT从第三方交易所抓取的数字代币市场交易行情等信息的及时性、准确性、完整性、可靠性做出保证;
109 |   (4)您在eosforcewallet上的交易各方会及时履行其在与您达成的交易协议中各项义务。
110 |   在任何情况下,EFWT对本协议所承担的违约赔偿责任总额不超过1)1个EOS;或2)人民币100元,以较高的为准。
111 |   您理解eosforcewallet仅作为用户管理数字代币、显示交易信息的工具,EFWT不提供法律、税务或投资建议等服务。您应当自行向法律、税务、投资方面的专业人士寻求建议,且您在使用我们服务过程中所遭受的投资损失、数据损失等,EFWT概不负责。
112 |   您理解根据有关中国政策法规的要求,我们可能不时更改我们的用户准入标准,限定向某一特定群体提供服务的范围和方式等。
113 |   八、 完整协议
114 |   本协议由《eosforcewallet服务协议》、《eosforcewallet隐私政策》及EFWT不时公布的各项规则(包括“帮助中心”的内容)组成。
115 |   本协议部分内容被有管辖权的法院认定为违反或无效的,不因此影响其他内容的效力。
116 |   本协议的任何译文版本仅为方便用户而提供,无意对本协议的条款进行修改。如果本协议的中文版本与非中文版本之间存在冲突,应以中文版本为准。
117 |   九、 知识产权保护
118 |   eosforcewallet系EFWT开发并拥有知识产权的应用程序。 eosforcewallet中显示的任何内容(包括本协议、公告、文章、视频、音频、图片、档案、资讯、资料、商标或标识)的知识产权归EFWT或第三方权利人所有。用户仅可为持有和管理数字代币之目的使用eosforcewallet应用程序及其中的内容。未经EFWT或第三方权利人的事先书面同意,任何人不得擅自使用、修改、反向编译、复制、公开传播、改变、散布、发行或公开发表上述应用程序及内容。
119 |   十、 法律适用与争议解决
120 |   本协议及其修订版之效力、解释、变更、执行与争议解决均适用中华人民共和国法律,如无相关法律规定,则应当适用国际商业惯例和(或)行业惯例。
121 |   若您和EFWT之间发生任何纠纷或争议,首先应友好协商解决,协商不成的,任何一方可提交EFWT所在地有管辖权的人民法院管辖。
122 |   十一、 其他
123 |   如您是中华人民共和国以外用户,您需全面了解并遵守您所在司法辖区与使用EFWT服务所有相关法律、法规及规则。
124 |   您在使用EFWT服务过程中,如遇到任何问题,您可以通过在eosforcewallet提交反馈等方式联系我们。
125 |   您可以在eosforcewallet中查看本协议。 EFWT鼓励您在每次访问eosforcewallet时都查阅EFWT的服务协议。
126 |   本协议自2018年6月20日起适用。
127 |   本协议未尽事宜,您需遵守EFWT不时更新的公告及相关规则。
128 |       eosforcewallet logo © 2018 eosforcewallet Team
129 |   
130 | 131 | -------------------------------------------------------------------------------- /upgrade.md: -------------------------------------------------------------------------------- 1 | # 发布流程 2 | 3 | 关于构建和发布和更新的详细文档可以参见 [electron-builder](https://github.com/electron-userland/electron-builder) 4 | 5 | ## CI 6 | 7 | 在项目里有两个配置文件 `.travis.yml` 和 `appveyor.yml` 分别对应 `travis-ci` 和 `appveyor` 两个平台。 8 | 9 | `travis-ci` 负责构建 `mac` 和 `linux` 的 app。`appveyor` 负责构建 `windows` 平台的 app。他们会监控 `master` 分支的代码,如果 `master` 有变更,就会开始构建任务。构建完成后,平台会检测 github releases 里面,是否有和 package.version 版本号相对应的 releases 的草稿,如果用则会自动上传构建好的文件到该草稿里面。 10 | 11 | ## 实际流程 12 | 13 | 当准备发布一个新版本的时候。 14 | 15 | 1. 按照语义化版本的规则,修改 develop 分支的 package 的版本号,例如 v1.1.1。 16 | 2. 在 github releases 增加 tag 为 v1.1.1 的 releases 草稿。tag 可以本地创建 push 到库里面,也可以直接通过 releases 创建。 17 | 18 | ![releases1](./screenshot/releases1.png) 19 | 20 | 3. 将 develop 合并到 master。此时平台会开始自动构建。可以在 branches 里面查看构建状态。 21 | 22 | ![releases1](./screenshot/branches.png) 23 | 24 | 4. 当平台构建完成且上传全部结束后,找到 v1.1.1 的 releases 草稿。点击发布。 25 | 26 | ## 自动更新 27 | 28 | v1.0.3 版本会检测 github release 是否有新版本发布。从而提示更新。v1.0.4 版本将会通过阿里云检查下载更新。 29 | 30 | `autoUpdater.setFeedURL('https://updatewallet.oss-cn-hangzhou.aliyuncs.com/latest/');` 31 | 32 | git releases 更新后,将所有文件下载下来,然后上传到 `https://updatewallet.oss-cn-hangzhou.aliyuncs.com/latest/` 这个目录即可。 --------------------------------------------------------------------------------