├── CONTRIBUTION.md ├── LICENSE.md ├── README.md ├── gulpfile.js ├── package-lock.json ├── package.json ├── pulse └── manifest.json └── src ├── app ├── app.js ├── components │ ├── Communication │ │ ├── controller.js │ │ ├── custom_actions.html │ │ ├── send_confirmation.html │ │ └── show.html │ ├── Dashboard │ │ ├── dashboard.html │ │ ├── dashboardController.js │ │ └── private_mode.html │ ├── Extra │ │ ├── controller.js │ │ ├── cpu.html │ │ ├── customNetwork.html │ │ ├── customToken.html │ │ └── info_and_help.html │ ├── Home │ │ ├── Controller.js │ │ └── home.html │ ├── KeyDownload │ │ ├── controller.js │ │ ├── exportkey.html │ │ ├── keydownload.html │ │ └── show.html │ ├── Notices │ │ ├── controller.js │ │ ├── lets_get_started.html │ │ ├── phishing_policy.html │ │ ├── privacy_policy.html │ │ ├── terms_and_conditions.html │ │ └── welcome.html │ ├── RecoverAccount │ │ ├── recover.html │ │ └── recoverController.js │ ├── Registration │ │ ├── controller.js │ │ ├── fees.html │ │ └── registration.html │ └── Transaction │ │ ├── controller.js │ │ ├── receive.html │ │ ├── send.html │ │ ├── send_confirmation.html │ │ ├── show_history.html │ │ └── transaction_status.html ├── config │ ├── config.js │ └── settings.js ├── constants │ └── enums.js └── services │ ├── EosServices.js │ ├── account.js │ ├── contentScriptService.js │ ├── encryption.js │ ├── storage.js │ └── validation.js ├── assets ├── images │ ├── Polygon.png │ ├── add-network.png │ ├── add-token.png │ ├── arrow-black.png │ ├── back.png │ ├── background.png │ ├── background1.png │ ├── confirmed-gray.png │ ├── confirmed-selected.png │ ├── copy-icon.png │ ├── cpu.png │ ├── dahboard-logo.png │ ├── down-arrow-white.png │ ├── down-arrow.png │ ├── edit.png │ ├── eos-logo.png │ ├── export.png │ ├── failed-gray.png │ ├── failed-selected.png │ ├── green-circle.png │ ├── hamburger-icon.png │ ├── import.png │ ├── info.png │ ├── key.png │ ├── logo-128.png │ ├── logo-16.png │ ├── logo-48.png │ ├── logo-white.png │ ├── logout.png │ ├── menu-close.png │ ├── new.png │ ├── password-text.png │ ├── password.png │ ├── plan-circle.png │ ├── privacy_mode.png │ ├── qr-code.png │ ├── settings-close.png │ ├── settings.png │ ├── submitted-gray.png │ ├── submitted-selected.png │ ├── top-logo.png │ ├── wallet.png │ └── white-selector.png └── scss │ ├── actions.scss │ ├── colors.scss │ ├── common.scss │ ├── communication.scss │ ├── cpu.scss │ ├── dashboard.scss │ ├── fees.scss │ ├── home.scss │ ├── notice.scss │ ├── receive.scss │ ├── style.scss │ ├── styles.scss │ ├── transaction.scss │ └── welcome.scss ├── background.js ├── contentscript.js └── index.html /CONTRIBUTION.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | Excited by our work and want to get involved in building out our extension releases? Or maybe you haven't learned as much about the EOS protocol but are a savvy developer? 4 | 5 | You can explore our [Current Projects](https://github.com/KoinEx/pulse) in-the works for our different releases. Feel free to fork our repo and start creating PR’s after assigning yourself to an issue of interest. We are always chatting on [Discord](https://discord.gg/zHymkdB) drop us a line there if you want to get more involved or have any questions on our implementation! 6 | 7 | ## Contribution Steps 8 | 9 | **1. Set up Pulse following the instructions in README.md.** 10 | 11 | **2. Fork the Pulse repo.** 12 | 13 | Sign in to your Github account or create a new account if you do not have one already. Then navigate your browser to https://github.com/KoinEx/pulse . In the upper right hand corner of the page, click “fork”. This will create a copy of the Pulse repo in your account. 14 | 15 | **3. Create a local clone of Pulse.** 16 | 17 | ``` 18 | $ git clone https://github.com/KoinEx/pulse.git 19 | ``` 20 | 21 | **4. Link your local clone to the fork on your Github repo.** 22 | 23 | ``` 24 | $ git remote add mypulserepo https://github.com//pulse.git 25 | ``` 26 | 27 | **5. Link your local clone to the repo so that you can easily fetch future changes to the Pulse repo.** 28 | 29 | ``` 30 | $ git remote add pulse https://github.com/KoinEx/pulse.git 31 | $ git remote -v (you should see pulse and mypulserepo in the list of remotes) 32 | ``` 33 | 34 | **6. Find an issue to work on.** 35 | 36 | Check out open issues at https://github.com/KoinEx/pulse/issues and pick one. Leave a comment to let the development team know that you would like to work on it. Or examine the code for areas that can be improved and leave a comment to the development team to ask if they would like you to work on it. 37 | 38 | **7. Create a local branch with a name that clearly identifies what you will be working on.** 39 | 40 | ``` 41 | $ git checkout -b feature-in-progress-branch 42 | ``` 43 | 44 | **8. Make improvements to the code.** 45 | 46 | Each time you work on the code be sure that you are working on the branch that you have created as opposed to your local copy of the Koinex Pulse repo. Keeping your changes segregated in this branch will make it easier to merge your changes into the repo later. 47 | 48 | ``` 49 | $ git checkout feature-in-progress-branch 50 | ``` 51 | 52 | **9. Test your changes.** 53 | 54 | Changes that only affect a single file can be tested with 55 | 56 | 57 | **10. Stage the file or files that you want to commit.** 58 | 59 | ``` 60 | $ git add --all 61 | ``` 62 | 63 | This command stages all of the files that you have changed. You can add individual files by specifying the file name or names and eliminating the “-- all”. 64 | 65 | **11. Commit the file or files.** 66 | 67 | ``` 68 | $ git commit -m “Message to explain what the commit covers” 69 | ``` 70 | 71 | You can use the –amend flag to include previous commits that have not yet been pushed to an upstream repo to the current commit. 72 | 73 | **12. Rebase your branch atop of the latest version of Pulse.** 74 | 75 | ``` 76 | $ git rebase pulse/master 77 | ``` 78 | 79 | If there are conflicts between your edits and those made by others since you started work Git will ask you to resolve them. To find out which files have conflicts run ... 80 | 81 | ``` 82 | $ git status 83 | ``` 84 | 85 | Open those files one at a time and you 86 | will see lines inserted by Git that identify the conflicts: 87 | 88 | ``` 89 | <<<<<< HEAD 90 | Other developers’ version of the conflicting code 91 | ====== 92 | Your version of the conflicting code 93 | '>>>>> Your Commit 94 | ``` 95 | 96 | The code from the Pulse repo is inserted between <<< and === while the change you have made is inserted between === and >>>>. Remove everything between <<<< and >>> and replace it with code that resolves the conflict. Repeat the process for all files listed by git status that have conflicts. 97 | 98 | **14. Push your changes to your fork of the Pulse repo.** 99 | 100 | Rebasing a pull request changes the history on your branch, so Git will reject a normal git push after a rebase. Use a force push to move your changes to your fork of the repo. 101 | 102 | ``` 103 | $ git push mypulserepo feature-in-progress-branch -f 104 | ``` 105 | 106 | **15. Check to be sure your fork of the Pulse repo contains your feature branch with the latest edits.** 107 | 108 | Navigate to your fork of the repo on Github. On the upper left where the current branch is listed, change the branch to your feature-in-progress-branch. Open the files that you have worked on and check to make sure they include your changes. 109 | 110 | **16. Create a pull request.** 111 | 112 | Navigate your browser to https://github.com/KoinEx/pulse and click on the new pull request button. In the “base” box on the left, leave the default selection “base master”, the branch that you want your changes to be applied to. In the “compare” box on the right, select feature-in-progress-branch, the branch containing the changes you want to apply. You will then be asked to answer a few questions about your pull request. After you complete the questionnaire, the pull request will appear in the list of pull requests at https://github.com/KoinEx/pulse/pulls. 113 | 114 | **17. Respond to comments by Core Contributors.** 115 | 116 | Core Contributors may ask questions and request that you make edits. If you set notifications at the top of the page to “not watching,” you will still be notified by email whenever someone comments on the page of a pull request you have created. If you are asked to modify your pull request, repeat steps 8 through 15, then leave a comment to notify the Core Contributors that the pull request is ready for further review.1 117 | 118 | We love working with people that are autonomous, bring independent thoughts to the team, and are excited for their work! We believe in a merit-based approach to becoming a core contributor, and any part-time contributor that puts in the time, work, and drive can become a core member of our team. 119 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ### OPEN SOURCE LICENSE FOR THE SOURCE CODE 2 | 3 | ## MIT License 4 | 5 | Copyright (c) 2019 Discidium Internet Labs Private Limited 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to deal in the Software without restriction, 8 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 9 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 17 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PULSE - Chrome Extension for EOS. 2 | 3 | Pulse is an open source browser extension for EOS blockchain. It enables easy integration with customised dApps and supports multiple accounts on various EOS networks. 4 | Pulse can be used to transact all EOS based tokens. One can send, receive or stake EOS and its custom tokens from wallets and exchanges globally. One can easily contribute to the Pulse source code or can even create multiple extensions on top of it. The open repository even allows developers to create similar dApps such as Pulse. It features a Private mode which if enabled helps in protecting sensitive information from connected dApps 5 | 6 | ## Dapp Developers 7 | 8 | Following API are exposed for Dapp Development : 9 | 10 | ```js 11 | pulse object can be accessed from every js enabled website under window object. 12 | 13 | All the functions provided below are return promises which have to be handled. 14 | 15 | pulse contains a variable network which provides selected network 16 | 17 | 18 | 1. pulse.connect() : To connect the Dapp with extension. 19 | response object 20 | {status:"success",data:{account_name:"selected_account_name",tokens:["1.0000 EOS","10.0000 JUNGLE"]}} 21 | {status:"error",message:"some error message",code:"error code"} 22 | 23 | 24 | 2. pulse.sendTransaction({to:"helloworld12",amount:"1.0000",symbol:"EOS",memo:"h"}): //given keys are mandatory 25 | This API helps to send the EOS from Dapp to desired destination. 26 | 27 | response object 28 | {status:"error",message:"some error message",code:"error code"} // if non-blockchain error occurs 29 | 30 | 31 | 32 | options = {param1:"value", ... } // params for contract action 33 | 3. pulse.sendCustomAction("your_contract_address","contract_action_name", options ): 34 | 35 | Helps in performing custom actions from selected contract. 36 | 37 | 4. pulse.init() 38 | 39 | Helps in updating pulse object. 40 | 41 | ``` 42 | ## Example 43 | 44 | ```js 45 | if (pulse){ 46 | // extension installed 47 | 48 | const network = pusle.network; 49 | if (network != "mainnet"){ 50 | // user is not on mainnet ask to switch if required 51 | // do pulse.init() to get the pulse object updated without and re-assign the network = pusle.network; 52 | // or do window.reload() 53 | } else { 54 | // bussiness logic 55 | // as per logic do sendTransaction or sendCustomAction 56 | 57 | } 58 | } 59 | 60 | ``` 61 | 62 | ## Error Codes 63 | 64 | ```js 65 | code : '30152' // user rejected the requests 66 | code : '30153' // privacy mode is on 67 | code : '30156' // no account configured yet 68 | code : '30157' // missing required fiels 69 | 70 | ``` 71 | 72 | ### Prerequisites 73 | 74 | ``Nodejs`` 75 | 76 | ### Building from Source 77 | 78 | ``` 79 | git clone 80 | npm install 81 | npm start 82 | 83 | After npm start your server will start and a folder (pulse) will be generated. 84 | Now add this folder as chrome extension 85 | ``` 86 | 87 | ## Running 88 | 89 | ``` 90 | Steps to add a chrome extension 91 | 92 | open chrome 93 | click more tools option 94 | select extensions option 95 | enable developer option by toggle switch in the right top 96 | click on load unpacked option and choose the folder (pulse) i.e you just generated using npm start 97 | ``` 98 | 99 | 100 | ## Built With 101 | 102 | `npm` 103 | 104 | ## Contributing 105 | 106 | We have put all of our contribution guidelines into [CONTRIBUTION.md](CONTRIBUTION.md) Check it out to get started. 107 | 108 | ## Authors 109 | 110 | * **Himanshu Singh** 111 | 112 | ## License 113 | 114 | This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details 115 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var sass = require('gulp-sass'); 3 | var browserify = require('browserify'); 4 | var source = require('vinyl-source-stream'); 5 | var browserSync = require('browser-sync').create(); 6 | 7 | 8 | 9 | gulp.task('scripts', function(){ 10 | return browserify(['./src/app/services/contentScriptService.js']) 11 | .transform("babelify", {presets: [["es2015"],["minify",{mangle:true,removeConsole:true,builtIns:false}]]}) 12 | .bundle() 13 | .pipe(source('vendor.min.js')) 14 | .pipe(gulp.dest('./pulse/')); 15 | }); 16 | 17 | 18 | gulp.task('browserify', function() { 19 | return browserify(['./src/app/app.js']) 20 | .transform("babelify", {plugins: ["angularjs-annotate"],presets: [["es2015"],["minify",{mangle:true,removeConsole:true,builtIns: false}]]}) 21 | .bundle() 22 | .pipe(source('main.js')) 23 | .pipe(gulp.dest('./pulse/')); 24 | }) 25 | 26 | 27 | gulp.task('background',['contentScript'],function() { 28 | return browserify(['./src/background.js']) 29 | .transform("babelify", {presets: [["es2015"],["minify",{mangle:true,removeConsole:true,builtIns: false}]]}) 30 | .bundle() 31 | .pipe(source('background.js')) 32 | .pipe(gulp.dest('./pulse/')); 33 | }) 34 | 35 | gulp.task('contentScript',function() { 36 | return browserify(['./src/contentscript.js']) 37 | .transform("babelify", {presets: [["es2015"],["minify",{mangle:true,removeConsole:true,builtIns:false}]]}) 38 | .bundle() 39 | .pipe(source('contentscript.js')) 40 | .pipe(gulp.dest('./pulse/')); 41 | }) 42 | 43 | gulp.task('images',function() { 44 | gulp.src('./src/**/*.png') 45 | .pipe(gulp.dest('./pulse')) 46 | }); 47 | 48 | 49 | gulp.task('copy', ['browserify','scss'], function() { 50 | gulp.src(['./src/**/*.html','./src/**/styles.css']) 51 | .pipe(gulp.dest('./pulse')) 52 | .pipe(browserSync.stream()) 53 | }); 54 | 55 | gulp.task('scss', function() { 56 | gulp.src('./src/assets/scss/styles.scss') 57 | .pipe(sass({outputStyle: 'compressed'}).on('error', sass.logError)) 58 | .pipe(gulp.dest('./src/assets/stylesheets/')); 59 | }); 60 | 61 | 62 | 63 | gulp.task('build',['scss', 'copy' ,'background', 'scripts','images']); 64 | 65 | gulp.task('browser-sync', ['build'], function() { 66 | browserSync.init({ 67 | server: { 68 | baseDir: "./pulse", 69 | }, 70 | }); 71 | }); 72 | 73 | 74 | gulp.task('default', ['browser-sync'], function(){ 75 | gulp.watch("./src/**/*.*", ["build"]); 76 | gulp.watch("./pulse/**/*.*").on('change', browserSync.reload); 77 | }) 78 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eoswallet", 3 | "version": "0.0.2", 4 | "description": "cold wallet for eos", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "gulp" 8 | }, 9 | "dependencies": { 10 | "angular": "^1.5.11", 11 | "angular-animate": "^1.4.7", 12 | "angular-aria": "^1.4.7", 13 | "angular-clipboard": "^1.6.2", 14 | "angular-ladda": "^0.4.0", 15 | "angular-qrcode": "^7.2.0", 16 | "angular-sanitize": "^1.7.4", 17 | "angular-ui-router": "^1.0.19 ", 18 | "await-to-js": "^2.1.1", 19 | "crypto-js": "^3.1.9-1", 20 | "eosjs": "^16.0.6", 21 | "fingerprintjs": "^0.5.3", 22 | "ng-csv": "^0.3.6", 23 | "ngletteravatar": "^4.0.4", 24 | "request": "^2.88.0", 25 | "request-promise": "^4.2.2" 26 | }, 27 | "devDependencies": { 28 | "babel-core": "^6.26.3", 29 | "babel-minify": "^0.5.0", 30 | "babel-plugin-angularjs-annotate": "^0.10.0", 31 | "babel-preset-es2015": "^6.24.1", 32 | "babelify": "^8.0.0", 33 | "browser-sync": "^2.26.3", 34 | "browserify": "^12.0.0", 35 | "gulp": "^3.9.1", 36 | "gulp-sass": "^2.1.0", 37 | "vinyl-source-stream": "^1.1.0" 38 | }, 39 | "author": "Himanshu Singh ", 40 | "license": "ISC" 41 | } 42 | -------------------------------------------------------------------------------- /pulse/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "EOS Pulse", 3 | "description": "Pulse is an open source browser extension for the EOS blockchain. It's a gateway to send, receive or stake EOS and custom tokens.", 4 | "version": "0.1.2", 5 | "permissions": [ 6 | "notifications", 7 | "storage", 8 | "webRequest", 9 | "activeTab", 10 | "unlimitedStorage", 11 | "" 12 | ], 13 | "background":{ 14 | "persistent": true, 15 | "scripts":[ 16 | "background.js" 17 | ] 18 | }, 19 | "content_scripts": [ { 20 | "all_frames": true, 21 | "js": [ "contentscript.js" ], 22 | "matches": [ "file://*/*", "http://*/*", "https://*/*" ], 23 | "run_at": "document_start" 24 | } ], 25 | "browser_action": { 26 | "default_title": "EOS Pulse", 27 | "default_popup": "index.html", 28 | "default_icon":"assets/images/logo-48.png" 29 | }, 30 | "web_accessible_resources": [ 31 | "assets/images/*.png", 32 | "vendor.min.js" 33 | ], 34 | "icons": { 35 | "16": "assets/images/logo-16.png", 36 | "48": "assets/images/logo-48.png", 37 | "128": "assets/images/logo-128.png" 38 | }, 39 | "manifest_version": 2 40 | } -------------------------------------------------------------------------------- /src/app/app.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular'; 2 | import router from 'angular-ui-router'; 3 | import HomeController from './components/Home/Controller'; 4 | import TransactionController from './components/Transaction/controller'; 5 | import AccountController from './components/Registration/controller'; 6 | import AccountService from './services/account'; 7 | import DashboardController from './components/Dashboard/dashboardController'; 8 | import RecoverController from './components/RecoverAccount/recoverController'; 9 | import keyDownloadController from './components/KeyDownload/controller'; 10 | import NoticeController from './components/Notices/controller'; 11 | import CommunicationController from './components/Communication/controller'; 12 | import CustomController from './components/Extra/controller'; 13 | import storage from './services/storage'; 14 | import EosService from './services/EosServices'; 15 | import EncryptionService from './services/encryption'; 16 | import ValidationService from './services/validation'; 17 | import qrcode from 'qrcode-generator'; 18 | import ngQrcode from 'angular-qrcode'; 19 | import 'angular-clipboard'; 20 | import 'ng-csv'; 21 | import 'angular-sanitize'; 22 | import 'ngletteravatar'; 23 | 24 | window.qrcode = qrcode; 25 | const eosWallet = angular.module('eosWallet', [router,'angular-clipboard','ngSanitize','ngCsv',ngQrcode,'ngLetterAvatar']) 26 | .controller('HomeController',HomeController) 27 | .controller('AccountController',AccountController) 28 | .controller('TransactionController',TransactionController) 29 | .controller('DashboardController',DashboardController) 30 | .controller('RecoverController',RecoverController) 31 | .controller('keyDownloadController',keyDownloadController) 32 | .controller('CommunicationController',CommunicationController) 33 | .controller('NoticeController',NoticeController) 34 | .controller('CustomController',CustomController) 35 | .service('AccountService',AccountService) 36 | .service('EosService',EosService) 37 | .service('EncryptionService',EncryptionService) 38 | .service('ValidationService',ValidationService) 39 | .service('StorageService',storage); 40 | 41 | 42 | eosWallet.config(($stateProvider,$urlRouterProvider,$compileProvider) =>{ 43 | $urlRouterProvider.otherwise("/"); 44 | $compileProvider.imgSrcSanitizationWhitelist(/^\s*((https?|ftp|file|blob|chrome-extension):|data:image\/)/); 45 | $stateProvider 46 | .state('home',{ 47 | url:'/', 48 | templateUrl:'app/components/home/home.html', 49 | controller:'HomeController', 50 | controllerAs:'vm' 51 | }) 52 | .state('register',{ 53 | url:'/register', 54 | templateUrl:'app/components/Registration/registration.html', 55 | controller:'AccountController', 56 | controllerAs:'vm' 57 | }) 58 | .state('registerMainnet',{ 59 | url:'/register/mainnet', 60 | templateUrl:'app/components/Registration/fees.html', 61 | controller:'AccountController', 62 | controllerAs:'vm' 63 | }) 64 | .state('dashboard',{ 65 | url:'/dashboard', 66 | templateUrl:'app/components/Dashboard/dashboard.html', 67 | controller:'DashboardController', 68 | controllerAs:'vm' 69 | }) 70 | .state('recoverAccount',{ 71 | url:'/recoverAccount', 72 | templateUrl:'app/components/RecoverAccount/recover.html', 73 | controller:'RecoverController', 74 | controllerAs:'vm' 75 | }) 76 | .state('receiveToken',{ 77 | url:'/receiveToken', 78 | templateUrl:'app/components/Transaction/receive.html', 79 | controller:'TransactionController', 80 | controllerAs:'vm' 81 | }) 82 | .state('sendToken',{ 83 | url:'/sendToken', 84 | templateUrl:'app/components/Transaction/send.html', 85 | controller:'TransactionController', 86 | controllerAs:'vm' 87 | }) 88 | .state('sendConfirmation',{ 89 | url:'/sendToken/confirmation', 90 | templateUrl:'app/components/Transaction/send_confirmation.html', 91 | controller:'TransactionController', 92 | controllerAs:'vm' 93 | }) 94 | .state('keyDownload',{ 95 | url:'/keyDownload', 96 | templateUrl:'app/components/KeyDownload/keydownload.html', 97 | controller:'keyDownloadController', 98 | controllerAs:'vm' 99 | }) 100 | .state('handshake',{ 101 | url:'/handshake', 102 | templateUrl:'app/components/Communication/show.html', 103 | controller:'CommunicationController', 104 | controllerAs:'vm' 105 | }) 106 | .state('externalSend',{ 107 | url:'/sendToken/external', 108 | templateUrl:'app/components/Communication/send_confirmation.html', 109 | controller:'TransactionController', 110 | controllerAs:'vm' 111 | }) 112 | .state('externalCustomSend',{ 113 | url:'/sendToken/external_custom', 114 | templateUrl:'app/components/Communication/custom_actions.html', 115 | controller:'TransactionController', 116 | controllerAs:'vm' 117 | }) 118 | .state('exportKey',{ 119 | url:'/exportkey', 120 | templateUrl:'app/components/KeyDownload/exportkey.html', 121 | controller:'keyDownloadController', 122 | controllerAs:'vm' 123 | }) 124 | .state('transactionStatus',{ 125 | url:'/sendToken/status', 126 | templateUrl:'app/components/Transaction/transaction_status.html', 127 | controller:'TransactionController', 128 | controllerAs:'vm' 129 | }) 130 | .state('showTransactionHistory',{ 131 | url:'/transaction_history', 132 | templateUrl:'app/components/Transaction/show_history.html', 133 | controller:'TransactionController', 134 | controllerAs:'vm' 135 | }) 136 | .state('welcome',{ 137 | url:'/welcome', 138 | templateUrl:'app/components/Notices/welcome.html', 139 | controller:'NoticeController', 140 | controllerAs:'vm' 141 | }) 142 | .state('termsAndConditions',{ 143 | url:'/termsAndConditions', 144 | templateUrl:'app/components/Notices/terms_and_conditions.html', 145 | controller:'NoticeController', 146 | controllerAs:'vm' 147 | }) 148 | .state('privacyPolicy',{ 149 | url:'/privacyPolicy', 150 | templateUrl:'app/components/Notices/privacy_policy.html', 151 | controller:'NoticeController', 152 | controllerAs:'vm' 153 | }) 154 | .state('phishingPolicy',{ 155 | url:'/phishingPolicy', 156 | templateUrl:'app/components/Notices/phishing_policy.html', 157 | controller:'NoticeController', 158 | controllerAs:'vm' 159 | }) 160 | .state('letsGetStarted',{ 161 | url:'/letsGetStarted', 162 | templateUrl:'app/components/Notices/lets_get_started.html', 163 | controller:'NoticeController', 164 | controllerAs:'vm' 165 | }) 166 | .state('whyRecover',{ 167 | url:'/whyRecover', 168 | templateUrl:'app/components/KeyDownload/show.html', 169 | controller:'keyDownloadController', 170 | controllerAs:'vm' 171 | }) 172 | .state('infoAndHelp',{ 173 | url:'/infoAndHelp', 174 | templateUrl:'app/components/Extra/info_and_help.html', 175 | controller:'CustomController', 176 | controllerAs:'vm' 177 | }) 178 | .state('privacyMode',{ 179 | url:'/privacyMode', 180 | templateUrl:'app/components/Dashboard/private_mode.html', 181 | controller:'DashboardController', 182 | controllerAs:'vm' 183 | }) 184 | .state('customNetwork',{ 185 | url:'/customNetwork', 186 | templateUrl:'app/components/Extra/customNetwork.html', 187 | controller:'CustomController', 188 | controllerAs:'vm' 189 | }) 190 | .state('customToken',{ 191 | url:'/customToken', 192 | templateUrl:'app/components/Extra/customToken.html', 193 | controller:'CustomController', 194 | controllerAs:'vm' 195 | }) 196 | .state('cpuInfo',{ 197 | url:'/cpuInfo', 198 | templateUrl:'app/components/Extra/cpu.html', 199 | controller:'CustomController', 200 | controllerAs:'vm' 201 | }); 202 | }); 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /src/app/components/Communication/controller.js: -------------------------------------------------------------------------------- 1 | import { Database_Controllers,External_Channels,Error_Codes} from '../../constants/enums'; 2 | 3 | export default class CommunicationController { 4 | // this controller is fot connecting a user user to the dapps 5 | constructor(StorageService,$scope){ 6 | this.store = StorageService; 7 | this.scope = $scope; 8 | this.connect = chrome.runtime.connect; 9 | this.port = this.connect({name:External_Channels.CONNECT}); 10 | this.init(); 11 | } 12 | 13 | async init(){ 14 | const networkController = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME); 15 | this.currentNetwork = networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]; 16 | const accountController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 17 | this.accountName = accountController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED].split('_')[0]; 18 | this.tokens = accountController[Database_Controllers.ACCOUNT_CONTROLLER.TOKENS]; 19 | const tempController = await this.store.get(Database_Controllers.EXTRA.NAME); 20 | this.host = tempController[Database_Controllers.EXTRA.TEMP_DATA].host; 21 | this.protocol = tempController[Database_Controllers.EXTRA.TEMP_DATA].protocol; 22 | this.favIcon = tempController[Database_Controllers.EXTRA.TEMP_DATA].favIcon || false; 23 | tempController[Database_Controllers.EXTRA.TEMP_DATA]={}; 24 | const tempData = {}; 25 | tempData[Database_Controllers.EXTRA.NAME] = tempController; 26 | await this.store.set(tempData); 27 | this.scope.$apply(); 28 | 29 | } 30 | 31 | allow(){ 32 | this.port.postMessage({allowed:true,data:{account_name:this.accountName,tokens:this.tokens}}); 33 | this.port.disconnect(); 34 | window.close(); 35 | } 36 | 37 | block(){ 38 | this.port.postMessage({allowed:false,messase:"User rejected the request",code:Error_Codes.USER_REJECTED}); 39 | this.port.disconnect(); 40 | window.close(); 41 | } 42 | 43 | } 44 | 45 | CommunicationController.$inject = ['StorageService','$scope']; 46 | -------------------------------------------------------------------------------- /src/app/components/Communication/custom_actions.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |
12 |
13 | {{vm.protocol}}//{{vm.host}}/ 14 |
15 | 16 |
17 | Wants you to sign this transaction 18 |
19 |
20 | 21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 | 29 | 30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 |
38 |
39 | 40 | 41 |
42 |
43 |
44 |
45 |
{{vm.error}}
46 |
47 |
48 | 55 |
56 | 63 |
64 |
65 |
66 | -------------------------------------------------------------------------------- /src/app/components/Communication/send_confirmation.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 |
11 |
12 |
13 | {{vm.protocol}}//{{vm.host}}/ 14 |
15 | 16 |
17 | Wants you to sign this transaction 18 |
19 |
20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 | 32 | 33 |
34 |
35 |
36 | 37 | 44 | 45 |
46 | 47 | 54 |
55 |
56 |
57 |
58 |
{{vm.error}}
59 |
60 |
-------------------------------------------------------------------------------- /src/app/components/Communication/show.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
7 |
Connection Request
8 |
9 |
10 |
11 | {{vm.protocol}}//{{vm.host}}/ 12 |
13 |
14 |
15 | 16 | 17 | 18 | 19 | 20 |
21 |
22 |
{{ vm.accountName }}
23 |
{{vm.protocol}}//{{vm.host}}
24 |
25 |
28 | Learn more 29 |
30 |
31 | 38 |
39 | 46 |
47 |
48 |
49 |
50 | -------------------------------------------------------------------------------- /src/app/components/Dashboard/private_mode.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
What is Private Mode?
7 |
Enabling Private Mode denies access to your data on EOS Pulse for all external parties. Integration with dApps is not allowed when Private Mode is enabled
8 |
9 | 10 | Enable Private Mode 11 | 12 | 16 |
17 |
18 | 19 | -------------------------------------------------------------------------------- /src/app/components/Extra/controller.js: -------------------------------------------------------------------------------- 1 | import { Database_Controllers,Networks,Errors,Channel_Names } from '../../constants/enums'; 2 | import to from 'await-to-js'; 3 | export default class CustomController { 4 | // custom controller for addon features netwotk,adding token, and CPU delegation and undelegation 5 | constructor(StorageService,EosService,ValidationService,$state,$scope){ 6 | this.store = StorageService; 7 | this.customNetwork = {}; 8 | this.state = $state; 9 | this.eosService = EosService; 10 | this.networkAttributes = ['name','host','port','protocol']; 11 | this.error = ""; 12 | this.scope = $scope; 13 | this.networkController=""; 14 | this.customToken = {}; 15 | this.ladda = false; 16 | this.accountName = ""; 17 | this.balance = ""; 18 | this.validationService = ValidationService; 19 | this.tokenAttributes = ['contract','token','decimalPrecision']; 20 | this.init(); 21 | } 22 | 23 | 24 | 25 | decimalPrecision(){ // to check for decimal precision 26 | const decimalPrecision = 4; 27 | this.transaction.CPU_quantity = Math.floor(this.transaction.CPU_quantity * Math.pow(10,decimalPrecision)) / Math.pow(10,decimalPrecision); 28 | this.transaction.net_quantity = Math.floor(this.transaction.net_quantity * Math.pow(10,decimalPrecision)) / Math.pow(10,decimalPrecision); 29 | } 30 | 31 | 32 | async init(){ 33 | const accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 34 | this.selected = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 35 | this.selectedOperation = 'delegate'; 36 | if(this.selected) { 37 | this.accountName = this.selected.split('_')[0]; 38 | this.cpuInfo = accountsController[this.selected][Database_Controllers.ACCOUNT_CONTROLLER.CPU_LIMIT]; 39 | this.netInfo = accountsController[this.selected][Database_Controllers.ACCOUNT_CONTROLLER.NET_LIMIT]; 40 | this.balance = accountsController[this.selected][Database_Controllers.ACCOUNT_CONTROLLER.BALANCE]; 41 | this.transaction = {symbol:'EOS',from:this.accountName,receiver:this.accountName}; 42 | } 43 | } 44 | 45 | async submitRequest(){ // this for the cpu delegation and undelegation 46 | this.ladda = true; 47 | this.transaction.type = this.selectedOperation; 48 | const validationResponse = await this.validationService.validatePartialDelicateTxn(this.transaction); 49 | if(validationResponse == true){ 50 | this.transactionController = await this.store.getTransactions() || {}; 51 | this.transactionController[Database_Controllers.TRANSACTION_CONTROLLER.TRANSACTION] = this.transaction; 52 | const transactionController = {}; 53 | transactionController[Database_Controllers.TRANSACTION_CONTROLLER.NAME] = this.transactionController; 54 | await this.store.setTransaction(transactionController); 55 | await this.store.setState('sendConfirmation'); 56 | this.ladda=false; 57 | this.state.go('sendConfirmation'); 58 | } else { 59 | this.ladda = false; 60 | this.error = validationResponse; 61 | this.scope.$apply(); 62 | return ; 63 | } 64 | } 65 | 66 | cpuOperation(operation){ // updating the operation type of cpu 67 | this.selectedOperation = operation; 68 | } 69 | 70 | 71 | async addNetwork(){ // add a custom network 72 | this.error = ''; 73 | this.ladda = true; 74 | let allParamas = true; 75 | 76 | const accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 77 | const accounts = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS]; 78 | 79 | if(accounts[this.customNetwork.name] ) { // checking if same network name is already present or not 80 | this.error = Errors.DUPLICATE_NETWORK_NAME; 81 | this.ladda = false; 82 | this.scope.$apply(); 83 | return ; 84 | } 85 | 86 | Object.keys(Networks).map((key)=>{ // checking if same network name is already present or not in default networks 87 | if(this.customNetwork.name == Networks[key]){ 88 | this.error = Errors.DUPLICATE_NETWORK_NAME; 89 | this.ladda = false; 90 | this.scope.$apply(); 91 | return ; 92 | } 93 | }); 94 | 95 | this.networkAttributes.forEach((attribute)=>{ // checking for all the required fields 96 | if(!this.customNetwork[attribute]){ 97 | allParamas = false; 98 | } 99 | }); 100 | 101 | const httpEndPoint = `${this.customNetwork.protocol}://${this.customNetwork.host}:${this.customNetwork.port}`; 102 | const [errorGettingInfo,networkInfo] = await to(this.eosService.getInfo(httpEndPoint)); // checking if node is runnig 103 | 104 | if(errorGettingInfo){ 105 | this.error=Errors.WRONG_NODE_ADDRESS; 106 | console.log(errorGettingInfo); 107 | this.ladda = false; 108 | this.scope.$apply(); 109 | return ; 110 | } else{ 111 | console.log(networkInfo); 112 | this.customNetwork.chainId = networkInfo.chain_id; 113 | } 114 | 115 | if(allParamas){ 116 | this.networkController = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME); 117 | const customNetwork = this.networkController[Database_Controllers.NETWORK_CONTROLLER.CUSTOM_NETWORKS] || {}; 118 | customNetwork[this.customNetwork.name] = this.customNetwork; 119 | this.networkController[Database_Controllers.NETWORK_CONTROLLER.CUSTOM_NETWORKS] = customNetwork; 120 | const networkData = {}; 121 | networkData[Database_Controllers.NETWORK_CONTROLLER.NAME]=this.networkController; 122 | accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][this.customNetwork.name] = []; 123 | const accountsData = {}; 124 | accountsData[Database_Controllers.ACCOUNT_CONTROLLER.NAME] = accountsController; 125 | this.store.set(networkData); 126 | this.store.set(accountsData); 127 | this.ladda = false; 128 | this.state.go('dashboard'); 129 | } else{ 130 | this.ladda = false; 131 | this.error = Errors.MI; 132 | this.scope.$apply(); 133 | } 134 | } 135 | 136 | async addToken(){ // adding a custom token 137 | this.ladda= true; 138 | this.error = ''; 139 | let allParamas = true; 140 | this.tokenAttributes.forEach((attribute)=>{ // checking for all required fields 141 | if(!this.customToken[attribute]){ 142 | allParamas = false; 143 | } 144 | }); 145 | 146 | let [error] = await to(this.eosService.getAccountByName({account_name:this.customToken.contract})); 147 | 148 | if(error){ 149 | this.error = Errors.INCORRECT_CONTRACT; 150 | this.ladda= false; 151 | this.scope.$apply(); 152 | return; 153 | } 154 | 155 | [error] = await to(this.eosService.getCurrencyBalance({acount:this.accountName,code:this.customToken.contract,symbol:this.customToken.token})); 156 | 157 | if(error){ // to check if this token is present on the blockchain or not 158 | this.error = Errors.TOKEN_DOESNOT_EXISTS; 159 | this.ladda= false; 160 | this.scope.$apply(); 161 | return; 162 | } 163 | 164 | if(allParamas){ 165 | await this.store.setCustomToken(this.customToken); 166 | const port = chrome.runtime.connect({name: Channel_Names.SYNC_BALANCE}); 167 | port.postMessage({message:`Check balance of current user`}); 168 | port.onMessage.addListener(async (message)=>{ this.state.go('dashboard'); this.ladda= false;}); 169 | } else{ 170 | this.error = Errors.MISSING_FIELDS; 171 | this.ladda= false; 172 | this.scope.$apply(); 173 | } 174 | 175 | } 176 | 177 | gotoDashboard(){ 178 | this.state.go('dashboard'); 179 | } 180 | 181 | 182 | } 183 | 184 | CustomController.$inject = ['StorageService','EosService','ValidationService','$state','$scope'] -------------------------------------------------------------------------------- /src/app/components/Extra/cpu.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |
7 |
8 | wallet 9 |
Available Balance
10 |
{{vm.accountName}}
11 |
{{vm.balance}} EOS
12 |
13 |
14 |
Net Available
15 |
{{ vm.netInfo.available }} Bytes
16 |
CPU Available
17 |
{{ (vm.cpuInfo.available)/1000 }} ms
18 |
19 |
20 |
21 |
22 | 23 | 24 |
25 |
26 |
27 |
28 | 29 |
30 | 31 | 32 |
33 |
34 |
35 | 36 |
37 | 38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
{{vm.error}}
47 |
48 |
49 | 56 |
57 | 64 |
65 |
66 |
67 |
-------------------------------------------------------------------------------- /src/app/components/Extra/customNetwork.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 |
8 |
9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 | 25 | 26 |
27 | 28 | 29 |
30 |
{{vm.error}}
31 |
32 | 33 |
34 | 41 |
42 | 48 |
49 |
50 |
-------------------------------------------------------------------------------- /src/app/components/Extra/customToken.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 |
8 |
9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 |
17 | 18 |
19 | 20 | 21 |
22 | 23 |
24 |
{{vm.error}}
25 |
26 | 27 |
28 | 35 |
36 | 42 |
43 |
44 |
-------------------------------------------------------------------------------- /src/app/components/Extra/info_and_help.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 6 |
7 |
8 |
9 | 11 | 12 |
13 |
EOS Pulse Version 0.0.2
14 |
EOS Pulse is designed and built in India
15 |
EOS Pulse is an open source browser extension for the EOS blockchain. It is a gateway to send, receive or stake EOS and its custom tokens. It enables easy integration with customised dApps and supports multiple accounts on various EOS networks.
16 | 23 |
24 |
25 | 26 | -------------------------------------------------------------------------------- /src/app/components/Home/Controller.js: -------------------------------------------------------------------------------- 1 | import {fees,creator} from '../../config/config'; 2 | import { Database_Controllers,Errors } from '../../constants/enums'; 3 | import { HASH } from 'crypto-js'; 4 | 5 | 6 | 7 | export default class Homecontroller { 8 | // this is the home/entrypoint controller 9 | constructor($state,StorageService,EncryptionService,EosService,ValidationService,$scope){ 10 | this.txnID=''; 11 | this.store = StorageService; 12 | this.eosService = EosService; 13 | this.fees = fees; 14 | this.creator = creator; 15 | this.state = $state; 16 | this.scope = $scope; 17 | this.password =''; 18 | this.error=''; 19 | this.cnpassword =''; 20 | this.encryptionService=EncryptionService; 21 | this.validationService= ValidationService; 22 | this.accountsController ={}; 23 | this.extra={}; 24 | this.typePassword = true; 25 | this.typeCnPassword=true; 26 | this.validations = { 27 | length:false, 28 | lowercase:false, 29 | uppercase:false, 30 | digit:false, 31 | specialCharacter:false 32 | } 33 | this.validationText = { 34 | length:'8 or more characters long', 35 | lowercase:'At least 1 lowercase character', 36 | uppercase:'At least 1 UPPERCASE character', 37 | digit:'At least 1 number', 38 | specialCharacter:'At least 1 special character' 39 | } 40 | this.warning = "Choose a strong password which will consistently be required for all actions. This password is not recoverable. Please memorise or store the password in a safe place."; 41 | this.init(); 42 | } 43 | 44 | async init() { 45 | if(!(await this.store.get('back')) && await this.store.get('onboarding')){ // condition for navigation to next state 46 | const state = await this.store.get(Database_Controllers.STATE_CONTROLLER.NAME); 47 | const current_state = state[Database_Controllers.STATE_CONTROLLER.CURRENT]; 48 | if(current_state) this.state.go(current_state); 49 | } 50 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 51 | this.pass = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] || ''; 52 | this.salt = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] || ''; 53 | this.scope.$apply(); 54 | } 55 | 56 | 57 | verifyPassword(){ // this is to check for all password validation 58 | const validationResponse = this.validationService.validatePassword(this.password); // please see the validation service for more details 59 | if(validationResponse == true){ 60 | Object.keys(this.validations).map((key)=>{ 61 | this.validations[key] = true; 62 | }); 63 | } else{ 64 | this.validations = validationResponse; 65 | } 66 | } 67 | 68 | getRandomSalt() { 69 | return (Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) ); 70 | } 71 | 72 | async createMasterAccount() { // to create the password 73 | this.error = ''; 74 | if(this.password && this.cnpassword && this.password === this.cnpassword) { 75 | const validationResponse = this.validationService.validatePassword(this.password); 76 | if(validationResponse != true) { 77 | this.error = Errors.PASSWORD_VALIDATION; 78 | this.resetError(); 79 | return ; 80 | } 81 | const salt = this.getRandomSalt(); 82 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] = HASH( this.password + salt ).toString(); 83 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] = await this.encryptionService.encryptSalt(this.password,salt); 84 | const accountsController = {}; 85 | accountsController[Database_Controllers.ACCOUNT_CONTROLLER.NAME] = this.accountsController; 86 | await this.store.set(accountsController); 87 | this.store.setState('register'); 88 | this.state.go('register'); 89 | } else if(! this.password ) { 90 | this.error = Errors.PASSWORD_MISSING; 91 | } else if (this.password !== this.cnpassword ){ 92 | this.error = Errors.PASSWORD_MUST_SAME; 93 | } 94 | this.resetError(); 95 | } 96 | 97 | async signIn(){ // signin 98 | this.error = ""; 99 | if(this.password && HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString() === this.pass ) { 100 | const state = await this.store.get(Database_Controllers.STATE_CONTROLLER.NAME); 101 | const current_state = state[Database_Controllers.STATE_CONTROLLER.CURRENT]; 102 | if(current_state) this.state.go(current_state); 103 | else this.state.go(Database_Controllers.STATE_CONTROLLER.DEFAULT); 104 | } else if(!this.password){ 105 | this.error = Errors.PASSWORD_MISSING; 106 | this.ladda=false; 107 | this.resetError(); 108 | }else { 109 | this.error = Errors.PASSWORD_MISMATCH; 110 | this.ladda=false; 111 | this.scope.$apply(); 112 | this.resetError(); 113 | } 114 | } 115 | 116 | async recoverAccount() { // navigate to the recover account page 117 | this.store.setState('recoverAccount'); 118 | this.state.go('recoverAccount'); 119 | } 120 | 121 | resetError(){ // to reset the error when user presses any thing 122 | setTimeout(()=>{ 123 | this.error = ''; 124 | },2000) 125 | } 126 | 127 | togglePassword(){ 128 | this.typePassword = !this.typePassword; 129 | } 130 | 131 | toggleCnPassword(){ 132 | this.typeCnPassword = !this.typeCnPassword; 133 | } 134 | } 135 | 136 | Homecontroller.$inject = ['$state','StorageService','EncryptionService','EosService','ValidationService','$scope']; 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/app/components/Home/home.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 | 13 |
14 |
15 |
16 |
17 | 48 |
49 |
50 | 54 |
55 |
56 |
57 |
58 | 79 |
80 | 81 |
-------------------------------------------------------------------------------- /src/app/components/KeyDownload/controller.js: -------------------------------------------------------------------------------- 1 | import { Database_Controllers,Errors } from '../../constants/enums'; 2 | import {HASH} from'crypto-js'; 3 | 4 | export default class KeyDownloadController { 5 | 6 | constructor(StorageService,$state,$scope,EncryptionService){ 7 | this.store = StorageService; 8 | this.key=''; 9 | this.password = ''; 10 | this.state = $state; 11 | this.scope = $scope; 12 | this.error =''; 13 | this.keyDownloaded=false; 14 | this.encryptionService = EncryptionService; 15 | this.accountsController={}; 16 | this.stateController = {}; 17 | this.typePassword=true; 18 | this.ladda = false; 19 | this.init(); 20 | } 21 | 22 | 23 | async init() { 24 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 25 | this.pass = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SALT]; 26 | this.salt = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] || ''; 27 | this.scope.$apply(); 28 | } 29 | 30 | async goToKeyDownload(){ // this to navigate to export private key on onboarding 31 | this.stateController = await this.store.get(Database_Controllers.STATE_CONTROLLER.NAME); 32 | this.store.setState('keyDownload',this.stateController[Database_Controllers.STATE_CONTROLLER.REDIRECT_TO]); 33 | this.state.go('keyDownload'); 34 | } 35 | 36 | async goToNextPage(){ // go to the redirect page 37 | this.stateController = await this.store.get(Database_Controllers.STATE_CONTROLLER.NAME); 38 | let next_state = this.stateController[Database_Controllers.STATE_CONTROLLER.REDIRECT_TO]; 39 | this.store.setState(next_state); 40 | this.state.go(next_state); 41 | } 42 | 43 | async success(){ // when a key is downloaded successfull naviagte to the redirect page 44 | this.ladda = true; 45 | if(HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString()!==this.pass) { 46 | this.error= Errors.PASSWORD_MISMATCH; 47 | this.ladda = false; 48 | this.scope.$apply(); 49 | } else { 50 | this.password=''; 51 | this.accountName=''; 52 | this.privateKeyArray=[]; 53 | this.keyDownloaded = true; 54 | this.ladda = false; 55 | this.goToNextPage(); 56 | } 57 | } 58 | 59 | async exportKey(){ // to export the private key 60 | if(HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString()!==this.pass) { 61 | this.error= Errors.PASSWORD_MISMATCH; 62 | this.scope.$apply(); 63 | } else { 64 | this.password=''; 65 | this.accountName=''; 66 | this.privateKeyArray=[]; 67 | this.keyDownloaded = true; 68 | this.goToNextPage(); 69 | } 70 | } 71 | 72 | fail(err){ // some failure during the export 73 | this.error=Errors.RETRY; 74 | } 75 | 76 | async keyDownload(){ // to check for password if correct change the button (for more deatils check keydownload.html) 77 | this.ladda = false; 78 | this.error = ''; 79 | if(!this.password){ 80 | this.error= Errors.PASSWORD_MISSING; 81 | this.privateKeyArray=[]; 82 | } else if(HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString()!==this.pass) { 83 | this.error = ""; 84 | this.privateKeyArray=[]; 85 | this.scope.$apply(); 86 | } else { 87 | this.ladda = true; 88 | this.error = ""; 89 | const selected = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 90 | let result = this.accountsController[selected]; 91 | this.accountName = result.account_name; 92 | const key = await this.encryptionService.decrypt(this.password,result.keyManager); 93 | this.privateKeyArray = [{accout_name:this.accountName,private_key:key}]; 94 | this.ladda = false; 95 | this.scope.$apply(); 96 | } 97 | } 98 | 99 | togglePassword(){ 100 | this.typePassword = !this.typePassword; 101 | } 102 | } 103 | 104 | KeyDownloadController.$inject = ['StorageService','$state','$scope','EncryptionService']; 105 | -------------------------------------------------------------------------------- /src/app/components/KeyDownload/exportkey.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
EOS Pulse
6 |
7 |
8 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
Enter your Pulse password
24 |
25 | 26 | 27 |
28 |
29 | 32 |
33 |
{{vm.error}}
34 |
35 | 36 |
37 | 38 |
39 | 47 | 55 |
56 | 58 |
59 |
60 | -------------------------------------------------------------------------------- /src/app/components/KeyDownload/keydownload.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
EOS Pulse
6 |
7 |
8 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 | 23 |
Enter your Pulse password
24 |
25 | 26 | 27 |
28 |
29 | 32 |
33 |
{{vm.error}}
34 |
35 | 36 |
37 | 45 | 53 |
54 |
55 | -------------------------------------------------------------------------------- /src/app/components/KeyDownload/show.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 |
Please store your Private Key
10 |
To recover or import your Account to another system you need to save your Private Key.
11 |
12 |
13 |
14 |
01
15 |
16 |
Export Private Key
17 |
Export your Private Key in CSV and save it for backup
18 |
19 |
20 |
21 |
02
22 |
23 |
Confirm Private Key
24 |
Paste your Private Key that you stored to continue further
25 |
26 |
27 |
28 |
29 | 30 |
31 |
-------------------------------------------------------------------------------- /src/app/components/Notices/controller.js: -------------------------------------------------------------------------------- 1 | 2 | export default class NoticeController{ 3 | constructor($state,StorageService,$scope){ 4 | this.state = $state; 5 | this.store = StorageService; 6 | this.scope=$scope; 7 | 8 | } 9 | 10 | async gotoHomePage(state){ // to show all the notices 11 | if(state == 'home'){ 12 | this.store.setState(null); 13 | } else { 14 | this.store.setState(state); 15 | } 16 | this.state.go(state); 17 | } 18 | 19 | } 20 | 21 | NoticeController.$inject = ['$state','StorageService','$scope'] -------------------------------------------------------------------------------- /src/app/components/Notices/lets_get_started.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 |
Let’s get started
10 |
You are a few steps away from building your EOS Pulse account
11 |
12 |
13 |
14 |
01
15 |
16 |
Create Pulse Password
17 |
Create a strong password to start your journey with EOS Pulse
18 |
19 |
20 |
21 |
02
22 |
23 |
Create Account Name
24 |
Enter your details for a new EOS account
25 |
26 |
27 |
or
28 |
29 |
03
30 |
31 |
Import EOS Account
32 |
Import existing EOS account using your Private Key
33 |
34 |
35 |
36 |
37 | 38 |
39 |
-------------------------------------------------------------------------------- /src/app/components/Notices/phishing_policy.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 |
phishing warning
10 |
11 |
12 | Dear EOS Pulse Users,
13 | Please be aware of Phishing attacks. This involves showing a fake EOS Pulse window on the page asking for user's Private Key. Revealing your Private Key to such malicious softwares may result in loss of funds. Users are encouraged to check author/publisher id before downloading the extension 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 |
-------------------------------------------------------------------------------- /src/app/components/Notices/privacy_policy.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 |
Privacy Note
10 |
11 |
12 | EOS Pulse is beta software.
13 | When you log in to EOS Pulse and approve account access, your current account's address is visible to the site you're currently viewing. This can be used to look up your account balances of EOS and other tokens. 14 | For your privacy, take caution when approving account access and sign out of EOS Pulse when you're done using a site. 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 25 |
26 |
-------------------------------------------------------------------------------- /src/app/components/Notices/welcome.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
7 | EOS Pulse 8 |
9 |
10 | Your Gateway to the EOS Blockchain 11 |
12 |
13 | EOS Pulse is an open source browser extension for the EOS blockchain. It is a gateway to send, receive or stake EOS and its custom tokens. It enables easy integration with customised dApps and supports multiple accounts on various EOS networks. 14 |
15 |
16 |
17 |
18 | 19 |
-------------------------------------------------------------------------------- /src/app/components/RecoverAccount/recover.html: -------------------------------------------------------------------------------- 1 |
2 | 5 |
EOS Pulse
6 |
7 |
8 | 9 | 13 |
14 |
15 |
16 |
17 | 55 |
56 |
57 | 58 | 62 |
63 |
64 |
65 |
66 | 103 |
104 | -------------------------------------------------------------------------------- /src/app/components/RecoverAccount/recoverController.js: -------------------------------------------------------------------------------- 1 | import { HASH } from 'crypto-js'; 2 | import { Channel_Names,Database_Controllers,Errors,Networks } from '../../constants/enums'; 3 | import to from 'await-to-js'; 4 | export default class RecoverController { 5 | 6 | constructor(EosService,StorageService,EncryptionService,ValidationService,$state,$scope){ 7 | this.store = StorageService; 8 | this.account_name=''; 9 | this.key=''; 10 | this.cnpassword=''; 11 | this.password = ''; 12 | this.state = $state; 13 | this.scope = $scope; 14 | this.eosService = EosService; 15 | this.error =''; 16 | this.validationService = ValidationService; 17 | this.encryptionService = EncryptionService; 18 | this.accountsController ={}; 19 | this.typePassword = true; 20 | this.typeCnPassword = true; 21 | this.ladda = false; 22 | this.dropdown = false; 23 | this.networks = Networks; 24 | this.validations = { 25 | length:false, 26 | lowercase:false, 27 | uppercase:false, 28 | digit:false, 29 | specialCharacter:false 30 | } 31 | this.validationText = { 32 | length:'8 or more characters long', 33 | lowercase:'At least 1 lowercase character', 34 | uppercase:'At least 1 UPPERCASE character', 35 | digit:'At least 1 number', 36 | specialCharacter:'At least 1 special character' 37 | } 38 | this.warning = "Password is not recoverable and you will lose your funds without them. Please write them down and store them in a safe place"; 39 | } 40 | 41 | async init() { 42 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 43 | this.networkController = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME); 44 | this.store.set({onboarding:true}); 45 | this.onboarding = true; 46 | this.firstPage = true; 47 | this.currentNetwork = this.networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]; 48 | this.scope.$apply(); 49 | } 50 | 51 | // To recover user account and add data to chrome storage. 52 | 53 | getRandomSalt() { 54 | return (Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) ); 55 | } 56 | 57 | verifyPassword(){ 58 | const validationResponse = this.validationService.validatePassword(this.password); 59 | if(validationResponse == true){ 60 | Object.keys(this.validations).map((key)=>{ 61 | this.validations[key] = true; 62 | }); 63 | } else{ 64 | this.validations = validationResponse; 65 | } 66 | } 67 | 68 | async recoverAccount(){ 69 | this.error=''; 70 | if (this.account_name && this.password && this.password === this.cnpassword && this.key && !(this.account_name.search(/^[a-z,1-5]{12}$/))) { 71 | 72 | const validationResponse = this.validationService.validatePassword(this.password); // validate password 73 | if(validationResponse != true){ 74 | this.error = Errors.PASSWORD_VALIDATION; 75 | this.resetError(); 76 | return ; 77 | } 78 | 79 | let [error,userdata] = await to(this.eosService.getAccountByName({account_name:this.account_name})); // checking if account present on blockchain 80 | let active = await this.eosService.privateToPublic(this.key); // getting the public key from private key 81 | 82 | if(error){ 83 | this.error = Errors.ACCOUNT_NOT_FOUND; 84 | this.resetAll(); 85 | this.resetError(); 86 | return; 87 | } 88 | 89 | if(userdata && userdata.permissions[0] && userdata.permissions[0].required_auth.keys[0].key === active){ // if correct private key 90 | this.key = await this.encryptionService.encrypt(this.password,this.key); 91 | const salt = this.getRandomSalt(); 92 | this.accountsController = {}; 93 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.DEFAULT_CURRENCY] = 'USD'; 94 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.DEFAULT_TOKEN] = 'EOS'; 95 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS] = {}; 96 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.TESTNET] = []; 97 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.MAINNET] = []; 98 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.LOCALNET] = []; 99 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] = HASH(this.password + salt).toString(); 100 | this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] = await this.encryptionService.encryptSalt(this.password,salt); 101 | const accountsController = {}; 102 | accountsController[Database_Controllers.ACCOUNT_CONTROLLER.NAME] = this.accountsController; // reset the chrome storage 103 | await this.store.set(accountsController); 104 | await this.store.save({account_name:userdata.account_name,balance:userdata.core_liquid_balance ? `${userdata.core_liquid_balance.split(' ')[0]}` : 0,resources:userdata.total_resources,keyManager:this.key}); 105 | await this.syncBalance(); 106 | this.resetAll(); 107 | this.state.go('dashboard'); 108 | }else { 109 | this.error = Errors.ACCOUNT_AND_KEY_MISSMATCH; 110 | this.resetAll(); 111 | this.resetError(); 112 | } 113 | } else if(!this.password){ 114 | this.error = Errors.PASSWORD_MISSING; 115 | } else if(this.password != this.cnpassword){ 116 | this.error = Errors.PASSWORD_MUST_SAME; 117 | } else if(this.account_name.search(/^[a-z,1-5]{12}$/)){ 118 | this.error = Errors.ACCOUNT_VALIDATION_ERROR; 119 | } else { 120 | this.error = Errors.MISSING_FIELDS; 121 | } 122 | this.resetError(); 123 | } 124 | 125 | syncBalance(){ // sync balance of the current user 126 | return new Promise((resolve,reject)=>{ 127 | const port = chrome.runtime.connect({name: Channel_Names.SYNC_BALANCE}); 128 | port.postMessage({message:`Sync balance of current user`}); 129 | port.onMessage.addListener((message)=>{resolve(true)}); 130 | }); 131 | } 132 | 133 | async gotoSecondPage(){ // to go to the create password page 134 | this.error=''; 135 | this.ladda = true; 136 | if(!this.key || !this.account_name ){ 137 | this.error = Errors.MISSING_FIELDS; 138 | this.ladda = false; 139 | return; 140 | } 141 | const [error,userdata] = await to(this.eosService.getAccountByName({account_name:this.account_name})); 142 | const isValidPrivateKey = this.eosService.isvalidPrivateKey(this.key); 143 | if( error){ 144 | this.error = Errors.ACCOUNT_NOT_FOUND; 145 | this.ladda = false; 146 | this.scope.$apply(); 147 | this.resetError(); 148 | return ; 149 | } else if( isValidPrivateKey != true ) { 150 | this.error = Errors.PRIVATE_KEY_ERROR; 151 | this.ladda = false; 152 | this.scope.$apply(); 153 | this.resetError(); 154 | return ; 155 | } else { 156 | let active = await this.eosService.privateToPublic(this.key); 157 | if(userdata && userdata.permissions[0] && userdata.permissions[0].required_auth.keys[0].key !== active){ 158 | this.error = Errors.ACCOUNT_AND_KEY_MISSMATCH; 159 | this.ladda=false; 160 | this.resetAll(); 161 | this.resetError(); 162 | return ; 163 | } 164 | this.ladda=false; 165 | this.firstPage = false; 166 | this.scope.$apply(); 167 | } 168 | } 169 | 170 | gotoFirstPage(){ // go to account and key page 171 | this.password=''; 172 | this.cnpassword=''; 173 | this.key = ''; 174 | this.firstPage=true; 175 | } 176 | 177 | toggleDropdown(){ 178 | this.dropdown = !this.dropdown; 179 | } 180 | 181 | togglePassword(){ 182 | this.typePassword = !this.typePassword; 183 | } 184 | 185 | toggleCnPassword(){ 186 | this.typeCnPassword = !this.typeCnPassword; 187 | } 188 | 189 | async changeNetwork(value){ // detect network change 190 | this.dropdown=false; 191 | this.balance=''; 192 | this.fiatValue = ''; 193 | this.selectedTabData={}; 194 | this.currentNetwork = this.networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE] = value; 195 | const networkData = {}; 196 | networkData[Database_Controllers.NETWORK_CONTROLLER.NAME] = this.networkController; 197 | await this.store.set(networkData); 198 | this.scope.$apply(); 199 | const port = chrome.runtime.connect({name:Channel_Names.NETWORK_CHANGE}); 200 | port.postMessage('updated network'); 201 | } 202 | 203 | goBack(){ // for back navigation 204 | if(this.firstPage){ 205 | this.store.set({back:true}); 206 | this.store.delete('onboarding'); 207 | this.store.setState('dashboard'); 208 | this.state.go('home'); 209 | return ; 210 | } 211 | this.password = ''; 212 | this.cnpassword=''; 213 | this.key=''; 214 | this.account_name=''; 215 | this.firstPage = true; 216 | } 217 | 218 | resetError(){ 219 | setTimeout(()=>{ 220 | this.error = ''; 221 | },1000) 222 | } 223 | 224 | resetAll(){ 225 | this.password = ''; 226 | this.cnpassword=''; 227 | this.key=''; 228 | this.account_name=''; 229 | this.firstPage = true; 230 | this.scope.$apply(); 231 | } 232 | 233 | } 234 | 235 | RecoverController.$inject = ['EosService','StorageService','EncryptionService','ValidationService','$state','$scope']; 236 | -------------------------------------------------------------------------------- /src/app/components/Registration/controller.js: -------------------------------------------------------------------------------- 1 | import { config } from '../../config/config'; 2 | import { HASH } from 'crypto-js'; 3 | import Fingerprint from 'fingerprintjs'; 4 | import to from 'await-to-js'; 5 | import { Database_Controllers,Channel_Names,Errors ,Networks} from '../../constants/enums'; 6 | 7 | export default class AccountController { 8 | 9 | constructor(AccountService,EosService,StorageService,EncryptionService,$state,$scope){ 10 | this.store = StorageService; 11 | this.txnID=''; 12 | this.creator = config.mainnet.creator; 13 | this.fees = config.mainnet.fees; 14 | this.account_name=''; 15 | this.key=''; 16 | this.cnpassword=''; 17 | this.dropdown = false; 18 | this.accountService = AccountService; 19 | this.password = ''; 20 | this.state = $state; 21 | this.scope = $scope; 22 | this.networks = Networks; 23 | this.eosService = EosService; 24 | this.error =''; 25 | this.encryptionService = EncryptionService; 26 | this.accountController={}; 27 | this.ladda = false; 28 | this.copyText = "Click to copy"; 29 | this.accountNameValidations = { 30 | length:false 31 | }; 32 | this.typePassword = true; 33 | this.warning = "The new account will be created on testnet by default. Once the account is created you will get the option to create one on the mainnet." 34 | } 35 | 36 | 37 | 38 | async init() { 39 | const database = await this.store.getAll(); 40 | this.onboarding = database['onboarding']; 41 | this.store.delete('back'); 42 | this.onboardingRecover = database['onboardingRecover'] || false; 43 | this.accountController = database[Database_Controllers.ACCOUNT_CONTROLLER.NAME] || {}; 44 | this.extraController = database[Database_Controllers.EXTRA.NAME] || {}; 45 | this.Memo = this.extraController[Database_Controllers.EXTRA.MEMO] || this.getRandomSalt(); 46 | this.memo = HASH(this.Memo).toString(); 47 | this.networkController = database[Database_Controllers.NETWORK_CONTROLLER.NAME] || {}; 48 | this.currentNetwork = this.networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE] || ''; 49 | this.pass = this.accountController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] || ''; 50 | this.salt = this.accountController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] || ''; 51 | this.is_forgotAccount = database[Database_Controllers.FORGOT_PASSWORD] || false; 52 | if(this.onboardingRecover) { 53 | this.account_name = this.accountController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED].split('_')[0]; 54 | } 55 | this.scope.$apply(); 56 | this.extraController[Database_Controllers.EXTRA.MEMO] = this.Memo; 57 | const extra = {}; 58 | extra[Database_Controllers.EXTRA.NAME]= this.extraController; 59 | await this.store.set(extra); 60 | } 61 | 62 | getRandomSalt() { 63 | return (Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15) ); 64 | } 65 | 66 | async verifyAndStoreData(){ // after storing the data go to next page 67 | await this.store.set({onboardingRecover:true}); 68 | await this.store.setState('whyRecover','register'); 69 | const extra = {}; 70 | this.extraController[Database_Controllers.EXTRA.MEMO] = ''; 71 | extra[Database_Controllers.EXTRA.NAME] = this.extraController; 72 | await this.store.set(extra); 73 | await this.store.set({is_forgotAccount:true}); 74 | this.state.go('whyRecover') 75 | } 76 | 77 | verifyAccountName(){ 78 | if(this.account_name.length == 12){ 79 | this.accountNameValidations.length = true; 80 | } else { 81 | this.accountNameValidations.length = false; 82 | } 83 | } 84 | 85 | // To Create new Eos Account 86 | async createAccount(){ 87 | this.error = ''; 88 | this.ladda=true; 89 | if (this.password && this.account_name && !(this.account_name.search(/^[a-z,1-5]{12}$/)) && HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString() === this.pass ){ 90 | const ERROR = await to(this.eosService.getAccountByName({account_name:this.account_name})); 91 | if(!ERROR){ 92 | this.error = Errors.DUPLICATE_ACCOUNT; 93 | this.ladda = false; 94 | this.scope.$apply(); 95 | await this.resetError(); 96 | return; 97 | } 98 | const deviceID = new Fingerprint({screen_resolution: true,hasher:HASH}).get().toString(); 99 | const [error,result] = await to(this.eosService.createAccount(this.account_name,deviceID,this.Memo)); 100 | if(error){ 101 | this.error=error.msg; 102 | this.ladda = false; 103 | this.scope.$apply(); 104 | await this.resetError(); 105 | } else { 106 | this.ladda=false; 107 | await this.store.save({account_name:this.account_name,keyManager: await this.encryptionService.encrypt(this.password,result.key)}); 108 | this.verifyAndStoreData(); 109 | } 110 | } else if(!this.account_name || !this.password){ 111 | this.error=Errors.MISSING_FIELDS; 112 | this.ladda = false; 113 | } else if(!this.accountNameValidations.length ){ 114 | this.error=Errors.ACCOUNT_NAME_LENGTH; 115 | this.ladda = false; 116 | }else if(this.account_name.search(/^[a-z,1-5]{12}$/)){ 117 | this.ladda = false; 118 | this.error = Errors.ACCOUNT_VALIDATION_ERROR; 119 | }else if(HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString() !== this.pass ) { 120 | this.error = Errors.PASSWORD_MISMATCH; 121 | this.ladda=false; 122 | this.scope.$apply(); 123 | } else { 124 | this.error= Errors.ACCOUNT_VALIDATION_ERROR; 125 | this.ladda=false; 126 | this.scope.$apply(); 127 | } 128 | this.resetError(); 129 | } 130 | 131 | async verifyTxn(){ // to verify txn if network is mainnet 132 | this.error = ''; 133 | this.ladda = true; 134 | if(this.txnID) { 135 | this.eosService.verifyTxn(this.txnID).then(async (txn)=>{ 136 | if (txn.trx.trx) { 137 | this.data = txn.trx.trx.actions[0].data; 138 | if (this.data.to != this.creator ){ this.error=Errors.INCORRECT_CREATOR;} 139 | else if ( this.data.quantity != this.fees ){this.error=Errors.INCORRECT_AMOUNT;} 140 | else if ( this.data.memo != this.memo ){this.error=Errors.INCORRECT_MEMO_TAG;} 141 | else { 142 | const port = chrome.runtime.connect({name: Channel_Names.SAVE_TXN_ID}); 143 | port.postMessage({id:this.txnID}); 144 | this.store.setState('register'); 145 | await this.store.set({is_forgotAccount:false}); 146 | this.state.go('register'); 147 | } 148 | this.ladda = false; 149 | this.scope.$apply(); 150 | } else { 151 | this.error=Errors.INCORRECT_TXN_ID; 152 | this.ladda = false; 153 | } 154 | }).catch((error)=>{ 155 | console.log(error); 156 | this.error= Errors.COMMON; 157 | this.ladda = false; 158 | this.scope.$apply(); 159 | }); 160 | } else { 161 | this.error = Errors.TRANSACTION_ID_MISSING; 162 | this.ladda = false; 163 | } 164 | } 165 | 166 | 167 | // To recover user account and add data to chrome storage. 168 | 169 | async recoverAccount(){ // 170 | this.ladda=true; 171 | this.error=''; 172 | 173 | if ((this.key && this.onboardingRecover) || (this.account_name && this.password && this.pass == HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString() && this.key && !(this.account_name.search(/^[a-z,1-5]{12}$/)))) { 174 | let [error,userdata] = await to(this.eosService.getAccountByName({account_name:this.account_name})); 175 | const isValidPrivateKey = this.eosService.isvalidPrivateKey(this.key); 176 | 177 | if(!isValidPrivateKey) { 178 | this.error = Errors.PRIVATE_KEY_ERROR; 179 | this.resetAll(); 180 | this.resetError(); 181 | return ; 182 | } 183 | let active = await this.eosService.privateToPublic(this.key); 184 | 185 | if(error){ 186 | this.error = Errors.ACCOUNT_NOT_FOUND; 187 | this.resetAll(); 188 | this.resetError(); 189 | return ; 190 | } 191 | 192 | if(userdata && userdata.permissions[0] && userdata.permissions[0].required_auth.keys[0].key === active){ 193 | if(!this.onboardingRecover) { 194 | this.key = await this.encryptionService.encrypt(this.password,this.key); 195 | await this.store.save({account_name:userdata.account_name,balance:userdata.core_liquid_balance ? `${userdata.core_liquid_balance.split(' ')[0]}` : 0,resources:userdata.total_resources,keyManager:this.key}); 196 | } 197 | await this.syncBalance(); 198 | this.ladda=false; 199 | this.resetAll(); 200 | this.gotoDashboard(); 201 | }else { 202 | this.error = Errors.ACCOUNT_NOT_FOUND; 203 | this.resetAll(); 204 | this.resetError(); 205 | } 206 | }else if(this.account_name.search(/^[a-z,1-5]{12}$/)){ 207 | this.error = Errors.ACCOUNT_VALIDATION_ERROR; 208 | this.ladda = false; 209 | this.scope.$apply(); 210 | }else if(!this.onboardingRecover && this.pass != HASH(this.password + (await this.encryptionService.decryptSalt(this.password,this.salt))).toString() ) { 211 | this.error=Errors.PASSWORD_MISMATCH; 212 | this.ladda=false; 213 | this.scope.$apply(); 214 | } else { 215 | this.error = Errors.MISSING_FIELDS; 216 | this.ladda=false; 217 | } 218 | this.resetError(); 219 | } 220 | 221 | // To show account recover Ui 222 | getRecoverUi(){ 223 | this.is_forgotAccount = !this.is_forgotAccount; 224 | this.store.set({is_forgotAccount:this.is_forgotAccount}); 225 | } 226 | 227 | syncBalance(){ 228 | return new Promise((resolve,reject)=>{ 229 | const port = chrome.runtime.connect({name: Channel_Names.SYNC_BALANCE}); 230 | port.postMessage({message:`Sync balance of current user`}); 231 | port.onMessage.addListener((message)=>{resolve(true)}); 232 | }); 233 | } 234 | 235 | async goBack(){ 236 | if(this.is_forgotAccount){ 237 | this.getRecoverUi(); 238 | return ; 239 | } 240 | this.accountController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] = ''; 241 | const acccoutData = {}; 242 | acccoutData[Database_Controllers.ACCOUNT_CONTROLLER.NAME] = this.accountController; 243 | await this.store.set(acccoutData); 244 | this.store.set({back:true}); 245 | this.state.go('home'); 246 | } 247 | 248 | resetAll(){ 249 | this.password = ''; 250 | this.key=''; 251 | this.ladda=false; 252 | if(!this.onboardingRecover) { 253 | this.account_name=''; 254 | } 255 | this.scope.$apply(); 256 | } 257 | 258 | resetError(){ 259 | setTimeout(()=>{ 260 | this.error = ''; 261 | this.ladda=false; 262 | },2000) 263 | } 264 | 265 | togglePassword(){ 266 | this.typePassword = !this.typePassword; 267 | } 268 | 269 | async changeNetwork(value){ 270 | this.dropdown=false; 271 | this.balance=''; 272 | this.fiatValue = ''; 273 | this.selectedTabData={}; 274 | this.currentNetwork = this.networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE] = value; 275 | const networkData = {}; 276 | networkData[Database_Controllers.NETWORK_CONTROLLER.NAME] = this.networkController; 277 | await this.store.set(networkData); 278 | this.scope.$apply(); 279 | const port = chrome.runtime.connect({name:Channel_Names.NETWORK_CHANGE}); 280 | port.postMessage('updated network'); 281 | } 282 | 283 | 284 | gotoDashboard(){ 285 | this.state.go('dashboard'); 286 | } 287 | 288 | success(){ 289 | this.copyText = "Copied!"; 290 | setTimeout(()=>{ 291 | this.copyText = "Click to copy"; 292 | this.scope.$apply(); 293 | },2000).bind(this); 294 | } 295 | 296 | toggleDropdown(){ 297 | this.dropdown = !this.dropdown; 298 | } 299 | 300 | } 301 | 302 | AccountController.$inject = ['AccountService','EosService','StorageService','EncryptionService','$state','$scope']; 303 | -------------------------------------------------------------------------------- /src/app/components/Registration/fees.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 | 8 |
9 |
10 | Use a wallet or an exchange to send mainnet fee to the EOS blockchain and enter transaction ID below. 11 |
12 |
13 |
14 |
15 | 16 |
17 | 18 | 19 |
20 |
21 |
22 | 23 |
This is an EOS creator account which creates your account on the EOS blockchain.
24 |
25 | 26 | 27 |
28 |
29 |
30 | 31 |
32 | 33 | 34 |
35 |
36 | 37 |
38 | 39 | 40 |
41 | 42 |
43 |
{{vm.error}}
44 |
45 |
46 | 53 |
54 |
-------------------------------------------------------------------------------- /src/app/components/Registration/registration.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 |
EOS Pulse
7 |
8 |
9 | 10 |
11 |
12 | 13 | 19 |
20 |
21 |
22 |
23 |
24 |
25 | 26 |
27 | 30 |
31 |
32 |
33 | 34 |
Only lower cased alphabets (a-z) and numbers (1-5) allowed
35 | 36 |
37 |
38 |
Account name Requirements
39 |
40 |
    41 |
  • 42 | 43 | 44 |
  • 45 |
46 | 47 |
48 | 49 |
Enter your Pulse password
50 |
51 | 52 | 53 |
54 |
55 | 56 |
57 |
{{vm.error}}
58 |
59 | 60 |
61 | 69 |
70 |
71 |
72 |
73 | 74 | 79 |
80 |
81 |
82 |
83 |
84 |
85 | 86 |
87 | 91 |
92 |
93 | {{ value }} 94 |
95 |
96 |
97 |
98 |
99 | 100 | 101 |
102 |
103 | 104 | 105 |
106 |
107 | 108 |
Enter your Pulse password
109 |
110 | 111 | 112 |
113 |
114 |
115 |
{{vm.error}}
116 |
117 |
118 | 126 |
127 |
128 |
129 |
-------------------------------------------------------------------------------- /src/app/components/Transaction/receive.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
Your public wallet address
6 |
Use this address to receive funds
7 |
8 | 9 |
10 |
11 |
12 |
13 |
14 |
15 | {{ vm.accountName }} 16 | 17 | copy-icon 18 | 19 |
20 |
21 | 24 |
25 | -------------------------------------------------------------------------------- /src/app/components/Transaction/send.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 |
8 | 9 | 13 |
14 |
Select Account
15 |
16 | {{ receipent }} 17 |
18 |
19 |
20 |
21 | 22 |
23 | 24 |
25 | 26 | 30 |
31 |
32 | {{ key }} 33 |
34 |
35 |
36 |
37 |
38 | 39 | 40 |
41 |
42 |
{{vm.error}}
43 |
44 |
45 | 52 |
53 | 60 |
61 |
62 |
-------------------------------------------------------------------------------- /src/app/components/Transaction/send_confirmation.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 | 6 |
7 |
8 | 9 | 10 |
11 |
12 |
13 |
14 | 15 |
16 | 17 | 18 |
19 |
20 | 21 |
22 |
{{vm.error}}
23 |
24 |
25 | 32 |
33 | 40 | 41 | 48 |
49 |
50 |
51 |
-------------------------------------------------------------------------------- /src/app/components/Transaction/show_history.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Balance : {{vm.balance}} EOS
4 |
Transaction History
5 |
6 |
7 | 8 | 9 | Submitted 10 |
11 |
12 | 13 | 14 | Confirmed
15 |
16 | 17 | 18 | Failed
19 |
20 |
21 | 22 | 23 | 24 | 25 | 26 |
27 |
28 |
29 |
-------------------------------------------------------------------------------- /src/app/components/Transaction/transaction_status.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
7 | 8 | 9 |
10 |
11 |
12 |
13 | 14 |
15 | 20 | 21 |
22 |
23 |
{{ vm.transaction.reason }}
24 |
25 | 26 |
27 | 28 |
29 |
30 | -------------------------------------------------------------------------------- /src/app/config/config.js: -------------------------------------------------------------------------------- 1 | const testnet = { 2 | configEos:{ 3 | chainId: 'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473', // 32 byte (64 char) hex string //038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca 4 | keyProvider: [], // WIF string or array of keys.. 5 | httpEndpoint: 'https://api.jungle.alohaeos.com:443', // httpEndPoint of Blockchain Node 6 | expireInSeconds: 60, 7 | broadcast: true, 8 | verbose: false, 9 | sign: true 10 | }, 11 | creator:'testnet2eosw', 12 | precision : 4, 13 | fees:'0.0000 EOS' 14 | }; 15 | 16 | const mainnet = { 17 | configEos:{ 18 | chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', // 32 byte (64 char) hex string //038f4b0fc8ff18a4f0842a8f0564611f6e96e8535901dd45e43ac8691a1c4dca 19 | keyProvider: [], // WIF string or array of keys.. 20 | httpEndpoint: 'https://api.eossweden.se', //httpEndPoint of Blockchain Node 21 | expireInSeconds: 60, 22 | broadcast: true, 23 | verbose: false, 24 | sign: true 25 | }, 26 | creator:'pulseaccount', 27 | precision : 4, 28 | fees:'0.4000 EOS' 29 | }; 30 | 31 | 32 | const config = { 33 | testnet, 34 | mainnet 35 | }; 36 | 37 | // config fot eos default networks we are providing 38 | 39 | module.exports = {config}; -------------------------------------------------------------------------------- /src/app/config/settings.js: -------------------------------------------------------------------------------- 1 | const env = process.env.NODE_ENV || 'dev' ; 2 | const dev = { 3 | host:'0.0.0.0', 4 | port:4000, 5 | protocol:'http' 6 | }; 7 | 8 | const config = { 9 | dev 10 | }; 11 | 12 | //config of our server 13 | 14 | 15 | module.exports = config[env]; -------------------------------------------------------------------------------- /src/app/constants/enums.js: -------------------------------------------------------------------------------- 1 | // all the contansts used in the project 2 | 3 | 4 | const Transaction_Status = Object.freeze({ 5 | PENDING:'submitted', 6 | COMPLETED:'confirmed', 7 | FAILED:'failed' 8 | }); 9 | 10 | const Database_Controllers =Object.freeze({ 11 | ACCOUNT_CONTROLLER : Object.freeze({ 12 | NAME:'AccountController', 13 | SELECTED:'selected', 14 | ACCOUNTS:'accounts', 15 | BALANCE:'balance', 16 | TOKENS:'tokens', 17 | SALT:'salt', 18 | VECTOR:'vi', 19 | CPU_LIMIT:'cpu_limit', 20 | NET_LIMIT:'net_limit', 21 | DEFAULT_CURRENCY:'DefaultCurrency', 22 | DEFAULT_TOKEN:'DefaultToken', 23 | CUSTOM_TOKENS:'Custom_Tokens' 24 | }), 25 | TRANSACTION_CONTROLLER : Object.freeze({ 26 | NAME:'TransactionController', 27 | HISTORY:'TransactionHistory', 28 | PENDING:'PendingTransactions', 29 | TRANSACTION:'transaction' 30 | }), 31 | EXTRA:Object.freeze({ 32 | NAME:'Extra', 33 | MEMO:'Memo', 34 | TOKEN_LIST:'TokenList', 35 | TEMP_DATA:'TempData' 36 | }), 37 | NETWORK_CONTROLLER:Object.freeze({ 38 | NAME:'NetworkController', 39 | TYPE:'type', 40 | CUSTOM_NETWORKS:'CustomNetwors' 41 | }), 42 | STATE_CONTROLLER:Object.freeze({ 43 | NAME:'StateController', 44 | CURRENT:'Current', 45 | REDIRECT_TO:'RedirectTo', 46 | DEFAULT:'home' 47 | }), 48 | COMMUCATION_CONTROLLER:Object.freeze({ 49 | NAME:'CommunicationController', 50 | ALLOWED_HOSTS:'AllowedHosts', 51 | BLOCKED_HOSTS:'BlockedHosts', 52 | PRIVACY_MODE:'Communication' 53 | }), 54 | FORGOT_PASSWORD:'is_forgotAccount', 55 | POLICY_CONTROLLER : 'PolicyController', 56 | VERSION_CONTROLLER : 'Version' 57 | }); 58 | 59 | const Channel_Names = Object.freeze({ 60 | TRANSFER_FUNDS:'TransferTokens', 61 | SYNC_BALANCE:'SyncUserBalance', 62 | GET_TRANSACTION:'GetAccountTransaction', 63 | CURRENCY_CHECK:'CheckForUserCurrencyBalance', 64 | NETWORK_CHANGE:'NetworkChangedPleaseUpdate', 65 | SAVE_TXN_ID:'SaveCurrentTransactionId', 66 | GET_TXN_ID:'GetCurrentTransactionId', 67 | GET_CONVERSION_RATES:'GetNewConversionRates', 68 | RECOVER:'ResetAll' 69 | }); 70 | 71 | const Networks = { 72 | TESTNET:'testnet', 73 | MAINNET:'mainnet', 74 | }; 75 | 76 | const External_Channels = Object.freeze({ 77 | CONNECT:'ConnectToExtension', 78 | SEND:'SendTransactionFromExtension', 79 | GETDATA:'GetInitData', 80 | GETDATA_RES:'GetInitDataResponse', 81 | CONNECT_RES:'ConnectToExtensionResponse', 82 | SEND_RES:'SendTransactionFromExtensionResponse', 83 | SEND_CUSTOM_ACTION:'SendCustomFromExtensionAction', 84 | SEND_CUSTOM_ACTION_RESPONSE:'SendCustomActionFromExtensionResponse' 85 | }); 86 | 87 | const Extention = Object.freeze({ 88 | NAME:'EOS Pulse', 89 | ID:'jlnbnjlakmkkhcmjbloceddnmclmfieo' 90 | }); 91 | 92 | const Error_Codes = Object.freeze({ 93 | USER_REJECTED:'30152', 94 | PRIVACY_MODE_ON:'30153', 95 | REQUESTER_NOT_ALLOWED:'30154', 96 | NO_ACCOUNT:'30156', 97 | REQUIRED_FIELDS_ARE_MISSING:'30157' 98 | }); 99 | 100 | const Errors = Object.freeze({ 101 | CPU_EXCEEDED : "More CPU required to complete the transaction", 102 | DUPLICATE_ACCOUNT:'Account name already taken', 103 | PASSWORD_MISSING:'Please enter your password', 104 | PASSWORD_MISMATCH:'Incorrect password', 105 | PASSWORD_VALIDATION:'Make sure all the conditions matched for password', 106 | PASSWORD_MUST_SAME:'Password and confirm password must be same', 107 | INSUFFICIENT_FUNDS:'Insufficient funds', 108 | ACCOUNT_VALIDATION_ERROR:'Account name should have 12 symbols (a-z lower case only, . , 1-5 are allowed)', 109 | WRONG_ACCOUNT_NAME:'Please provide valid receiver account name', 110 | ACCOUNT_NOT_FOUND:'Sorry account not found', 111 | ACCOUNT_AND_KEY_MISSMATCH:'Account Name and Private Key do not match', 112 | MISSING_FIELDS:'Please fill all the required fields', 113 | RETRY:'Please try again later', 114 | MISSING_NAME:'Please provide receiver account name', 115 | MiSSING_AMOUNT:'Please provide amount', 116 | MISSING_SYMBOL:'Please choose a token', 117 | MISSING_NET_QUNATITY:'Please provide net quantity', 118 | MISSING_CPU_QUNATITY:'Please provide CPU quantity', 119 | SAME_FROM_AND_TO:'You cannot send tokens to yourself', 120 | PRIVATE_KEY_ERROR:'Invalid private key', 121 | TRANSACTION_ID_MISSING:'Please enter your transaction id', 122 | INCORRECT_CREATOR:'Sorry you have sent on incorrect address', 123 | INCORRECT_AMOUNT:'Sorry incorrect amount sent', 124 | INCORRECT_MEMO_TAG:'Sorry incorrect memo', 125 | INCORRECT_TXN_ID:'Invalid transaction id', 126 | COMMON:'Something went wrong', 127 | MISSING_CONTRACT:'please send the contract name', 128 | INCORRECT_CONTRACT:'invalid contract address', 129 | MISSING_ACTION:'please send the action u want to perform', 130 | WRONG_NODE_ADDRESS:'cannot connect to the node', 131 | DUPLICATE_NETWORK_NAME:'network name already exists', 132 | TOKEN_DOESNOT_EXISTS:'token doesnot exists' 133 | }); 134 | 135 | const Conversion_Rates = Object.freeze({ 136 | NAME:"Conversion_Controller" 137 | }); 138 | 139 | 140 | 141 | module.exports = {Conversion_Rates,Transaction_Status,Database_Controllers,Channel_Names,Networks,External_Channels,Extention,Error_Codes,Errors}; -------------------------------------------------------------------------------- /src/app/services/EosServices.js: -------------------------------------------------------------------------------- 1 | import to from 'await-to-js'; 2 | import { config } from '../config/config'; 3 | import { Channel_Names, Database_Controllers, Networks } from '../constants/enums'; 4 | 5 | 6 | export default class EosService { 7 | // servece to access all the eos blockchain functions 8 | 9 | constructor(StorageService,AccountService,EncryptionService){ 10 | this.ecc = eosjs_ecc; 11 | this.configEos = {}; 12 | eosjs_ecc =undefined; 13 | this.store = StorageService; 14 | this.accountService = AccountService; 15 | this.DecimalPad = Eos.modules.format.DecimalPad; 16 | this.accountsController = {}; 17 | this.encryptionService =EncryptionService; 18 | this.init(); 19 | } 20 | 21 | async init() { 22 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 23 | await this.initialize(); 24 | } 25 | 26 | 27 | async getInfo(httpEndpoint){ // get info of the current node 28 | const eos = Eos({httpEndpoint}); 29 | return eos.getInfo({}); 30 | } 31 | 32 | async initialize(passkey = null,contract=null){ // to initialize the eos object 33 | 34 | const networkController = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME); // to get the current network status 35 | this.networkType = networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]; // to get the selected network 36 | const CUSTOM_NETWORKS = networkController[Database_Controllers.NETWORK_CONTROLLER.CUSTOM_NETWORKS] || {}; 37 | if(!CUSTOM_NETWORKS[this.networkType]) { // to check if the current network is a custom network or default once and then initialize the config accordingily 38 | this.configEos = config[this.networkType]['configEos']; 39 | } else { 40 | const network = CUSTOM_NETWORKS[this.networkType]; 41 | this.configEos = config[Networks.LOCALNET]['configEos']; 42 | this.configEos.httpEndpoint = `${network.protocol}://${network.host}:${network.port}`; 43 | this.configEos.chainId = network.chainId; 44 | } 45 | 46 | const localConfigForEos = Object.create(this.configEos), // for deep copying 47 | localEos = Eos(localConfigForEos); 48 | if (passkey) { 49 | const expireInSeconds = 60 * 60,// 1 hour 50 | Contract = contract ? await localEos.getAbi({account_name:contract}): {abi:''}, // getting the abi of the current contract 51 | info = await localEos.getInfo({}), 52 | chainDate = new Date(info.head_block_time + 'Z'), 53 | block = await localEos.getBlock(info.last_irreversible_block_num); 54 | let expiration = new Date(chainDate.getTime() + expireInSeconds * 1000); 55 | expiration = expiration.toISOString().split('.')[0]; 56 | const transactionHeaders = { 57 | expiration, 58 | ref_block_num: info.last_irreversible_block_num & 0xFFFF, 59 | ref_block_prefix: block.ref_block_prefix 60 | }; 61 | localConfigForEos.httpEndpoint = null; // to just sign the transaction not pushing to the blockchain 62 | localConfigForEos.transactionHeaders = transactionHeaders; 63 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 64 | const selected = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 65 | const userData = this.accountsController[selected]; 66 | localConfigForEos.keyProvider =[`${await this.encryptionService.decrypt(passkey,userData.keyManager)}`]; 67 | return Promise.resolve({eos:Eos(localConfigForEos),abi:Contract.abi}); 68 | // configEos.; 69 | } 70 | console.log(localEos); 71 | return Promise.resolve(Eos(localConfigForEos)); 72 | } 73 | 74 | createAccount(name,deviceID,memo){ // to create new account on the blockchain 75 | return new Promise(async (resolve,reject)=>{ 76 | const networkController = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME), 77 | networkType = networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]; 78 | 79 | if(Networks.MAINNET != networkType && Networks.TESTNET != networkType){ 80 | reject({msg:`unable to create account on ${networkType} network`}); 81 | } 82 | 83 | this.ecc.randomKey().then( async (key) => { 84 | let owner = ''; 85 | const active = owner = this.ecc.privateToPublic(key); 86 | const [error] = await to(this.getAccountByName({account_name:name})); // its a check wheathere account is already present with this name or not 87 | if(error){ 88 | const [error,data] = await to (this.accountService.createAccount({ name:name,owner,active,deviceID,memo })); // check account service for more details 89 | if (error){ 90 | reject({success:false,msg:error}); 91 | } 92 | resolve({success:true,msg:data,key:key}); 93 | } 94 | else { 95 | reject({success:false,msg:'Account name already taken'}); 96 | } 97 | }); 98 | }); 99 | } 100 | 101 | privateToPublic(key) { // to convert private key to public key 102 | try{ 103 | return Promise.resolve( this.ecc.privateToPublic(key) ); 104 | } catch(error) { 105 | return Promise.resolve(false); 106 | } 107 | } 108 | 109 | isvalidPrivateKey(key){ // to validate a private key 110 | return this.ecc.isValidPrivate(key); 111 | } 112 | 113 | 114 | async getAccountByName({account_name}){ // to get an account details using name from blockchian 115 | const eos = await this.initialize(); 116 | return eos.getAccount({account_name}); 117 | } 118 | 119 | async getCurrencyBalance({account,code,symbol}){ 120 | const eos = await this.initialize(); 121 | return eos.getCurrencyBalance({account,code,symbol}); 122 | } 123 | 124 | pushTransaction(transctionData){ // to push transaction through background script 125 | const port = chrome.runtime.connect({name:Channel_Names.TRANSFER_FUNDS}); // this is to connect to the background script on the particular channel name 126 | port.postMessage({transaction:`${JSON.stringify(transctionData.transaction)}`}); // sending messsage 127 | return new Promise((resolve,reject)=>{ 128 | port.onMessage.addListener((result)=>{ // listner for the response from the background script 129 | if(result.status == "success"){ 130 | resolve(result.response); 131 | port.disconnect(); 132 | } else { 133 | reject(JSON.parse(result.error)); 134 | port.disconnect(); 135 | } 136 | }); 137 | }); 138 | } 139 | 140 | async transfer_amount(contract,from,passKey,decimalPrecision,{to,amount,memo,symbol}){ // to create a transaction object 141 | let {eos,abi} = await this.initialize(passKey,contract); 142 | eos.fc.abiCache.abi(contract, abi); 143 | amount = this.DecimalPad(amount,decimalPrecision); 144 | const options = {authorization: from} 145 | const transctionData = await eos.transaction(contract,(currentContract)=>{currentContract.transfer(from, to, `${amount} ${symbol.toUpperCase()}`, (memo || ' '),options);}); 146 | await this.initialize(); 147 | return await this.pushTransaction(transctionData); 148 | } 149 | 150 | async verifyTxn(txnID){ // to verify the transaction for creating acount on mainnet 151 | const port = chrome.runtime.connect({name:Channel_Names.GET_TRANSACTION}); // to get the transaction details from the blockchain throught bg script 152 | port.postMessage({transaction:`${JSON.stringify({id:txnID,block_num_hint:0})}`}); 153 | return new Promise((resolve,reject)=>{ 154 | port.onMessage.addListener((result)=>{ 155 | if(result.status == "success"){ 156 | resolve(result.response); 157 | port.disconnect(); 158 | } else { 159 | reject(result.error); 160 | port.disconnect(); 161 | } 162 | }); 163 | }); 164 | } 165 | 166 | async customActions(contract,from,action,passKey,data){ // to handle custom actions of contarcts 167 | try{ 168 | const {eos,abi} = await this.initialize(passKey,contract); 169 | eos.fc.abiCache.abi(contract, abi); 170 | console.log(data); 171 | const transctionData = await eos.transaction( 172 | { 173 | actions: [ 174 | { 175 | account: contract, 176 | name: action, 177 | authorization: [{ 178 | actor: from, 179 | permission: 'active' 180 | }], 181 | data: data 182 | } 183 | ] 184 | } 185 | ) 186 | await this.initialize(); 187 | return await this.pushTransaction(transctionData); 188 | } catch(error) { 189 | return Promise.reject(error); 190 | } 191 | } 192 | 193 | async delegate(password,decimalPrecision,{from,receiver,CPU_quantity,net_quantity,symbol}){ // to delegatr the CPU 194 | const {eos} = await this.initialize(password); 195 | const transctionData = await eos.delegatebw({from,receiver,stake_cpu_quantity:`${this.DecimalPad(CPU_quantity,decimalPrecision)} ${symbol}`,stake_net_quantity:`${this.DecimalPad(net_quantity,decimalPrecision)} ${symbol}`,transfer:0}); 196 | await this.initialize(); 197 | console.log(transctionData); 198 | return await this.pushTransaction(transctionData); 199 | } 200 | 201 | async undelegate(password,decimalPrecision,{from,receiver,CPU_quantity,net_quantity,symbol}){ // to undelegate the cpu 202 | const {eos} = await this.initialize(password); 203 | const transctionData = await eos.undelegatebw({from,receiver,unstake_cpu_quantity:`${this.DecimalPad(CPU_quantity,decimalPrecision)} ${symbol}`,unstake_net_quantity:`${this.DecimalPad(net_quantity,decimalPrecision)} ${symbol}`}); 204 | await this.initialize(); 205 | return await this.pushTransaction(transctionData); 206 | } 207 | 208 | } 209 | 210 | 211 | 212 | EosService.$inject = ['StorageService','AccountService','EncryptionService']; -------------------------------------------------------------------------------- /src/app/services/account.js: -------------------------------------------------------------------------------- 1 | import {protocol,host,port} from '../config/settings'; 2 | import {Database_Controllers,Channel_Names} from '../constants/enums'; 3 | 4 | export default class AccountService { 5 | constructor($http,StorageService){ 6 | this.http = $http; 7 | this.store =StorageService; 8 | this.baseurl = `${protocol}://${host}:${port}`; 9 | } 10 | 11 | 12 | async createAccount(wallet){ 13 | const port = chrome.runtime.connect({name: Channel_Names.GET_TXN_ID}); 14 | port.postMessage({message:'give me the txn id'}); 15 | port.onMessage.addListener((message)=>{wallet.Id = (message.id || '');}); 16 | const network = await this.store.get(Database_Controllers.NETWORK_CONTROLLER.NAME); 17 | 18 | if(network) { 19 | wallet.network = network.type; 20 | } 21 | 22 | return new Promise((resolve,reject)=>{ 23 | this.http.post(`${this.baseurl}/api/wallet/registration`,wallet).then((result)=>{ 24 | resolve(result); 25 | }).catch((error)=>{ 26 | console.error(error); 27 | reject(error.data ? error.data.message : "something went wrong"); 28 | }); 29 | }); 30 | 31 | } 32 | 33 | } 34 | 35 | AccountService.$inject = ['$http','StorageService']; -------------------------------------------------------------------------------- /src/app/services/contentScriptService.js: -------------------------------------------------------------------------------- 1 | import to from 'await-to-js'; 2 | import {config} from '../config/config'; 3 | import Eos from 'eosjs'; 4 | 5 | import { Database_Controllers,External_Channels,Extention } from '../constants/enums'; 6 | 7 | class ContentScriptService{ 8 | // this whole script is injected on every js enabled page 9 | // every event dispatched from here will be capture by the contentscript.js 10 | 11 | constructor(){ 12 | this.network = ''; 13 | this.init(); 14 | } 15 | 16 | async init(){ 17 | this.extentionID = Extention.ID; 18 | window.dispatchEvent(new Event(External_Channels.GETDATA)); 19 | window.addEventListener(External_Channels.GETDATA_RES,(response)=>{ 20 | this.network = response.detail[Database_Controllers.NETWORK_CONTROLLER.TYPE]; 21 | }); 22 | } 23 | 24 | sendTransaction(transactionObject){ // to handle the transactions from the other dapps 25 | 26 | return new Promise(async (resolve,reject)=>{ 27 | window.dispatchEvent(new CustomEvent(External_Channels.SEND,{detail:transactionObject})); 28 | window.addEventListener(External_Channels.SEND_RES,(response)=>{ 29 | if(response.detail.status == 'success') { 30 | resolve(response.detail); 31 | } else{ 32 | reject(response.detail); 33 | } 34 | }); 35 | }); 36 | } 37 | 38 | connect(){ // to handle the connections of dapps 39 | return new Promise(async (resolve,reject)=>{ 40 | window.dispatchEvent(new Event(External_Channels.CONNECT)); 41 | window.addEventListener(External_Channels.CONNECT_RES,(response)=>{ 42 | if(response.detail.status == 'success'){ 43 | resolve(response.detail); 44 | } else { 45 | reject(response.detail); 46 | } 47 | }); 48 | }); 49 | } 50 | 51 | sendCustomAction(contract,action,data){ // to handle the custom actions from the other dapps 52 | return new Promise(async (resolve,reject)=>{ 53 | window.dispatchEvent(new CustomEvent(External_Channels.SEND_CUSTOM_ACTION,{detail:{contract,action,data}})); 54 | window.addEventListener(External_Channels.SEND_CUSTOM_ACTION_RESPONSE,(response)=>{ 55 | if(response.detail.status == 'success'){ 56 | resolve(response.detail); 57 | } else { 58 | reject(response.detail); 59 | } 60 | }); 61 | }); 62 | } 63 | } 64 | 65 | ContentScriptService.$inject = []; 66 | 67 | window.pulse = new ContentScriptService(); 68 | window.eosController = Eos; -------------------------------------------------------------------------------- /src/app/services/encryption.js: -------------------------------------------------------------------------------- 1 | 2 | export default class EncryptionService{ 3 | 4 | constructor(){} 5 | 6 | encrypt(key,value){ // to encrypt the private key by password 7 | return Promise.resolve(encrypt(value,key).toString()); 8 | } 9 | 10 | decrypt(key,value){ // to decrypt the private key by password 11 | return Promise.resolve(decrypt(value,key).toString(this.enc.Utf8)); 12 | } 13 | 14 | encryptSalt(key,value){ // to encrypt the salt 15 | return Promise.resolve(encrypt(value,key).toString()); 16 | } 17 | 18 | decryptSalt(key,value){ // to decrypt the salt 19 | try{ 20 | return Promise.resolve(decrypt(value,key).toString(this.enc.Utf8)); 21 | } catch(err){ 22 | return Promise.resolve('wrong password'); 23 | } 24 | } 25 | 26 | } 27 | EncryptionService.$inject = []; 28 | -------------------------------------------------------------------------------- /src/app/services/storage.js: -------------------------------------------------------------------------------- 1 | import { Database_Controllers,Networks } from '../constants/enums'; 2 | 3 | export default class StorageService{ 4 | 5 | //service to store data in chrome storage 6 | constructor(){ 7 | this.store = chrome.storage.local; 8 | } 9 | 10 | async save(data){ // to store new created accounts or imported accounts 11 | let accountData=await this.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 12 | const networkController = await this.get(Database_Controllers.NETWORK_CONTROLLER.NAME), 13 | networkType = networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]; 14 | accountData[`${data.account_name}_${networkType}`]=data; 15 | accountData[`${Database_Controllers.ACCOUNT_CONTROLLER.SELECTED}`]=`${data.account_name}_${networkType}`; 16 | if(!accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS]) { 17 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS]={}; 18 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.TESTNET]=[]; 19 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.LOCALNET]=[]; 20 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][Networks.MAINNET]=[]; 21 | } 22 | if ( accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][networkType].indexOf(data.account_name)<0 ) 23 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS][networkType].push(data.account_name); 24 | const saveData = {}; 25 | saveData[Database_Controllers.ACCOUNT_CONTROLLER.NAME] = accountData; 26 | await this.set(saveData); 27 | return Promise.resolve(true); 28 | } 29 | 30 | get(key = null){ // to get data from the storage as per the key 31 | return new Promise((resolve,reject)=>{ 32 | this.store.get(key,(result,error)=>{ 33 | if(error || result=='') reject(error); 34 | else resolve(result[key]); 35 | }) 36 | }) 37 | } 38 | 39 | set(controller) { // to store data in the storage 40 | return new Promise((resolve,reject)=>{ 41 | this.store.set(controller,(result,error)=>{ 42 | if(error) reject(error); 43 | else resolve(true); 44 | }); 45 | }); 46 | } 47 | 48 | setState(currentState,redirectTo=null) { // store current state of the extension 49 | return new Promise((resolve,reject)=>{ 50 | const state = {}; 51 | state[Database_Controllers.STATE_CONTROLLER.NAME]={ 52 | Current:currentState, 53 | RedirectTo:redirectTo 54 | } 55 | this.store.set(state,(result,error)=>{ 56 | if(error || result=='') reject(error); 57 | else resolve(result); 58 | }); 59 | }); 60 | } 61 | 62 | getTransactions(){ // get all txns of the selected account 63 | return new Promise(async (resolve,reject)=>{ 64 | const accountsController = await this.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 65 | const selected = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 66 | this.store.get(Database_Controllers.TRANSACTION_CONTROLLER.NAME,(result,error)=>{ 67 | if(error || result=='') reject(error); 68 | else resolve(result[Database_Controllers.TRANSACTION_CONTROLLER.NAME][selected]); 69 | }) 70 | }) 71 | } 72 | 73 | setTransaction(data){ // store transactions of the selected account 74 | return new Promise(async (resolve,reject)=>{ 75 | const accountsController = await this.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 76 | const selected = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 77 | const transactionController = await this.get(Database_Controllers.TRANSACTION_CONTROLLER.NAME); 78 | transactionController[selected]=data[Database_Controllers.TRANSACTION_CONTROLLER.NAME]; 79 | const transactionData = {}; 80 | transactionData[Database_Controllers.TRANSACTION_CONTROLLER.NAME]=transactionController; 81 | console.log(transactionData,"nnnnneeeewwwww"); 82 | this.store.set(transactionData,(result,error)=>{ 83 | if(error || result=='') reject(error); 84 | else resolve(result); 85 | }); 86 | }) 87 | } 88 | 89 | setCustomToken(tokenDetails){ // this is to store the custom tokens added by the user in pulse 90 | return new Promise(async (resolve,reject)=>{ 91 | const accountsController = await this.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 92 | const networkController = await this.get(Database_Controllers.NETWORK_CONTROLLER.NAME); 93 | const selected = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED]; 94 | const accounts = accountsController[Database_Controllers.ACCOUNT_CONTROLLER.ACCOUNTS]; 95 | if(accounts[networkController[Database_Controllers.NETWORK_CONTROLLER.TYPE]].length) { 96 | const customTokens = accountsController[selected][Database_Controllers.ACCOUNT_CONTROLLER.CUSTOM_TOKENS] || {}; 97 | customTokens[tokenDetails.token.toUpperCase()] = tokenDetails; 98 | console.log("custom->",customTokens); 99 | accountsController[selected][Database_Controllers.ACCOUNT_CONTROLLER.CUSTOM_TOKENS] = customTokens; 100 | } else { 101 | reject(false); 102 | } 103 | const accountData = {}; 104 | accountData[Database_Controllers.ACCOUNT_CONTROLLER.NAME]=accountsController; 105 | console.log("accounts DATA ->",accountData,tokenDetails); 106 | await this.set(accountData); 107 | resolve(true); 108 | }); 109 | } 110 | 111 | clear(){ // to clear the chrome storage 112 | this.store.clear(); 113 | return Promise.resolve(true); 114 | } 115 | 116 | getAll(){ // to get all data from the storage 117 | return new Promise((resolve,reject)=>{ 118 | this.store.get(null,(result,error)=>{ 119 | if(error || result=='') reject(error); 120 | else resolve(result); 121 | }) 122 | }) 123 | } 124 | 125 | 126 | delete(key){ // to delete a particular key from the storage 127 | this.store.remove(key); 128 | } 129 | 130 | } 131 | 132 | StorageService.$inject = []; -------------------------------------------------------------------------------- /src/app/services/validation.js: -------------------------------------------------------------------------------- 1 | import {Errors,Database_Controllers} from '../constants/enums'; 2 | import to from 'await-to-js'; 3 | import { HASH } from 'crypto-js'; 4 | 5 | export default class ValidationService { 6 | 7 | // this is to validate 8 | 9 | constructor(StorageService,EosService,EncryptionService){ 10 | this.eosService = EosService; 11 | this.store = StorageService; 12 | this.encryptionService = EncryptionService; 13 | this.validations ={}; 14 | } 15 | 16 | async init(){ 17 | this.accountsController = await this.store.get(Database_Controllers.ACCOUNT_CONTROLLER.NAME); 18 | this.selected = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SELECTED] || ''; 19 | if(this.selected){ 20 | this.accountName = this.selected.split('_')[0]; 21 | this.balance = this.accountsController[this.selected][Database_Controllers.ACCOUNT_CONTROLLER.BALANCE] || 0; 22 | } 23 | this.pass = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.SALT] || ''; 24 | this.salt = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.VECTOR] || ''; 25 | this.getAllAvailableTokens(); 26 | } 27 | 28 | async validateTxn( transaction ,password){ // to validate transaction with password 29 | await this.init(); 30 | if( transaction && transaction.symbol && transaction.to && transaction.to != this.accountName && transaction.amount && parseFloat(transaction.amount) <= parseFloat(this.availableTokens[transaction.symbol] || 0) && !(transaction.to.search(/^[a-z,A-Z,1-5]{12}$/)) && password && HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() === this.pass ) { 31 | let [error] = await to(this.eosService.getAccountByName({account_name:transaction.to})); 32 | if(error) { 33 | return Errors.WRONG_ACCOUNT_NAME; 34 | } else{ 35 | return true; 36 | } 37 | } else if(!transaction) { 38 | return Errors.MISSING_FIELDS; 39 | } else if(!password) { 40 | return Errors.PASSWORD_MISSING; 41 | }else if(HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() !== this.pass) { 42 | return Errors.PASSWORD_MISMATCH; 43 | }else if (!transaction.to) { 44 | return Errors.MISSING_NAME; 45 | } else if (!transaction.amount) { 46 | return Errors.MiSSING_AMOUNT; 47 | } else if (transaction.to == this.accountName) { 48 | return Errors.SAME_FROM_AND_TO; 49 | } else if (parseFloat(transaction.amount) > parseFloat(this.availableTokens[transaction.symbol] || 0)) { 50 | return Errors.INSUFFICIENT_FUNDS; 51 | } else { 52 | return Errors.WRONG_ACCOUNT_NAME; 53 | } 54 | } 55 | 56 | 57 | async partialValidateTxn( transaction){ // to validate transaction without password 58 | await this.init(); 59 | if( transaction && transaction.symbol && transaction.to && transaction.to != this.accountName && transaction.amount && parseFloat(transaction.amount) <= parseFloat(this.availableTokens[transaction.symbol] || 0) && !(transaction.to.search(/^[a-z,A-Z,1-5]{12}$/))) { 60 | let [error] = await to(this.eosService.getAccountByName({account_name:transaction.to})); 61 | if(error) { 62 | return Errors.WRONG_ACCOUNT_NAME; 63 | } else{ 64 | return true; 65 | } 66 | }else if (!transaction) { 67 | return Errors.MISSING_FIELDS; 68 | }else if (!transaction.to) { 69 | return Errors.MISSING_NAME; 70 | }else if (!transaction.symbol) { 71 | return Errors.MISSING_SYMBOL; 72 | } else if (!transaction.amount) { 73 | return Errors.MiSSING_AMOUNT; 74 | } else if (transaction.to == this.accountName) { 75 | return Errors.SAME_FROM_AND_TO; 76 | } else if (parseFloat(transaction.amount) > parseFloat(this.availableTokens[transaction.symbol] || 0)) { 77 | return Errors.INSUFFICIENT_FUNDS; 78 | } else { 79 | return Errors.WRONG_ACCOUNT_NAME; 80 | } 81 | } 82 | 83 | async validatePartialDelicateTxn(transaction){ // to validate delegate/undelegate cpu transaction without password 84 | await this.init(); 85 | if( transaction && transaction.symbol && transaction.receiver && parseFloat(transaction.net_quantity) > 0 && parseFloat(transaction.CPU_quantity) > 0 && ( transaction.type == "undelegate" || ( ( transaction.type == 'delegate' && parseFloat(transaction.CPU_quantity) + parseFloat(transaction.net_quantity)) <= parseFloat(this.availableTokens[transaction.symbol] || 0))) ) { 86 | console.log('ho gya pass'); 87 | return true; 88 | } else if (!transaction) { 89 | return Errors.MISSING_FIELDS; 90 | } else if (!transaction.CPU_quantity) { 91 | return Errors.MISSING_CPU_QUNATITY; 92 | } else if (!transaction.net_quantity) { 93 | return Errors.MISSING_NET_QUNATITY; 94 | } else if ((parseFloat(transaction.CPU_quantity) + parseFloat(transaction.net_quantity)) > parseFloat(this.availableTokens[transaction.symbol] || 0)) { 95 | return Errors.INSUFFICIENT_FUNDS; 96 | } else { 97 | return Errors.WRONG_ACCOUNT_NAME; 98 | } 99 | } 100 | 101 | async validateDelicateTxn(transaction,password){ // to validate delegate/undelegate CPU transaction with password 102 | await this.init(); 103 | if( transaction && transaction.symbol && transaction.receiver && parseFloat(transaction.net_quantity) > 0 && parseFloat(transaction.CPU_quantity) > 0 && ( transaction.type == "undelegate" || ( (parseFloat(transaction.CPU_quantity) + parseFloat(transaction.net_quantity)) <= parseFloat(this.availableTokens[transaction.symbol] || 0))) && password && HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() === this.pass) { 104 | console.log('ho gya pass'); 105 | return true; 106 | }else if(!transaction) { 107 | return Errors.MISSING_FIELDS; 108 | }else if(!password) { 109 | return Errors.PASSWORD_MISSING; 110 | }else if(HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() !== this.pass) { 111 | return Errors.PASSWORD_MISMATCH; 112 | } else if (!transaction.net_quantity) { 113 | return Errors.MISSING_NET_QUNATITY; 114 | } else if (!transaction.CPU_quantity) { 115 | return Errors.MISSING_CPU_QUNATITY; 116 | } else if ((parseFloat(transaction.CPU_quantity) + parseFloat(transaction.net_quantity)) > parseFloat(this.availableTokens[transaction.symbol] || 0)) { 117 | return Errors.INSUFFICIENT_FUNDS; 118 | } else { 119 | return Errors.WRONG_ACCOUNT_NAME; 120 | } 121 | } 122 | 123 | async getAllAvailableTokens(){ // to create a map of all tokens available to the selected account 124 | this.availableTokens = {}; 125 | let currency_balances = this.accountsController[Database_Controllers.ACCOUNT_CONTROLLER.TOKENS] || []; 126 | currency_balances.map((currency)=>{ 127 | this.availableTokens[currency.split(' ')[1]] = currency.split(' ')[0]; 128 | }); 129 | } 130 | 131 | 132 | 133 | async validateCustomAction(transaction,password){ // to validate the custom dapp actions 134 | await this.init(); 135 | if(password && HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() == this.pass && transaction.contract && transaction.action){ 136 | return true; 137 | }else if(!transaction) { 138 | return Errors.MISSING_FIELDS; 139 | }else if(!password) { 140 | return Errors.PASSWORD_MISSING; 141 | }else if(HASH(password + await(this.encryptionService.decryptSalt(password,this.salt))).toString() !== this.pass) { 142 | return Errors.PASSWORD_MISMATCH; 143 | } else if (!transaction.contract) { 144 | return Errors.MISSING_CONTRACT; 145 | } else if (!transaction.action) { 146 | return Errors.MISSING_ACTION; 147 | } 148 | } 149 | 150 | validatePassword(password){ // to validate the password strength 151 | this.validations = { 152 | length:true, 153 | lowercase:true, 154 | uppercase:true, 155 | digit:true, 156 | specialCharacter:true 157 | } 158 | 159 | if(!(password.search(/^(?=.*\d)(?=.*[!@#$%^&*])(?=.*[a-z])(?=.*[A-Z]).{8,}$/))){ 160 | return true; 161 | } 162 | 163 | if(password.length < 8){ 164 | this.validations.length = false; 165 | } 166 | if(password.search(/^.*[a-z]{1,}.*$/)){ 167 | this.validations.lowercase = false; 168 | } 169 | if(password.search(/^.*[A-Z]{1,}.*$/)){ 170 | this.validations.uppercase = false; 171 | } 172 | if(password.search(/^.*[0-9]{1,}.*$/)){ 173 | this.validations.digit = false; 174 | } 175 | if(password.search(/^.*[!@#$%^&*]{1,}.*$/)) { 176 | this.validations.specialCharacter = false; 177 | } 178 | return this.validations; 179 | } 180 | } 181 | 182 | ValidationService.$inject = ['StorageService','EosService','EncryptionService'] -------------------------------------------------------------------------------- /src/assets/images/Polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/Polygon.png -------------------------------------------------------------------------------- /src/assets/images/add-network.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/add-network.png -------------------------------------------------------------------------------- /src/assets/images/add-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/add-token.png -------------------------------------------------------------------------------- /src/assets/images/arrow-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/arrow-black.png -------------------------------------------------------------------------------- /src/assets/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/back.png -------------------------------------------------------------------------------- /src/assets/images/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/background.png -------------------------------------------------------------------------------- /src/assets/images/background1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/background1.png -------------------------------------------------------------------------------- /src/assets/images/confirmed-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/confirmed-gray.png -------------------------------------------------------------------------------- /src/assets/images/confirmed-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/confirmed-selected.png -------------------------------------------------------------------------------- /src/assets/images/copy-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/copy-icon.png -------------------------------------------------------------------------------- /src/assets/images/cpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/cpu.png -------------------------------------------------------------------------------- /src/assets/images/dahboard-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/dahboard-logo.png -------------------------------------------------------------------------------- /src/assets/images/down-arrow-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/down-arrow-white.png -------------------------------------------------------------------------------- /src/assets/images/down-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/down-arrow.png -------------------------------------------------------------------------------- /src/assets/images/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/edit.png -------------------------------------------------------------------------------- /src/assets/images/eos-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/eos-logo.png -------------------------------------------------------------------------------- /src/assets/images/export.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/export.png -------------------------------------------------------------------------------- /src/assets/images/failed-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/failed-gray.png -------------------------------------------------------------------------------- /src/assets/images/failed-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/failed-selected.png -------------------------------------------------------------------------------- /src/assets/images/green-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/green-circle.png -------------------------------------------------------------------------------- /src/assets/images/hamburger-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/hamburger-icon.png -------------------------------------------------------------------------------- /src/assets/images/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/import.png -------------------------------------------------------------------------------- /src/assets/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/info.png -------------------------------------------------------------------------------- /src/assets/images/key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/key.png -------------------------------------------------------------------------------- /src/assets/images/logo-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/logo-128.png -------------------------------------------------------------------------------- /src/assets/images/logo-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/logo-16.png -------------------------------------------------------------------------------- /src/assets/images/logo-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/logo-48.png -------------------------------------------------------------------------------- /src/assets/images/logo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/logo-white.png -------------------------------------------------------------------------------- /src/assets/images/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/logout.png -------------------------------------------------------------------------------- /src/assets/images/menu-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/menu-close.png -------------------------------------------------------------------------------- /src/assets/images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/new.png -------------------------------------------------------------------------------- /src/assets/images/password-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/password-text.png -------------------------------------------------------------------------------- /src/assets/images/password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/password.png -------------------------------------------------------------------------------- /src/assets/images/plan-circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/plan-circle.png -------------------------------------------------------------------------------- /src/assets/images/privacy_mode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/privacy_mode.png -------------------------------------------------------------------------------- /src/assets/images/qr-code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/qr-code.png -------------------------------------------------------------------------------- /src/assets/images/settings-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/settings-close.png -------------------------------------------------------------------------------- /src/assets/images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/settings.png -------------------------------------------------------------------------------- /src/assets/images/submitted-gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/submitted-gray.png -------------------------------------------------------------------------------- /src/assets/images/submitted-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/submitted-selected.png -------------------------------------------------------------------------------- /src/assets/images/top-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/top-logo.png -------------------------------------------------------------------------------- /src/assets/images/wallet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/wallet.png -------------------------------------------------------------------------------- /src/assets/images/white-selector.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KoinEx/pulse/cec87d768e25cc438d554c79d27aa3c6c98104ed/src/assets/images/white-selector.png -------------------------------------------------------------------------------- /src/assets/scss/actions.scss: -------------------------------------------------------------------------------- 1 | .alert-box{ 2 | border: 1px solid $black; 3 | // min-height: 30px; 4 | padding: 10px 10px 10px 35px; 5 | border-radius: 2px; 6 | margin: 0 auto; 7 | width: 84%; 8 | } 9 | 10 | .instructions{ 11 | border: 1px solid $warn; 12 | color: $warn; 13 | padding: 15px 10px 10px 10px; 14 | border-radius: 2px; 15 | margin: 0 auto; 16 | width: 74%; 17 | position: relative; 18 | z-index: 0; 19 | &::before{ 20 | content: 'alert'; 21 | position: absolute; 22 | padding: 5px 13px; 23 | border-radius: 4px; 24 | background: $warn; 25 | color:$white; 26 | top: -13px; 27 | text-transform: uppercase; 28 | z-index: 1; 29 | } 30 | } 31 | 32 | .warnings{ 33 | color: $warn; 34 | border-color: $warn; 35 | position: relative; 36 | &::before{ 37 | content: '!'; 38 | position: absolute; 39 | padding: 1.5px 7px; 40 | border-radius: 4px; 41 | background: $warn; 42 | color:$white; 43 | top: 8px; 44 | font-size: 15px; 45 | font-weight: bolder; 46 | left: 10px; 47 | text-transform: uppercase; 48 | } 49 | } 50 | 51 | .error{ 52 | color: $slightly-black; 53 | background: rgba($danger,0.3); 54 | border: 1px solid $danger; 55 | font-size: 12px; 56 | padding: 10px; 57 | border-radius: 2px; 58 | text-align: center; 59 | } 60 | 61 | .info{ 62 | color: $info; 63 | border-color: $info; 64 | position: relative; 65 | &::before{ 66 | content: '!'; 67 | position: absolute; 68 | padding: 1.5px 7px; 69 | border-radius: 4px; 70 | background: $info; 71 | color:$white; 72 | top: 8px; 73 | font-size: 15px; 74 | font-weight: bolder; 75 | left: 10px; 76 | text-transform: uppercase; 77 | } 78 | } -------------------------------------------------------------------------------- /src/assets/scss/colors.scss: -------------------------------------------------------------------------------- 1 | $white:white; 2 | $black:black; 3 | $primary:#195BDD; 4 | $border-primary:rgba(24, 89, 220, 0.34); 5 | $gray:#BEBEBE; 6 | $red:#FF0000; 7 | $background-color:#F9F9F9; 8 | $Lato : 'Lato', sans-serif; 9 | $submitted:#FF9F00; 10 | $confirmed:#609a1c; 11 | $failed:#FF0000; 12 | $bg-submitted:rgba(255, 157, 0, 0.2); 13 | $bg-confirmed:#eafad7; 14 | $bg-failed:rgba(255, 0, 0, 0.2); 15 | $row-hover:#ECF3FF; 16 | $warn:#F5A623; 17 | $danger:#FFBABA; 18 | $info:#195BDD; 19 | $secondary:#BEBEBE; 20 | $secondary-text:#484848; 21 | $slightly-black: #35373A; 22 | $green:#57AD68; 23 | $connection-bg-color :rgba(25,91,221,0.11); -------------------------------------------------------------------------------- /src/assets/scss/communication.scss: -------------------------------------------------------------------------------- 1 | .communication{ 2 | position: relative; 3 | .network{ 4 | background: rgba($slightly-black,0.05); 5 | text-align: center; 6 | padding: 5px; 7 | } 8 | .colored-strip{ 9 | background-color:$connection-bg-color; 10 | height: 56px; 11 | width: 100%; 12 | position: relative; 13 | z-index: 2; 14 | &::before{ 15 | position: absolute; 16 | background-color: $white; 17 | top: 20px; 18 | left: 150px; 19 | content: ' '; 20 | height: 70px; 21 | width: 70px; 22 | border-radius: 50%; 23 | box-shadow: 0 1px 4px 0 rgba(239,239,239,0.5), 1px 1px 5px 0 rgba(239,239,239,0.5); 24 | } 25 | &::after { 26 | content: '⇄'; 27 | position: absolute; 28 | top: 28px; 29 | font-size: 25px; 30 | left: 157px; 31 | height: 55px; 32 | text-align: center; 33 | width: 55px; 34 | display: flex; 35 | background-color:$connection-bg-color; 36 | border-radius: 50%; 37 | color: $primary; 38 | justify-content: center; 39 | align-items: center; 40 | } 41 | } 42 | .header{ 43 | position: relative; 44 | background: $white; 45 | z-index: 1; 46 | margin-top: 30px; 47 | .title{ 48 | font-size: 16px; 49 | text-align: center; 50 | font-weight: bold; 51 | line-height: 19px; 52 | color: $slightly-black; 53 | } 54 | .desc{ 55 | color: rgba($secondary-text,0.5); 56 | font-family: $Lato !important; 57 | font-size: 12px; 58 | text-align: center; 59 | line-height: 15px; 60 | 61 | } 62 | } 63 | .body{ 64 | position: relative; 65 | margin-top: 10px; 66 | .elements{ 67 | width: 90%; 68 | margin: auto; 69 | } 70 | .text-box{ 71 | margin: 0 auto; 72 | width: max-content; 73 | padding: 8px 30px; 74 | border: 1px solid rgba($slightly-black,0.1); 75 | background-color: rgba($slightly-black,0.06); 76 | font-family: $Lato !important; 77 | font-size: 12px; 78 | letter-spacing: -0.73px; 79 | line-height: 15px; 80 | color: $slightly-black; 81 | } 82 | .pairing{ 83 | margin-top: 10px; 84 | padding: 10px; 85 | display: flex; 86 | justify-content: center; 87 | align-items: center; 88 | .circle{ 89 | border-radius: 50%; 90 | height: 69px; 91 | width: 69px; 92 | background-color: $white; 93 | border:1px solid $gray; 94 | } 95 | .dots{ 96 | margin-left: 15px; 97 | width:30%; 98 | img{ 99 | margin-right: 5px; 100 | width: 10%; 101 | &:last-child{ 102 | margin: 0; 103 | } 104 | } 105 | } 106 | } 107 | .labels{ 108 | display: flex; 109 | justify-content:space-between; 110 | align-items: center; 111 | color: $gray; 112 | margin-left: 30px; 113 | width: 75%; 114 | } 115 | .host-info { 116 | margin: 40px auto 0 auto; 117 | color: $primary; 118 | font-size: 14px; 119 | font-family: $Lato; 120 | width:max-content; 121 | } 122 | 123 | .question{ 124 | margin-top:10px; 125 | color: $gray; 126 | font-size: 11px; 127 | text-align: center; 128 | } 129 | .warning{ 130 | background-color: rgba($warn,0.1); 131 | border: 1px solid rgba($warn,0.3); 132 | padding: 10px; 133 | width: 75%; 134 | margin:20px auto 0 auto; 135 | text-align: center; 136 | color: rgba($secondary-text,0.8); 137 | a{ 138 | text-decoration: none; 139 | color: $primary; 140 | } 141 | .label { 142 | color: $gray; 143 | text-align: center; 144 | font-size: 11px; 145 | } 146 | } 147 | } 148 | } -------------------------------------------------------------------------------- /src/assets/scss/cpu.scss: -------------------------------------------------------------------------------- 1 | .cpuInfo{ 2 | width: 100%; 3 | .card{ 4 | width: 90%; 5 | margin:0 auto; 6 | box-shadow: 0 2px 5px 0 rgba(59,74,116,0.14); 7 | border-radius: 2px; 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | .left-section{ 12 | width: 50%; 13 | padding: 20px; 14 | padding-right:0; 15 | border-right:1px solid rgba($slightly-black,0.1); 16 | .title{ 17 | font-family: $Lato !important; 18 | font-size: 10px; 19 | line-height: 12px; 20 | color: $slightly-black; 21 | opacity: 0.7; 22 | } 23 | .data{ 24 | font-size: 12px; 25 | line-height: 15px; 26 | font-family: $Lato !important; 27 | margin-bottom: 5px; 28 | } 29 | } 30 | .right-section{ 31 | padding: 20px; 32 | width: 50%; 33 | .title{ 34 | font-family: $Lato !important; 35 | font-size: 10px; 36 | line-height: 12px; 37 | color: $slightly-black; 38 | opacity: 0.7; 39 | } 40 | .data{ 41 | font-size: 14px; 42 | line-height: 14px; 43 | font-family: $Lato !important; 44 | margin-bottom: 5px; 45 | } 46 | } 47 | } 48 | .option-tabs{ 49 | width: 100%; 50 | ::-webkit-scrollbar { 51 | width: 2px; 52 | } 53 | 54 | /* Track */ 55 | ::-webkit-scrollbar-track { 56 | border-radius:10px ; 57 | } 58 | 59 | /* Handle */ 60 | ::-webkit-scrollbar-thumb { 61 | background: $gray; 62 | border-radius: 10px; 63 | } 64 | display: block; 65 | .selection-buttons{ 66 | display: flex; 67 | justify-content: center; 68 | align-items: center; 69 | .selection-button{ 70 | padding-left: 16px; 71 | padding-right: 15px; 72 | width: 46.8%; 73 | height: 40px; 74 | border-width:0; 75 | outline: none; 76 | font-family: $Lato; 77 | font-size: 13px; 78 | } 79 | } 80 | .selected-tab-data{ 81 | margin: 0 auto; 82 | width: 94%; 83 | overflow-y: scroll; 84 | overflow-x: hidden; 85 | height: max-content; 86 | margin-bottom: 20px; 87 | padding-bottom:10px; 88 | background-color: $background-color; 89 | } 90 | } 91 | .element{ 92 | width: 80%; 93 | margin: 0 auto; 94 | padding: 5px; 95 | font-weight: bold; 96 | font-size: 14px; 97 | font-family: $Lato; 98 | } 99 | .action_buttons{ 100 | display: flex; 101 | justify-content: space-evenly; 102 | align-content: center; 103 | } 104 | .confirmation-box{ 105 | padding: 3px 5px; 106 | label,input,.dropdown{ 107 | font-weight: normal; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /src/assets/scss/dashboard.scss: -------------------------------------------------------------------------------- 1 | .dashboard{ 2 | width: 375px; 3 | height: 600px; 4 | .account-header{ 5 | 6 | ::-webkit-scrollbar { 7 | width: 5px; 8 | } 9 | 10 | /* Track */ 11 | ::-webkit-scrollbar-track { 12 | border-radius:10px ; 13 | } 14 | 15 | /* Handle */ 16 | ::-webkit-scrollbar-thumb { 17 | background: $gray; 18 | border-radius: 10px; 19 | } 20 | 21 | display: flex; 22 | align-items: center; 23 | box-shadow: 0 0 4px 0 rgba(0,0,0,0.12), 0 0px 3px 0 rgba(225,225,225,0.14); 24 | width: 100%; 25 | padding-bottom: 10px; 26 | .settings{ 27 | text-align: center; 28 | width: 10%; 29 | button{ 30 | background: url('/assets/images/settings.png'); 31 | background-size: cover; 32 | background-repeat: no-repeat; 33 | border: none; 34 | border-radius: 0; 35 | height: 20px; 36 | outline: none; 37 | } 38 | } 39 | .hamburger{ 40 | text-align: center; 41 | width: 10%; 42 | button{ 43 | background: url('/assets/images/hamburger-icon.png'); 44 | background-size: cover; 45 | background-repeat: no-repeat; 46 | border: none; 47 | border-radius: 0; 48 | height: 15px; 49 | outline: none; 50 | } 51 | } 52 | .dropdown{ 53 | margin-left: 70px; 54 | margin-top:10px; 55 | border: 1px solid rgba($slightly-black,0.2); 56 | border-radius: 4px; 57 | padding: 10px 0; 58 | width: 140px; 59 | display: flex; 60 | align-items: center; 61 | justify-content: center; 62 | 63 | img{ 64 | width: 5%; 65 | } 66 | .select{ 67 | all: unset; 68 | border: none; 69 | user-select: none; 70 | -webkit-appearance: none; 71 | outline: none; 72 | font-size: 14px; 73 | color: $primary; 74 | font-family: $Lato; 75 | } 76 | } 77 | .options { 78 | width: 140px; 79 | border-radius: 2px 5px 5px 2px; 80 | background-color: $white; 81 | position: absolute; 82 | left: 108px; 83 | top: 49px; 84 | overflow: scroll; 85 | z-index: 1; 86 | 87 | .option{ 88 | display: flex; 89 | align-items: center; 90 | font-size: 14px; 91 | color: $primary; 92 | height: 40px; 93 | padding: 5px 8px; 94 | cursor: pointer; 95 | img{ 96 | width: 5%; 97 | } 98 | &:hover{ 99 | background-color: #F6F7F9; 100 | } 101 | } 102 | } 103 | .privacy-tooltip{ 104 | cursor: pointer; 105 | position: relative; 106 | &::before,&::after{ 107 | position: absolute; 108 | visibility: hidden; 109 | opacity: 0; 110 | transition-duration: 1s; 111 | content: " "; 112 | font-size: 16px; 113 | } 114 | &:hover{ 115 | &::before,&::after{ 116 | visibility: visible; 117 | opacity: 1; 118 | } 119 | } 120 | &::before{ 121 | content: attr(tooltip-text); 122 | color: $white; 123 | font-family: $Lato; 124 | top: 25px; 125 | right:-30px; 126 | text-align: center; 127 | width: max-content; 128 | border-radius: 4px; 129 | padding: 5px; 130 | font-size: 12px; 131 | background-color: rgba($black, 0.74); 132 | z-index: 2; 133 | } 134 | &::after{ 135 | top: 15px; 136 | left: 5px; 137 | border-left: 8px solid transparent; 138 | border-right: 8px solid transparent; 139 | border-bottom: 10px solid rgba($black,0.74); 140 | z-index: 3; 141 | } 142 | } 143 | } 144 | .account-body{ 145 | display: block; 146 | margin-top: 15px; 147 | .logo{ 148 | display: flex; 149 | align-items: center; 150 | justify-content: center; 151 | } 152 | .fiat{ 153 | 154 | width: max-content; 155 | min-width: 80px; 156 | display: flex; 157 | align-items: center; 158 | border-radius: 4px; 159 | border: 1px solid rgba($slightly-black,0.2); 160 | font-size: 14px; 161 | letter-spacing: -0.5px; 162 | line-height: 17px; 163 | font-family: $Lato !important; 164 | padding: 5px; 165 | margin:0 auto; 166 | position: relative; 167 | 168 | ::-webkit-scrollbar { 169 | width: 5px; 170 | } 171 | 172 | /* Track */ 173 | ::-webkit-scrollbar-track { 174 | border-radius:10px ; 175 | } 176 | 177 | /* Handle */ 178 | ::-webkit-scrollbar-thumb { 179 | background: $gray; 180 | border-radius: 10px; 181 | } 182 | 183 | 184 | .value{ 185 | padding-right:2px; 186 | width: max-content; 187 | min-width: 50px; 188 | border-right: 1px solid rgba($slightly-black,0.2); 189 | } 190 | .currency{ 191 | background-image: url('/assets/images/arrow-black.png'); 192 | background-repeat: no-repeat; 193 | background-position: right center; 194 | background-size: 10px; 195 | padding-left: 2px; 196 | padding-right: 15px; 197 | width: max-content; 198 | } 199 | .options { 200 | width: max-content; 201 | border-radius: 2px; 202 | background-color: $white; 203 | position: absolute; 204 | right: 0; 205 | top: 28px; 206 | padding: 0 4px; 207 | overflow: scroll; 208 | z-index: 1; 209 | .option{ 210 | display: flex; 211 | align-items: center; 212 | font-size: 14px; 213 | color: $primary; 214 | height: 40px; 215 | padding: 5px 8px; 216 | cursor: pointer; 217 | img{ 218 | width: 5%; 219 | } 220 | &:hover{ 221 | background-color: #F6F7F9; 222 | } 223 | } 224 | } 225 | } 226 | .balance { 227 | color: $black; 228 | font-size: 26px; 229 | font-weight: bold; 230 | line-height: 28px; 231 | text-align: center; 232 | font-family: $Lato; 233 | margin-top: 5px; 234 | } 235 | .action-buttons{ 236 | display: flex; 237 | justify-content: center; 238 | align-items: center; 239 | button{ 240 | width: auto; 241 | border-width: 0; 242 | border-radius: 4px; 243 | font-size: 15px; 244 | color: $white; 245 | padding: 10px 20px; 246 | min-width: 100px; 247 | background-color: $primary; 248 | font-family: $Lato; 249 | } 250 | } 251 | .option-tabs{ 252 | ::-webkit-scrollbar { 253 | width: 2px; 254 | } 255 | 256 | /* Track */ 257 | ::-webkit-scrollbar-track { 258 | border-radius:10px ; 259 | } 260 | 261 | /* Handle */ 262 | ::-webkit-scrollbar-thumb { 263 | background: $gray; 264 | border-radius: 10px; 265 | } 266 | display: block; 267 | .selection-buttons{ 268 | display: flex; 269 | justify-content: center; 270 | align-items: center; 271 | .selection-button{ 272 | padding-left: 16px; 273 | padding-right: 15px; 274 | width: 47%; 275 | height: 40px; 276 | border-width:0; 277 | outline: none; 278 | font-family: $Lato; 279 | font-size: 13px; 280 | // transition-duration: 1s; 281 | } 282 | } 283 | .selected-tab-data{ 284 | margin: 0 auto; 285 | width: 94%; 286 | overflow-y: scroll; 287 | overflow-x: hidden; 288 | height: 250px; 289 | margin-bottom: 20px; 290 | .row{ 291 | background-color: $background-color; 292 | height: 77px; 293 | padding: 10px 15px; 294 | border-bottom: 1px solid #eee; 295 | font-family: $Lato; 296 | &:hover{ 297 | background-color: $row-hover; 298 | } 299 | } 300 | } 301 | } 302 | } 303 | .header{ 304 | width: 100%; 305 | .account-info{ 306 | width: 50%; 307 | font-family: $Lato; 308 | } 309 | .actions{ 310 | float: right; 311 | width: 50%; 312 | display: flex; 313 | align-items: center; 314 | justify-content: center; 315 | font-family: $Lato; 316 | 317 | } 318 | } 319 | .info-data{ 320 | padding: 10px; 321 | background-color: $white; 322 | width: 80%; 323 | margin: 0 auto; 324 | .title{ 325 | font-size: 16px; 326 | font-weight: bold; 327 | line-height: 19px; 328 | font-family: $Lato !important; 329 | } 330 | .desc{ 331 | font-size: 12px; 332 | line-height: 15px; 333 | font-family: $Lato !important; 334 | color: rgba($secondary-text,0.8); 335 | } 336 | .action-links{ 337 | position: absolute; 338 | bottom: 40px; 339 | .link{ 340 | cursor: pointer; 341 | padding:5px 0; 342 | a{ 343 | color: $primary; 344 | font-size: 14px; 345 | text-decoration: none; 346 | } 347 | } 348 | } 349 | } 350 | } 351 | 352 | .sideMenu{ 353 | 354 | .circle{ 355 | height: 50px; 356 | width: 50px; 357 | border-radius: 50%; 358 | margin-left: 15px; 359 | } 360 | 361 | select{ 362 | all: unset; 363 | color:$white; 364 | font-size: 15px; 365 | font-family: $Lato !important; 366 | background-image:url('/assets/images/down-arrow-white.png'); 367 | background-color: $primary; 368 | background-repeat: no-repeat; 369 | background-size: contain; 370 | background-position-x: right; 371 | background-position-y: center; 372 | background-size: 15px; 373 | padding-right: 20px; 374 | padding-bottom: 3px; 375 | margin-left:15px; 376 | } 377 | .actions{ 378 | height: 100%; 379 | position: relative; 380 | .action{ 381 | margin: 0; 382 | padding: 0; 383 | list-style-type: none; 384 | li{ 385 | width: 95%; 386 | padding: 12px 5px; 387 | cursor: pointer; 388 | text-align: center; 389 | align-items: center; 390 | display: flex; 391 | &:hover{ 392 | background-color: #1753CA; 393 | background-image: url('/assets/images/white-selector.png'); 394 | background-position-x: left; 395 | background-repeat: no-repeat; 396 | background-size: 3%; 397 | } 398 | .icon{ 399 | width: 7%; 400 | float: left; 401 | margin-right:20px; 402 | margin-left: 37px; 403 | } 404 | .value{ 405 | text-align: left; 406 | width: 90%; 407 | font-size: 12px; 408 | color: $white; 409 | } 410 | } 411 | } 412 | } 413 | .logout{ 414 | padding: 10px; 415 | border-top: 1px solid rgba($white,0.2); 416 | position: absolute; 417 | bottom: 10px; 418 | width: 100%; 419 | .icon{ 420 | margin-left: 37px; 421 | width: 7%; 422 | float: left; 423 | margin-right:20px; 424 | } 425 | .value{ 426 | text-align: left; 427 | widows: 90%; 428 | font-size: 12px; 429 | color: $white; 430 | } 431 | } 432 | } 433 | 434 | .sideSettings{ 435 | .heading{ 436 | width:70%; 437 | .title{ 438 | font-size: 17px; 439 | color:$secondary; 440 | text-align: center; 441 | padding-bottom: 10px; 442 | font-weight: bold; 443 | } 444 | } 445 | .body{ 446 | ul{ 447 | all: unset; 448 | li{ 449 | cursor: pointer; 450 | text-align: center; 451 | width: 90%; 452 | padding: 18px 16px; 453 | min-height: 20px; 454 | &:hover{ 455 | background-color: #ECF3FF; 456 | } 457 | .icon{ 458 | width: 10%; 459 | float: left; 460 | margin-right:20px; 461 | margin-left: 37px; 462 | } 463 | .value{ 464 | text-align: left; 465 | widows: 90%; 466 | font-size: 12px; 467 | color: $primary; 468 | } 469 | } 470 | li.selected{ 471 | background-color:#ECF3FF; 472 | background-image: url('/assets/images/blue-selector.png'); 473 | background-position-x: left; 474 | background-repeat: no-repeat; 475 | background-size: 5%; 476 | } 477 | } 478 | .selectDropdown{ 479 | width: 70%; 480 | border: 2px solid $primary; 481 | border-radius: 4px; 482 | padding: 16px; 483 | margin-left: 20px; 484 | img{ 485 | width: 5%; 486 | } 487 | } 488 | .selectOptions{ 489 | width: 70%; 490 | margin-left: 20px; 491 | margin-top: 10px; 492 | padding: 10px; 493 | border-radius: 4px; 494 | box-shadow: 0 0 0 1px #E0E7EE; 495 | .option{ 496 | display: flex; 497 | align-items: center; 498 | justify-content: space-between; 499 | cursor: pointer; 500 | img{ 501 | width: 5%; 502 | } 503 | padding:5px; 504 | &:hover{ 505 | background-color: #F6F7F9; 506 | } 507 | } 508 | } 509 | } 510 | } 511 | 512 | -------------------------------------------------------------------------------- /src/assets/scss/fees.scss: -------------------------------------------------------------------------------- 1 | .fees{ 2 | .network{ 3 | background: rgba($slightly-black,0.02); 4 | text-align: center; 5 | padding: 5px; 6 | } 7 | .desc{ 8 | padding: 0 5px; 9 | text-align: center; 10 | line-height: 15px; 11 | font-size: 12px; 12 | font-family: $Lato; 13 | color: $secondary-text; 14 | } 15 | 16 | } -------------------------------------------------------------------------------- /src/assets/scss/home.scss: -------------------------------------------------------------------------------- 1 | .home{ 2 | width: 100%; 3 | .login-header{ 4 | 5 | .title{ 6 | font-size: 16px; 7 | font-weight: bold; 8 | line-height: 19px; 9 | text-align: center; 10 | font-family: $Lato; 11 | width: 100%; 12 | } 13 | .desc{ 14 | text-align: center; 15 | line-height: 15px; 16 | font-size: 12px; 17 | font-family: $Lato; 18 | color: $secondary-text; 19 | } 20 | 21 | } 22 | .login-body{ 23 | font-family: $Lato !important; 24 | } 25 | } -------------------------------------------------------------------------------- /src/assets/scss/notice.scss: -------------------------------------------------------------------------------- 1 | .notice{ 2 | 3 | position: relative; 4 | .title{ 5 | font-size: 16px; 6 | font-weight: bold; 7 | line-height: 19px; 8 | text-align: center; 9 | font-family: $Lato; 10 | width: 100%; 11 | } 12 | .desc{ 13 | padding: 0 5px; 14 | text-align: center; 15 | line-height: 15px; 16 | font-size: 12px; 17 | font-family: $Lato; 18 | color: $secondary-text; 19 | } 20 | .section { 21 | overflow-y: scroll; 22 | height: 320px; 23 | width: 85%; 24 | border: 1px solid #D8D8D8; 25 | border-radius: 2px; 26 | padding: 10px; 27 | margin:0 auto; 28 | width: 80%; 29 | .text { 30 | color: #000000; 31 | font-family: $Lato; 32 | font-size: 11px; 33 | line-height: 24px; 34 | } 35 | } 36 | .piles{ 37 | width: 20%; 38 | margin: 10px auto; 39 | img{ 40 | margin-left: 10px; 41 | width: 10px; 42 | &:first{ 43 | margin: 0; 44 | } 45 | } 46 | } 47 | .info-image{ 48 | top: -80px; 49 | left: 102px; 50 | position: absolute; 51 | img{ 52 | width: 60%; 53 | } 54 | } 55 | .three-dots{ 56 | margin: 0 auto; 57 | display: flex; 58 | justify-content: center; 59 | align-items: center; 60 | margin-top: 20px; 61 | .dot{ 62 | margin: 0 20px; 63 | width: 8px; 64 | height: 8px; 65 | background-color: rgba($secondary-text,0.3); 66 | border-radius: 50%; 67 | cursor: pointer; 68 | } 69 | .filled{ 70 | background-color: rgba($secondary-text,0.6) !important; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/assets/scss/receive.scss: -------------------------------------------------------------------------------- 1 | .receive-tokens{ 2 | margin: 0 auto; 3 | margin-top: 35px; 4 | // width: 80% !important; 5 | .title{ 6 | font-family: $Lato !important; 7 | font-size: 16px; 8 | font-weight: bold; 9 | line-height: 19px; 10 | color: $black; 11 | text-align: center; 12 | } 13 | .desc{ 14 | color:$slightly-black; 15 | text-align: center; 16 | line-height: 15px; 17 | font-size: 12px; 18 | font-family: $Lato !important; 19 | } 20 | .name{ 21 | background-color: #F5F6FA; 22 | width: 60%; 23 | font-size: 18px; 24 | line-height: 23px; 25 | margin: 0 auto; 26 | padding: 12px; 27 | border-radius: 2px; 28 | } 29 | .qrcode-show{ 30 | width: 120px; 31 | height: 120px; 32 | background: url('/assets/images/qr-code.png'); 33 | background-repeat: no-repeat; 34 | background-position: center; 35 | background-size: cover; 36 | margin:0 auto; 37 | canvas{ 38 | margin-left: 19px !important; 39 | margin-top:19px !important; 40 | } 41 | } 42 | 43 | a{ 44 | text-decoration: none; 45 | color: $primary; 46 | } 47 | } -------------------------------------------------------------------------------- /src/assets/scss/style.scss: -------------------------------------------------------------------------------- 1 | html,body{ 2 | width: 375px !important; 3 | height: 600px; 4 | margin: 0 auto; 5 | 6 | } 7 | body{ 8 | display: flex; 9 | flex-direction: column; 10 | align-items: center; 11 | justify-content: center; 12 | overflow-y: hidden; 13 | position: relative; 14 | .eos-form{ 15 | width: 100%; 16 | .requirements { 17 | list-style-type: none; 18 | padding: 10px; 19 | padding-top: 0; 20 | margin: 0; 21 | width: 90% !important; 22 | li{ 23 | padding: 5px 0; 24 | label{ 25 | padding-left: 35px; 26 | position: relative; 27 | font-size: 12px; 28 | font-family: $Lato !important; 29 | line-height: 15px; 30 | color: $secondary-text; 31 | &::before{ 32 | content: '✓'; 33 | position: absolute; 34 | left: 10px; 35 | top: 0; 36 | font-size: 10px; 37 | border-radius: 50%; 38 | padding: 0 4px; 39 | border:1px solid rgba($slightly-black,0.8); 40 | color: $white; 41 | } 42 | } 43 | input{ 44 | display: none; 45 | &:checked + label{ 46 | &::before{ 47 | background:$green; 48 | } 49 | } 50 | } 51 | 52 | } 53 | } 54 | .elements{ 55 | padding: 10px; 56 | margin: 0 auto; 57 | font-family: $Lato; 58 | width: 90%; 59 | .input{ 60 | border: 1px solid rgba($slightly-black,0.25); 61 | outline: $slightly-black; 62 | border-radius: 2px; 63 | font-size: 1.1em; 64 | padding-right: 0; 65 | width: 100%; 66 | height: 45px; 67 | font-family: $Lato !important; 68 | margin-top: 13px; 69 | box-shadow: 0 2px 10px 0 rgba(0,0,0,0.04); 70 | position: relative; 71 | input{ 72 | all:unset; 73 | width: 70%; 74 | font-family: $Lato; 75 | padding: 5px; 76 | height: 82%; 77 | border-radius: 2px; 78 | } 79 | .dropdown{ 80 | height: 83%; 81 | width: 30%; 82 | border-left: 1px solid rgba($slightly-black,0.25); 83 | padding: 5px; 84 | display: flex; 85 | align-items: center; 86 | justify-content: space-between; 87 | .select{ 88 | background-image:url('/assets/images/down-arrow.png'); 89 | background-repeat: no-repeat; 90 | background-size: contain; 91 | background-position-x: right; 92 | background-position-y: center; 93 | background-size: 10%; 94 | width: 100%; 95 | font-family: $Lato; 96 | } 97 | } 98 | .options { 99 | position: absolute; 100 | top: 45px; 101 | right: 0; 102 | width: 125px; 103 | border-radius: 2px 5px 5px 2px; 104 | background-color: $white; 105 | overflow: scroll; 106 | z-index: 1; 107 | .option{ 108 | display: flex; 109 | align-items: center; 110 | font-size: 14px; 111 | color: $primary; 112 | height: 40px; 113 | padding: 5px 8px; 114 | cursor: pointer; 115 | img{ 116 | width: 5%; 117 | } 118 | &:hover{ 119 | background-color: #F6F7F9; 120 | } 121 | } 122 | } 123 | } 124 | input{ 125 | border-width:0; 126 | border-radius: 2px; 127 | font-size: 1.1em; 128 | padding: 5px; 129 | width: 97%; 130 | height: 35px; 131 | background: #F3F3F3; 132 | font-family: $Lato; 133 | outline: #F3F3F3; 134 | margin-top: 13px; 135 | } 136 | textarea{ 137 | border:1px solid rgba(128, 128, 128, 0.769); 138 | border-radius: 2px; 139 | font-size: 1.1em; 140 | padding: 5px; 141 | width: 97%; 142 | font-family: $Lato; 143 | margin-top: 13px; 144 | } 145 | label{ 146 | // padding: 10px; 147 | text-align: left; 148 | font-family: $Lato; 149 | font-size: 14px; 150 | line-height: 17px; 151 | } 152 | } 153 | } 154 | .border-form{ 155 | width: 100%; 156 | 157 | .requirements { 158 | list-style-type: none; 159 | padding: 10px; 160 | padding-top: 0; 161 | margin: 0; 162 | width: 90% !important; 163 | li{ 164 | padding: 5px 0; 165 | label{ 166 | padding-left: 35px; 167 | position: relative; 168 | font-size: 12px; 169 | font-family: $Lato !important; 170 | line-height: 15px; 171 | color: $secondary-text; 172 | &::before{ 173 | content: '✓'; 174 | position: absolute; 175 | left: 10px; 176 | top: 0; 177 | font-size: 10px; 178 | border-radius: 50%; 179 | padding: 0 4px; 180 | border:1px solid rgba($slightly-black,0.8); 181 | color: $white; 182 | } 183 | } 184 | input{ 185 | display: none; 186 | &:checked + label{ 187 | &::before{ 188 | background:$green; 189 | } 190 | } 191 | } 192 | 193 | } 194 | } 195 | .elements{ 196 | padding: 10px; 197 | margin: 0 auto; 198 | font-family: $Lato; 199 | width: 90% !important; 200 | ::-webkit-scrollbar { 201 | width: 5px; 202 | } 203 | 204 | /* Track */ 205 | ::-webkit-scrollbar-track { 206 | border-radius:10px ; 207 | } 208 | 209 | /* Handle */ 210 | ::-webkit-scrollbar-thumb { 211 | background: $gray; 212 | border-radius: 10px; 213 | } 214 | 215 | .input{ 216 | border: 1px solid rgba($slightly-black,0.25); 217 | outline: $slightly-black; 218 | border-radius: 2px; 219 | font-size: 1.1em; 220 | padding-right: 0; 221 | width: 100%; 222 | height: 45px; 223 | font-family: $Lato !important; 224 | margin-top: 13px; 225 | box-shadow: 0 2px 10px 0 rgba(0,0,0,0.04); 226 | position: relative; 227 | a{ 228 | text-decoration: none; 229 | color: $primary; 230 | } 231 | input{ 232 | all:unset; 233 | width: 70%; 234 | font-family: $Lato; 235 | padding: 5px; 236 | height: 82%; 237 | border-radius: 2px; 238 | } 239 | .dropdown{ 240 | height: 83%; 241 | width: 30%; 242 | border-left: 1px solid rgba($slightly-black,0.25); 243 | padding: 5px; 244 | display: flex; 245 | align-items: center; 246 | justify-content: space-between; 247 | .select{ 248 | background-image:url('/assets/images/down-arrow.png'); 249 | background-repeat: no-repeat; 250 | background-size: contain; 251 | background-position-x: right; 252 | background-position-y: center; 253 | background-size: 10%; 254 | width: 100%; 255 | font-family: $Lato; 256 | } 257 | } 258 | .options { 259 | position: absolute; 260 | top: 45px; 261 | right: 0; 262 | width: 125px; 263 | border-radius: 2px 5px 5px 2px; 264 | background-color: $white; 265 | overflow: scroll; 266 | z-index: 1; 267 | .option{ 268 | display: flex; 269 | align-items: center; 270 | font-size: 14px; 271 | color: $primary; 272 | height: 40px; 273 | padding: 5px 8px; 274 | cursor: pointer; 275 | img{ 276 | width: 5%; 277 | } 278 | &:hover{ 279 | background-color: #F6F7F9; 280 | } 281 | } 282 | } 283 | } 284 | input{ 285 | border-radius: 2px; 286 | font-size: 1.1em; 287 | padding: 5px 10px; 288 | width: 93%; 289 | height: 35px; 290 | background: $white; 291 | font-family: $Lato !important; 292 | border: 1px solid rgba($slightly-black,0.25); 293 | outline: $slightly-black; 294 | margin-top: 13px; 295 | box-shadow: 0 2px 10px 0 rgba(0,0,0,0.04); 296 | } 297 | textarea{ 298 | border: 1px solid rgba($slightly-black,0.25); 299 | border-radius: 2px; 300 | font-size: 1.1em; 301 | padding: 5px 10px; 302 | width: 93%; 303 | font-family: $Lato !important; 304 | margin-top: 13px; 305 | box-shadow: 0 2px 10px 0 rgba(0,0,0,0.04); 306 | } 307 | label{ 308 | // padding: 10px; 309 | text-align: left; 310 | font-family: $Lato; 311 | font-size: 14px; 312 | line-height: 17px; 313 | } 314 | } 315 | } 316 | } 317 | 318 | input{ 319 | border-width: 0px; 320 | } 321 | // button{ 322 | // padding: 5px 10px; 323 | // font-size: 1.1em; 324 | // border-radius: 4px; 325 | // cursor: pointer; 326 | // } -------------------------------------------------------------------------------- /src/assets/scss/styles.scss: -------------------------------------------------------------------------------- 1 | @import 'colors'; 2 | @import 'common'; 3 | @import 'style'; 4 | @import 'home'; 5 | @import 'dashboard'; 6 | @import 'actions'; 7 | @import 'transaction'; 8 | @import 'notice'; 9 | @import '../../../node_modules/ladda/css/ladda-themed'; 10 | @import 'communication'; 11 | @import 'cpu'; 12 | @import 'welcome'; 13 | @import 'receive'; 14 | @import 'fees'; 15 | @import url('https://fonts.googleapis.com/css?family=Lato'); -------------------------------------------------------------------------------- /src/assets/scss/transaction.scss: -------------------------------------------------------------------------------- 1 | .transaction-history{ 2 | .balance{ 3 | color: $primary; 4 | width: 100%; 5 | text-align: center; 6 | } 7 | .close-button{ 8 | background-image: url('/assets/images/menu-close.png'); 9 | background-repeat: no-repeat; 10 | background-size: 40%; 11 | background-position-x: right; 12 | background-position-y: center; 13 | width: 10%; 14 | float: right; 15 | height: 15px; 16 | margin-right: 30px; 17 | margin-top: -20px; 18 | cursor: pointer; 19 | } 20 | .title{ 21 | font-weight: bold; 22 | color: #a2a1a1; 23 | text-align: center; 24 | font-size: 16px; 25 | width: 100%; 26 | } 27 | .tabs{ 28 | width: 90%; 29 | margin:0 auto; 30 | background-color: rgba($color: #BEBEBE, $alpha: 0.06); 31 | .tab{ 32 | padding: 20px 0; 33 | width: 31.3%; 34 | font-size: 13px; 35 | background-color: rgba($color: #BEBEBE, $alpha: 0.06); 36 | float: left; 37 | cursor: pointer; 38 | color: $gray; 39 | } 40 | ::-webkit-scrollbar { 41 | width: 2px; 42 | } 43 | 44 | /* Track */ 45 | ::-webkit-scrollbar-track { 46 | border-radius:10px ; 47 | } 48 | 49 | /* Handle */ 50 | ::-webkit-scrollbar-thumb { 51 | background: $gray; 52 | border-radius: 10px; 53 | } 54 | 55 | .tab-data{ 56 | max-height: 500px; 57 | overflow-x: hidden; 58 | width: 100%; 59 | .row{ 60 | background-color: rgba($color: #BEBEBE, $alpha: 0.06);; 61 | height: 77px; 62 | padding: 10px 15px; 63 | border-bottom: 1px solid #eee; 64 | font-family: $Lato; 65 | &:hover{ 66 | background-color: $row-hover; 67 | } 68 | } 69 | } 70 | .submitted-background{ 71 | background-color: #FEFAF4 !important; 72 | } 73 | .submitted-text{ 74 | color: $warn; 75 | } 76 | 77 | .failed-background{ 78 | background-color: #FFF6F6 !important; 79 | } 80 | .failed-text{ 81 | color: $failed; 82 | } 83 | 84 | .confirmed-background{ 85 | background-color: #F6FDEE !important; 86 | } 87 | 88 | .confirmed-text{ 89 | color: $confirmed; 90 | } 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /src/assets/scss/welcome.scss: -------------------------------------------------------------------------------- 1 | .welcome{ 2 | position: absolute; 3 | top: 13.83%; 4 | padding: 0 8.53%; 5 | .box-layout{ 6 | position: relative; 7 | font-family: $Lato !important; 8 | .logo{ 9 | display: flex; 10 | justify-content: center; 11 | align-items: center; 12 | } 13 | .name{ 14 | margin-top: 2.55%; 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | font-size: 30px; 19 | font-weight: bold; 20 | line-height: 48px; 21 | } 22 | .desc{ 23 | font-size: 14px; 24 | line-height: 27px; 25 | text-align: center; 26 | } 27 | 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /src/contentscript.js: -------------------------------------------------------------------------------- 1 | import {External_Channels } from './app/constants/enums'; 2 | 3 | // all the events emited here get catch on websites 4 | 5 | const getData = () => { 6 | var port = chrome.runtime.connect({name:External_Channels.GETDATA}); 7 | port.postMessage({}); 8 | port.onMessage.addListener((response)=>{ 9 | if(response.status) { 10 | window.dispatchEvent(new CustomEvent(External_Channels.GETDATA_RES,{detail:response})); 11 | port.disconnect(); 12 | } 13 | }); 14 | } 15 | 16 | const connect = () => { 17 | var port = chrome.runtime.connect({name:External_Channels.CONNECT}); 18 | port.postMessage({message:'handshake'}); 19 | } 20 | 21 | const sendTransaction = (tranaction)=>{ 22 | console.log("Details ==> ",tranaction); 23 | var port = chrome.runtime.connect({name:External_Channels.SEND}); 24 | port.postMessage(tranaction.detail); 25 | } 26 | 27 | const sendCustomAction = (customAction)=>{ 28 | console.log("Custom Details ==> ",customAction); 29 | var port = chrome.runtime.connect({name:External_Channels.SEND_CUSTOM_ACTION}); 30 | port.postMessage(customAction.detail); 31 | } 32 | 33 | 34 | // event listners for events emitted from any js website 35 | 36 | window.addEventListener(External_Channels.SEND_CUSTOM_ACTION,sendCustomAction); 37 | window.addEventListener(External_Channels.GETDATA,getData); 38 | window.addEventListener(External_Channels.CONNECT,connect); 39 | window.addEventListener(External_Channels.SEND,sendTransaction); 40 | 41 | 42 | // dispach events after getting response form the bg script 43 | chrome.runtime.onConnect.addListener((port)=>{ 44 | port.onMessage.addListener((response)=>{ 45 | port.disconnect(); 46 | window.dispatchEvent(new CustomEvent(`${port.name}Response`,{detail:response})); 47 | }); 48 | }); 49 | 50 | 51 | // inject the contentScript to every js enabled website 52 | 53 | const injectPulseScript = async ()=>{ 54 | if(window.document){ 55 | const codeScript = document.createElement('script'); 56 | codeScript.src = chrome.extension.getURL('vendor.min.js'); 57 | (window.document.head || window.document.documentElement).appendChild(codeScript); 58 | codeScript.remove(); // this remove the code after injection 59 | } 60 | }; 61 | 62 | injectPulseScript(); 63 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Document 12 | 13 | 14 |
15 | 16 | --------------------------------------------------------------------------------