├── .gitignore ├── .travis.yml ├── .vscode └── vetur │ └── snippets │ └── vue.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md └── dashboard ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── .vscode └── vetur │ └── snippets │ ├── template-typescript-w-decorator.vue │ └── vue.json ├── Dockerfile ├── README.md ├── TESTING.md ├── babel.config.js ├── docker-compose.yml ├── justfile ├── local-compose.yml ├── package.json ├── postcss.config.js ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── img │ └── icons │ │ └── favicon-32x32.png ├── index.html ├── manifest.webmanifest ├── mstile-150x150.png ├── robots.txt └── safari-pinned-tab.svg ├── src ├── App.vue ├── assets │ ├── android-chrome-192x192.png │ ├── koda_logo_843x843.png │ └── vue-polkadot.png ├── colors.scss ├── components │ ├── FourZeroFour.vue │ ├── SidebarMenu.vue │ ├── accounts │ │ └── Accounts.vue │ ├── addressbook │ │ └── Addressbook.vue │ ├── democracy │ │ ├── Conviction.vue │ │ ├── Democracy.vue │ │ ├── DemocracyWrapper.vue │ │ ├── Preimage.vue │ │ ├── Proposal.vue │ │ ├── Proposals.vue │ │ ├── Referendum.vue │ │ ├── Referendums.vue │ │ ├── Seconds.vue │ │ ├── SubmitProposal.vue │ │ ├── Summary.vue │ │ ├── VoteDropdown.vue │ │ ├── convictionUtil.ts │ │ ├── referendumState.ts │ │ └── test.json │ ├── explorer │ │ ├── BlockDetails.vue │ │ ├── Explorer.vue │ │ ├── NetworkVisualCue.vue │ │ ├── NodeDetails.vue │ │ ├── NodeVerbose.vue │ │ ├── RecentBlocks.vue │ │ ├── RecentEvents.vue │ │ ├── SingleBlockDetail.vue │ │ ├── SingleBlockEventDetail.vue │ │ ├── SingleBlockExtrinsicsDetail.vue │ │ ├── SingleEventDetail.vue │ │ ├── Summary.vue │ │ └── SummarySession.vue │ ├── extrinsics │ │ ├── ArgumentHandler.vue │ │ ├── Arguments.vue │ │ ├── Balance.vue │ │ ├── Executor.vue │ │ ├── InputHandler.vue │ │ ├── Selection.vue │ │ └── components │ │ │ └── InputFile.vue │ ├── landing │ │ └── Landing.vue │ ├── metadata │ │ └── Metadata.vue │ ├── offline │ │ └── Offline.vue │ ├── rpc │ │ ├── CallRPC.vue │ │ └── RPC.vue │ ├── settings │ │ ├── AddOption.vue │ │ ├── General.vue │ │ ├── SettingChooser.vue │ │ ├── SettingChooserDevelopment.vue │ │ └── SettingChooserExplorer.vue │ ├── shared │ │ ├── AccountInput.vue │ │ ├── AccountNameTag.vue │ │ ├── AccountSelect.vue │ │ ├── Balance.vue │ │ ├── BalanceInput.vue │ │ ├── BlockExplorer.vue │ │ ├── Card.vue │ │ ├── CardEvents.vue │ │ ├── CardExtrinsic.vue │ │ ├── CardRecentEvent.vue │ │ ├── ChainProperties.vue │ │ ├── Collapse.vue │ │ ├── DisabledInput.vue │ │ ├── Dropdown.vue │ │ ├── FileLoad.vue │ │ ├── OptionDropdown.vue │ │ ├── Password.vue │ │ ├── PasswordInput.vue │ │ ├── ProgressBar.vue │ │ ├── SectionTitle.vue │ │ ├── SettingInfo.vue │ │ ├── Table.vue │ │ ├── TxButton.vue │ │ ├── ViewTransaction.vue │ │ ├── WithKeyring.vue │ │ ├── accounts │ │ │ ├── Backup.vue │ │ │ ├── ChangePassword.vue │ │ │ ├── Create.vue │ │ │ ├── Keypair.vue │ │ │ └── Restore.vue │ │ ├── collapse │ │ │ └── CollapseWrapper.vue │ │ ├── format │ │ │ ├── Identity.vue │ │ │ ├── Money.vue │ │ │ ├── Percent.vue │ │ │ └── WithLabel.vue │ │ ├── modals │ │ │ ├── ModalWrapper.vue │ │ │ ├── Proposal.vue │ │ │ ├── Second.vue │ │ │ ├── Tip.vue │ │ │ └── Vote.vue │ │ └── wrapper │ │ │ ├── EmptyGuard.vue │ │ │ ├── ItemCard.vue │ │ │ └── SummaryCard.vue │ ├── staking │ │ ├── AccountsInfo.vue │ │ ├── Actions │ │ │ ├── ActionModal.vue │ │ │ ├── Actions.vue │ │ │ ├── ElectionBanner.vue │ │ │ ├── NewNominator.vue │ │ │ ├── NewStash.vue │ │ │ ├── NewValidator.vue │ │ │ ├── TableOverview.vue │ │ │ ├── ValidatorRow.vue │ │ │ ├── constants.ts │ │ │ ├── partial │ │ │ │ ├── BondExtra.vue │ │ │ │ ├── BondPartial.vue │ │ │ │ ├── Nominate.vue │ │ │ │ ├── NominateInput.vue │ │ │ │ ├── NominatePartial.vue │ │ │ │ ├── SetCommision.vue │ │ │ │ ├── SetControllerAccount.vue │ │ │ │ ├── SetRewardDestination.vue │ │ │ │ ├── SetSessionKey.vue │ │ │ │ ├── Stop.vue │ │ │ │ └── Unbond.vue │ │ │ ├── stashInfo.ts │ │ │ └── types.ts │ │ ├── Nominators.vue │ │ ├── Overview.vue │ │ ├── Payouts │ │ │ ├── PayoutBanner.vue │ │ │ ├── Payouts.vue │ │ │ ├── StashRow.vue │ │ │ ├── TableOverview.vue │ │ │ ├── ValidatorRow.vue │ │ │ ├── ValidatorWarningMessage.vue │ │ │ ├── getOwnEraRewards.ts │ │ │ ├── types.ts │ │ │ └── utils.ts │ │ ├── StakerInfo.vue │ │ ├── Summary.vue │ │ ├── TableOverview.vue │ │ ├── Targets │ │ │ ├── Summary.vue │ │ │ ├── TableOverview.vue │ │ │ ├── Targets.vue │ │ │ ├── ValidatorRow.vue │ │ │ ├── registry.ts │ │ │ └── utills.ts │ │ ├── ValidatorRow.vue │ │ ├── Waiting │ │ │ ├── TableOverview.vue │ │ │ ├── ValidatorRow.vue │ │ │ ├── Waiting.vue │ │ │ └── utils.ts │ │ ├── getEraPoints.ts │ │ ├── types.ts │ │ └── utils.ts │ ├── storage │ │ ├── Constants.vue │ │ ├── Queries.vue │ │ ├── Query.vue │ │ ├── Raw.vue │ │ ├── Storage.vue │ │ ├── extractParams.ts │ │ └── types.ts │ ├── toolbox │ │ ├── ConvertAddress.vue │ │ ├── HashData.vue │ │ ├── SignMessage.vue │ │ ├── Toolbox.vue │ │ └── VerifySignature.vue │ ├── transfer │ │ ├── SignSubmit.vue │ │ ├── Transfer.vue │ │ └── TxSelect.vue │ └── treasury │ │ ├── Proposal.vue │ │ ├── Proposals.vue │ │ ├── Summary.vue │ │ ├── Tip.vue │ │ ├── Tips.vue │ │ ├── Treasury.vue │ │ └── TreasuryWrapper.vue ├── icons.ts ├── main.ts ├── params │ ├── components │ │ ├── Account.vue │ │ ├── Amount.vue │ │ ├── Balance.vue │ │ ├── Bool.vue │ │ ├── Bytes.vue │ │ ├── Call.vue │ │ ├── Code.vue │ │ ├── Data.vue │ │ ├── DispatchError.vue │ │ ├── Enum.vue │ │ ├── FileUpload.vue │ │ ├── Hash256.vue │ │ ├── Hash512.vue │ │ ├── KeyValue.vue │ │ ├── KeyValueArray.vue │ │ ├── Moment.vue │ │ ├── Null.vue │ │ ├── OpaqueCall.vue │ │ ├── Option.vue │ │ ├── Proposal.vue │ │ ├── Raw.vue │ │ ├── Struct.vue │ │ ├── TextField.vue │ │ ├── Tuple.vue │ │ ├── Unknown.vue │ │ ├── Vector.vue │ │ ├── Vote.vue │ │ ├── VoteThreshold.vue │ │ ├── findComponent.ts │ │ ├── generator.sh │ │ ├── imports │ │ ├── newImports │ │ ├── script.txt │ │ └── typeRegistry.ts │ ├── constants.ts │ └── types.ts ├── registerServiceWorker.ts ├── routeGuard.ts ├── router │ ├── accounts.ts │ ├── explorer.ts │ ├── index.ts │ ├── staking.ts │ ├── staking2.ts │ ├── toolbox.ts │ └── transfer.ts ├── shims-tsx.d.ts ├── shims-vue.d.ts ├── store.ts ├── types.ts ├── utils │ ├── WithKeyring.ts │ ├── chainProperties.ts │ ├── empty.ts │ ├── explorerGuide.ts │ ├── filters.ts │ ├── formatBalance.ts │ ├── isFunction.ts │ ├── mixins │ │ ├── extrinsicsMixin.ts │ │ ├── identityMixin.ts │ │ ├── keyringMixin.ts │ │ ├── queryMixin.ts │ │ └── subscribeMixin.ts │ ├── notification.ts │ ├── shortAddress.ts │ ├── transactionExecutor.ts │ └── vueNotification.ts ├── views │ ├── ChainState.vue │ ├── Debug.vue │ ├── Extrinsics.vue │ ├── Settings.vue │ ├── Staking.vue │ └── accounts │ │ ├── Accounts.vue │ │ ├── AccountsBackup.vue │ │ ├── AccountsChangePassword.vue │ │ ├── AccountsCreate.vue │ │ ├── AccountsRestore.vue │ │ └── AddressbookCreate.vue └── vuex │ └── IdentityModule.ts ├── tsconfig.json ├── tslint.json ├── vue.config.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | .idea/ 9 | # Runtime data 10 | pids 11 | *.pid 12 | *.seed 13 | *.pid.lock 14 | 15 | # Directory for instrumented libs generated by jscoverage/JSCover 16 | lib-cov 17 | 18 | # Coverage directory used by tools like istanbul 19 | coverage 20 | 21 | # nyc test coverage 22 | .nyc_output 23 | 24 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 25 | .grunt 26 | 27 | # Bower dependency directory (https://bower.io/) 28 | bower_components 29 | 30 | # node-waf configuration 31 | .lock-wscript 32 | 33 | # Compiled binary addons (https://nodejs.org/api/addons.html) 34 | build/Release 35 | 36 | # Dependency directories 37 | node_modules/ 38 | jspm_packages/ 39 | 40 | # TypeScript v1 declaration files 41 | typings/ 42 | 43 | # Optional npm cache directory 44 | .npm 45 | 46 | # Optional eslint cache 47 | .eslintcache 48 | 49 | # Optional REPL history 50 | .node_repl_history 51 | 52 | # Output of 'npm pack' 53 | *.tgz 54 | 55 | # Yarn Integrity file 56 | .yarn-integrity 57 | 58 | # dotenv environment variables file 59 | .env 60 | 61 | # next.js build output 62 | .next 63 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | cache: 5 | yarn: true 6 | directories: 7 | - node_modules 8 | before_install: 9 | - curl -o- -L https://yarnpkg.com/install.sh | bash 10 | - export PATH=$HOME/.yarn/bin:$PATH 11 | script: 12 | - cd dashboard;yarn;yarn run build 13 | deploy: 14 | provider: pages 15 | keep-history: true 16 | skip_cleanup: true 17 | local_dir: dist/ 18 | github-token: $GITHUB_TOKEN 19 | repo: dysonring/vue-apps-polkadot 20 | target-branch: gh-pages 21 | on: 22 | branch: master 23 | -------------------------------------------------------------------------------- /.vscode/vetur/snippets/vue.json: -------------------------------------------------------------------------------- 1 | { 2 | "vue typescript w decorator": { 3 | "prefix": "" 10 | "" 20 | ], 21 | "description": "vue template w decorator component" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Issues 4 | 5 | Issues are very valuable to this project. 6 | 7 | * Ideas are a valuable source of contributions others can make 8 | * Problems show where this project is lacking 9 | * With a question you show where contributors can improve the user experience 10 | 11 | Thank you for creating them. 12 | 13 | ## Pull Requests 14 | 15 | Pull requests are, a great way to get your ideas into this repository. 16 | 17 | When deciding if I merge in a pull request I look at the following things: 18 | 19 | ### Does it state intent 20 | 21 | You should be clear which problem you're trying to solve with your contribution. 22 | 23 | For example: 24 | 25 | > Add link to code of conduct in README.md 26 | 27 | Doesn't tell me anything about why you're doing that 28 | 29 | > Add link to code of conduct in README.md because users don't always look in the CONTRIBUTING.md 30 | 31 | **Tells me the problem that you have found, and the pull request shows me the action you have taken to solve it.** 32 | 33 | 34 | ### Is it of good quality 35 | 36 | * There are no spelling mistakes 37 | * It reads well 38 | * For english language contributions: Has a good score on [Grammarly](grammarly.com) or [Hemingway App](http://www.hemingwayapp.com/) 39 | 40 | ### Does it move this repository closer to my vision for the repository 41 | 42 | The aim of this repository is: 43 | 44 | * To provide a [README](README.md) and assorted documents anyone can copy and paste, into their project 45 | * The content is usable by someone who hasn't written something like this before 46 | * Foster a culture of respect and gratitude in the open source community. 47 | 48 | ### Does it follow the contributor covenant 49 | 50 | This repository has a [code of conduct](CODE_OF_CONDUCT.md), This repository has a code of conduct, I will remove things that do not respect it. 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 DysonRing 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dashboard/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /dashboard/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | # Unix-style newlines with a newline ending every file 4 | [*] 5 | end_of_line = lf 6 | insert_final_newline = true 7 | 8 | # Matches multiple files with brace expansion notation 9 | # Set default charset 10 | [*.{js,py}] 11 | charset = utf-8 12 | 13 | # Indentation override for all JS 14 | [**.js] 15 | indent_style = space 16 | indent_size = 2 17 | quote_type = single 18 | 19 | # Indentation override for all VUE 20 | [**.vue] 21 | indent_style = space 22 | indent_size = 2 23 | quote_type = single 24 | 25 | # Indentation override for all TS 26 | [**.ts] 27 | indent_style = space 28 | indent_size = 2 29 | quote_type = single 30 | -------------------------------------------------------------------------------- /dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | yarn.lock 5 | package-lock.json 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | #.vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | 24 | .vercel 25 | -------------------------------------------------------------------------------- /dashboard/.vscode/vetur/snippets/template-typescript-w-decorator.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | -------------------------------------------------------------------------------- /dashboard/.vscode/vetur/snippets/vue.json: -------------------------------------------------------------------------------- 1 | { 2 | "vue typescript w decorator": { 3 | "prefix": "" 10 | "" 20 | ], 21 | "description": "vue template w decorator component" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14 as builder 2 | 3 | ### RUN npm install -g yarn 4 | 5 | RUN yarn global add http-server 6 | 7 | WORKDIR /dashboard 8 | 9 | ### leverage docker fs cache http://bitjudo.com/blog/2014/03/13/building-efficient-dockerfiles-node-dot-js/ 10 | COPY package.json . 11 | 12 | COPY yarn.lock . 13 | 14 | RUN yarn 15 | 16 | COPY . . 17 | 18 | RUN yarn build 19 | 20 | EXPOSE 8080 21 | CMD ["http-server", "dist"] 22 | -------------------------------------------------------------------------------- /dashboard/README.md: -------------------------------------------------------------------------------- 1 | # dashboard 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn run serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn run build 16 | ``` 17 | 18 | ### Run your tests 19 | ``` 20 | yarn run test 21 | ``` 22 | 23 | ### Lints and fixes files 24 | ``` 25 | yarn run lint 26 | ``` 27 | 28 | ### Dev hints 29 | 30 | In order to execute some transaction you can use `exec` located in `src/utils/transactionExecutor.ts` 31 | Usage: 32 | ```js 33 | import exec from '@/utils/transactionExecutor'; 34 | 35 | // arguments: from which account, password for account, which action, array of parameters 36 | this.tx = await exec(this.account, this.password, api.tx.democracy.vote, [referendumId, { aye, conviction }]); 37 | ``` 38 | 39 | #### Using reactive properties 40 | Some of the properies on the component needs to be automatically updated (currentBlock) 41 | 42 | Usage: 43 | ```html 44 | 47 | 48 | 65 | ``` 66 | 67 | ### Customize configuration 68 | See [Configuration Reference](https://cli.vuejs.org/config/). 69 | -------------------------------------------------------------------------------- /dashboard/TESTING.md: -------------------------------------------------------------------------------- 1 | KUSAMA acc 2 | 3 | GTzRQPzkcuynHgkEHhsPBFpKdh4sAacVRsnd8vYfPpTMeEY Polkastat 4 | Cn2LmF7os4b4uxkRVZa3bqmXAYEmXybDbHKXabqy6kKNwwK 5 | DABmvpEuvFssthysEcTePxuLfQHebJQr2F4n31xZCvCFcXe 6 | 7 | 8 | const { api } = C.getInstance() 9 | api.derive.chain. 10 | await api.query.system.events.at('0xacbf31202a89627b57a68e762040fe8829b917fcb64842aaa5452f0e593aa17a') 11 | 12 | 0x27e7a17305ce99d357bb8f147754c9fdcf701fefc5d09e9cc042e8eaa9b35dc0 13 | -------------------------------------------------------------------------------- /dashboard/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ], 5 | plugins: [ 6 | '@babel/plugin-proposal-optional-chaining' 7 | ], 8 | } 9 | -------------------------------------------------------------------------------- /dashboard/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | kusama: 4 | image: parity/polkadot:latest 5 | logging: 6 | driver: "json-file" 7 | options: 8 | max-size: "100M" 9 | max-file: "2" 10 | volumes: 11 | - ./data_ksmcc2:/data/chains 12 | ports: 13 | - "127.0.0.1:9933:9933" 14 | - "0.0.0.0:9944:9944" 15 | - "127.0.0.1:30333:30333" 16 | command: ['--chain','kusama','--name', 'KodaDot','--out-peers','20','--in-peers','20','--ws-external','--rpc-external','--rpc-cors','all', '--wasm-execution=Compiled' ] 17 | kodadot: 18 | image: yangwao/kodadot:develop-latest 19 | logging: 20 | driver: "json-file" 21 | options: 22 | max-size: "100M" 23 | max-file: "2" 24 | ports: 25 | - "0.0.0.0:8080:8080" 26 | 27 | -------------------------------------------------------------------------------- /dashboard/justfile: -------------------------------------------------------------------------------- 1 | upgrade: 2 | yarn add @polkadot/types @polkadot/ui-keyring @polkadot/ui-settings @polkadot/util @polkadot/util-crypto @polkadot/vue-identicon 3 | -------------------------------------------------------------------------------- /dashboard/local-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.6' 2 | services: 3 | substrate: 4 | image: parity/polkadot:latest 5 | logging: 6 | driver: "json-file" 7 | options: 8 | max-size: "100M" 9 | max-file: "2" 10 | volumes: 11 | - ./data_local_alice:/data/chains 12 | ports: 13 | - "0.0.0.0:9933:9933" 14 | - "0.0.0.0:9944:9944" 15 | - "127.0.0.1:30333:30333" 16 | command: ['--dev','--ws-external','--rpc-cors','all', '--wasm-execution=Compiled','--alice', '--rpc-methods=Unsafe'] 17 | kodadot: 18 | image: yangwao/kodadot:develop-latest 19 | logging: 20 | driver: "json-file" 21 | options: 22 | max-size: "100M" 23 | max-file: "2" 24 | ports: 25 | - "0.0.0.0:8080:8080" 26 | -------------------------------------------------------------------------------- /dashboard/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dashboard", 3 | "version": "1.8.1", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint", 9 | "start": "vue-cli-service serve" 10 | }, 11 | "dependencies": { 12 | "@fortawesome/fontawesome-common-types": "^0.2.27", 13 | "@fortawesome/fontawesome-svg-core": "^1.2.27", 14 | "@fortawesome/free-brands-svg-icons": "^5.12.1", 15 | "@fortawesome/free-solid-svg-icons": "^5.12.1", 16 | "@fortawesome/vue-fontawesome": "^0.1.9", 17 | "@polkadot/types": "^2.3.1", 18 | "@polkadot/ui-keyring": "^0.61.1", 19 | "@polkadot/ui-settings": "^0.61.1", 20 | "@polkadot/util": "^3.6.1", 21 | "@polkadot/util-crypto": "^3.6.1", 22 | "@polkadot/vue-identicon": "^0.61.1", 23 | "@types/file-saver": "^2.0.1", 24 | "@vue-polkadot/vue-api": "^0.0.24", 25 | "@vue-polkadot/vue-identicon": "^0.0.8", 26 | "@vue-polkadot/vue-settings": "0.0.15", 27 | "buefy": "^0.9.2", 28 | "core-js": "^2.6.5", 29 | "file-saver": "^2.0.2", 30 | "register-service-worker": "^1.7.1", 31 | "serialize-javascript": "^3.1.0", 32 | "setimmediate": "^1.0.5", 33 | "vue": "2.6.11", 34 | "vue-class-component": "^7.2.2", 35 | "vue-clipboard2": "^0.3.1", 36 | "vue-property-decorator": "^8.4.0", 37 | "vue-router": "^3.1.5", 38 | "vuex": "^3.1.2", 39 | "vuex-persist": "^2.2.0" 40 | }, 41 | "devDependencies": { 42 | "@babel/plugin-proposal-optional-chaining": "^7.11.0", 43 | "@vue/cli-plugin-babel": "^3.12.1", 44 | "@vue/cli-plugin-pwa": "~4.4.0", 45 | "@vue/cli-plugin-typescript": "^4.2.3", 46 | "@vue/cli-service": "^4.2.3", 47 | "sass": "^1.26.5", 48 | "sass-loader": "^8.0.2", 49 | "tslint": "^6.1.0", 50 | "typescript": "^3.8.3", 51 | "vue-template-compiler": "2.6.11" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /dashboard/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /dashboard/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /dashboard/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /dashboard/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/apple-touch-icon.png -------------------------------------------------------------------------------- /dashboard/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /dashboard/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/favicon-16x16.png -------------------------------------------------------------------------------- /dashboard/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/favicon-32x32.png -------------------------------------------------------------------------------- /dashboard/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/favicon.ico -------------------------------------------------------------------------------- /dashboard/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /dashboard/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | KodaDot - Polkadot Wallet 10 | 48 | 49 | 50 | 56 |
57 |
58 |

🔌 Charging 🏛 Governance Reality

59 |
60 |
61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /dashboard/public/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "KodaDot - Polkadot Wallet", 3 | "short_name": "KodaDot", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone", 19 | "start_url": "/", 20 | "scope": "/" 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/public/mstile-150x150.png -------------------------------------------------------------------------------- /dashboard/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /dashboard/src/assets/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/src/assets/android-chrome-192x192.png -------------------------------------------------------------------------------- /dashboard/src/assets/koda_logo_843x843.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/src/assets/koda_logo_843x843.png -------------------------------------------------------------------------------- /dashboard/src/assets/vue-polkadot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vue-polkadot/apps/46b6253762df2a9e3fabda56cadd2c742935480e/dashboard/src/assets/vue-polkadot.png -------------------------------------------------------------------------------- /dashboard/src/colors.scss: -------------------------------------------------------------------------------- 1 | $primary: #d32e79; 2 | $primary-invert: findColorInvert($primary); 3 | $dark: rgba(0,0,0,0.74); 4 | $dark-invert: findColorInvert($dark); 5 | $less-white: #fcfcfc 6 | -------------------------------------------------------------------------------- /dashboard/src/components/FourZeroFour.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/Conviction.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 33 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/DemocracyWrapper.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 43 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/Preimage.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 40 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/Proposals.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/Referendums.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/Seconds.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 39 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/VoteDropdown.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/convictionUtil.ts: -------------------------------------------------------------------------------- 1 | import Connector from '@vue-polkadot/vue-api'; 2 | 3 | export interface ConvictionOption { 4 | text: string; 5 | value: number; 6 | } 7 | 8 | const messageTransfer = (value: any, lock: any, period: any) => 9 | `${value}x voting balance, locked for ${lock}x enactment (${period} days)`; 10 | 11 | const CONVICTIONS: [number, number][] = [ 12 | 1, 13 | 2, 14 | 4, 15 | 8, 16 | 16, 17 | 32, 18 | ].map((lock, index) => [index + 1, lock]); 19 | 20 | const convictionMapper = ( 21 | [value, lock]: [number, number], 22 | enact: number, 23 | ): ConvictionOption => ({ 24 | text: messageTransfer(value, lock, (enact * lock).toFixed(2)), 25 | value, 26 | }); 27 | 28 | export default (): ConvictionOption[] => { 29 | const { api } = Connector.getInstance(); 30 | 31 | if (!api) { 32 | return []; 33 | } 34 | 35 | const enact = 36 | (((api.consts.democracy.enactmentPeriod.toNumber() * 37 | api.consts.timestamp.minimumPeriod.toNumber()) / 38 | 1000) * 39 | 2) / 40 | 60 / 41 | 60 / 42 | 24; 43 | 44 | return [ 45 | { text: '0.1x voting balance, no lockup period', value: 0 }, 46 | ...CONVICTIONS.map((pair) => convictionMapper(pair, enact)), 47 | ]; 48 | }; 49 | -------------------------------------------------------------------------------- /dashboard/src/components/democracy/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "balance": 10000000000000, 3 | "hash": "0x90a1b2f648fc4eaff4f236b9af9ead77c89ecac953225c5fafb069d27b7131b7", 4 | "index": 9, 5 | "preimage": { 6 | "at": 844839, 7 | "balance": 3400000000, 8 | "proposer": "CpjsLDC1JFyrhm3ftC9Gs4QoyrkHKhZKtK7YqGTRFtTafgp" 9 | }, 10 | "proposal": { 11 | "callIndex": "0x1900", 12 | "args": { "account": "E4x8NJPyoNsx1EAgoUKGo1a8FcZpw6Y2XZKNQuqAuZUqjjA" } 13 | }, 14 | "proposer": "CpjsLDC1JFyrhm3ftC9Gs4QoyrkHKhZKtK7YqGTRFtTafgp", 15 | "seconds": [ 16 | "CpjsLDC1JFyrhm3ftC9Gs4QoyrkHKhZKtK7YqGTRFtTafgp", 17 | "GcBoDaTtuWx88sL1th8BPWjoAdjiVzwMvv7ojbbJvEzP6uJ", 18 | "H9eSvWe34vQDJAWckeTHWSqSChRat8bgKHG39GC1fjvEm7y", 19 | "CmD9vaMYoiKe7HiFnfkftwvhKbxN9bhyjcDrfFRGbifJEG8" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/src/components/explorer/NetworkVisualCue.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 39 | 40 | 56 | -------------------------------------------------------------------------------- /dashboard/src/components/explorer/NodeVerbose.vue: -------------------------------------------------------------------------------- 1 | 17 | 49 | -------------------------------------------------------------------------------- /dashboard/src/components/explorer/RecentBlocks.vue: -------------------------------------------------------------------------------- 1 | 9 | 42 | -------------------------------------------------------------------------------- /dashboard/src/components/explorer/SingleBlockEventDetail.vue: -------------------------------------------------------------------------------- 1 | 12 | 41 | -------------------------------------------------------------------------------- /dashboard/src/components/explorer/SingleEventDetail.vue: -------------------------------------------------------------------------------- 1 | 10 | 51 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/Arguments.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 53 | 54 | 65 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/Balance.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 28 | 29 | 34 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/Executor.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 39 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/InputHandler.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 31 | 32 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/Selection.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 78 | -------------------------------------------------------------------------------- /dashboard/src/components/extrinsics/components/InputFile.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 47 | 48 | 57 | -------------------------------------------------------------------------------- /dashboard/src/components/landing/Landing.vue: -------------------------------------------------------------------------------- 1 | 30 | 41 | 42 | 47 | -------------------------------------------------------------------------------- /dashboard/src/components/metadata/Metadata.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 52 | -------------------------------------------------------------------------------- /dashboard/src/components/offline/Offline.vue: -------------------------------------------------------------------------------- 1 | 8 | 14 | 15 | 29 | -------------------------------------------------------------------------------- /dashboard/src/components/rpc/RPC.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 38 | -------------------------------------------------------------------------------- /dashboard/src/components/settings/AddOption.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 38 | 39 | -------------------------------------------------------------------------------- /dashboard/src/components/settings/General.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 32 | -------------------------------------------------------------------------------- /dashboard/src/components/settings/SettingChooser.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 54 | -------------------------------------------------------------------------------- /dashboard/src/components/settings/SettingChooserDevelopment.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 48 | 53 | -------------------------------------------------------------------------------- /dashboard/src/components/settings/SettingChooserExplorer.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 55 | 60 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/AccountNameTag.vue: -------------------------------------------------------------------------------- 1 | 8 | 16 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/AccountSelect.vue: -------------------------------------------------------------------------------- 1 | 14 | 46 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/Balance.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 34 | 35 | 40 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/BalanceInput.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 30 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/BlockExplorer.vue: -------------------------------------------------------------------------------- 1 | 7 | 18 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/CardEvents.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 42 | 58 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/ChainProperties.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/Collapse.vue: -------------------------------------------------------------------------------- 1 | 21 | 41 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/DisabledInput.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/FileLoad.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 60 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/OptionDropdown.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/Password.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/PasswordInput.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 39 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/ProgressBar.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/SectionTitle.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 13 | 14 | 20 | 21 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/SettingInfo.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 26 | 27 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/Table.vue: -------------------------------------------------------------------------------- 1 | 6 | 15 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/TxButton.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 50 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/ViewTransaction.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 22 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/WithKeyring.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/accounts/Restore.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 52 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/collapse/CollapseWrapper.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 24 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/format/Identity.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 70 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/format/Money.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 31 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/format/Percent.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 20 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/format/WithLabel.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/modals/ModalWrapper.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 47 | 48 | 53 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/wrapper/EmptyGuard.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 29 | 30 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/wrapper/ItemCard.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 19 | 20 | 26 | -------------------------------------------------------------------------------- /dashboard/src/components/shared/wrapper/SummaryCard.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 17 | 18 | 26 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/AccountsInfo.vue: -------------------------------------------------------------------------------- 1 | 10 | 26 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/ElectionBanner.vue: -------------------------------------------------------------------------------- 1 | 10 | 24 | 25 | 35 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/TableOverview.vue: -------------------------------------------------------------------------------- 1 | 10 | 56 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/constants.ts: -------------------------------------------------------------------------------- 1 | 2 | // Copyright 2017-2020 @polkadot/react-components authors & contributors 3 | // This software may be modified and distributed under the terms 4 | // of the Apache-2.0 license. See the LICENSE file for details. 5 | 6 | export const rewardDestinationOptions = [ 7 | { text: 'Stash account (increase the amount at stake)', value: 0 }, 8 | { text: 'Stash account (do not increase the amount at stake)', value: 1 }, 9 | { text: 'Controller account', value: 2 } 10 | ]; 11 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/partial/BondExtra.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 70 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/partial/NominateInput.vue: -------------------------------------------------------------------------------- 1 | 12 | 31 | 32 | 39 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Actions/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2020 @polkadot/app-staking authors & contributors 2 | // This software may be modified and distributed under the terms 3 | // of the Apache-2.0 license. See the LICENSE file for details. 4 | 5 | import { AccountId, Balance, UnappliedSlashOther, Exposure, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces'; 6 | 7 | import BN from 'bn.js'; 8 | 9 | export interface AmountValidateState { 10 | error: string | null; 11 | warning: string | null; 12 | } 13 | 14 | interface Unapplied { 15 | others: UnappliedSlashOther[]; 16 | own: Balance; 17 | payout: Balance; 18 | reporters: AccountId[]; 19 | validator: AccountId; 20 | } 21 | 22 | export interface Slash { 23 | era: BN; 24 | slashes: Unapplied[]; 25 | } 26 | 27 | export interface StakerState { 28 | controllerId: string | null; 29 | destination?: string; 30 | destinationId: number; 31 | exposure?: Exposure; 32 | hexSessionIdNext: string | null; 33 | hexSessionIdQueue: string | null; 34 | isLoading: boolean; 35 | isOwnController: boolean; 36 | isOwnStash: boolean; 37 | isStashNominating: boolean; 38 | isStashValidating: boolean; 39 | nominating?: string[]; 40 | sessionIds: string[]; 41 | stakingLedger?: StakingLedger; 42 | stashId: string; 43 | validatorPrefs?: ValidatorPrefs; 44 | } 45 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Nominators.vue: -------------------------------------------------------------------------------- 1 | 9 | 22 | 23 | 33 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/PayoutBanner.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 27 | 28 | 38 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/StashRow.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 64 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/TableOverview.vue: -------------------------------------------------------------------------------- 1 | 10 | 50 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/ValidatorRow.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 68 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/ValidatorWarningMessage.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Payouts/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2020 @polkadot/app-staking authors & contributors 2 | // This software may be modified and distributed under the terms 3 | // of the Apache-2.0 license. See the LICENSE file for details. 4 | 5 | import { DeriveStakerReward } from '@polkadot/api-derive/types'; 6 | import { Balance, EraIndex } from '@polkadot/types/interfaces'; 7 | 8 | import BN from 'bn.js'; 9 | 10 | export interface PayoutEraValidator { 11 | era: EraIndex; 12 | stashes: Record; 13 | } 14 | 15 | export interface PayoutValidator { 16 | available: BN; 17 | eras: PayoutEraValidator[]; 18 | validatorId: string; 19 | } 20 | 21 | export interface PayoutStash { 22 | available: BN; 23 | rewards: DeriveStakerReward[]; 24 | stashId: string; 25 | } 26 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/StakerInfo.vue: -------------------------------------------------------------------------------- 1 | 10 | 26 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/TableOverview.vue: -------------------------------------------------------------------------------- 1 | 10 | 59 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Targets/Summary.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 66 | 67 | 78 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Targets/TableOverview.vue: -------------------------------------------------------------------------------- 1 | 10 | 54 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Targets/ValidatorRow.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 69 | 70 | 71 | 76 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Targets/registry.ts: -------------------------------------------------------------------------------- 1 | import { TypeRegistry } from '@polkadot/types'; 2 | 3 | const registry = new TypeRegistry(); 4 | 5 | export default registry; 6 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Waiting/TableOverview.vue: -------------------------------------------------------------------------------- 1 | 10 | 56 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/Waiting/Waiting.vue: -------------------------------------------------------------------------------- 1 | 9 | 49 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/getEraPoints.ts: -------------------------------------------------------------------------------- 1 | import Connector from '@vue-polkadot/vue-api' 2 | import { BTreeMap } from '@polkadot/types' 3 | import AccountId from '@polkadot/types/generic/AccountId' 4 | import { RewardPoint } from '@polkadot/types/interfaces' 5 | 6 | export const getEraPoints = async (): Promise> => { 7 | const { api } = Connector.getInstance() 8 | const response = await api.derive.staking?.currentPoints() 9 | 10 | if (!response.individual) { 11 | return {} 12 | } 13 | 14 | return mapEraPoint(response.individual) 15 | } 16 | 17 | export const mapEraPoint = (eraPoints: BTreeMap): Record => { 18 | const result: Record = {}; 19 | 20 | eraPoints.forEach((value, key) => { 21 | result[key.toString()] = value.toString() 22 | }) 23 | 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2020 @polkadot/app-staking authors & contributors 2 | // This software may be modified and distributed under the terms 3 | // of the Apache-2.0 license. See the LICENSE file for details. 4 | 5 | import { AccountId, Balance, BlockNumber, Hash, SessionIndex } from '@polkadot/types/interfaces'; 6 | 7 | import BN from 'bn.js'; 8 | 9 | export type Nominators = Record; 10 | 11 | export type AccountFilter = 'all' | 'controller' | 'session' | 'stash' | 'unbonded'; 12 | 13 | export type ValidatorFilter = 'all' | 'hasNominators' | 'noNominators' | 'hasWarnings' | 'noWarnings' | 'iNominated' | 'nextSet'; 14 | 15 | export interface Slash { 16 | accountId: AccountId; 17 | amount: Balance; 18 | } 19 | 20 | export interface SessionRewards { 21 | blockHash: Hash; 22 | blockNumber: BlockNumber; 23 | isEventsEmpty: boolean; 24 | parentHash: Hash; 25 | reward: Balance; 26 | sessionIndex: SessionIndex; 27 | slashes: Slash[]; 28 | treasury: Balance; 29 | } 30 | 31 | interface ValidatorInfoRank { 32 | rankBondOther: number; 33 | rankBondOwn: number; 34 | rankBondTotal: number; 35 | rankComm: number; 36 | rankNumNominators: number; 37 | rankOverall: number; 38 | rankPayment: number; 39 | rankReward: number; 40 | } 41 | 42 | export interface ValidatorInfo extends ValidatorInfoRank { 43 | accountId: AccountId; 44 | bondOther: BN; 45 | bondOwn: Balance; 46 | bondShare: number; 47 | bondTotal: Balance; 48 | commissionPer: number; 49 | hasIdentity: boolean; 50 | isCommission: boolean; 51 | isElected: boolean; 52 | isFavorite: boolean; 53 | isNominating: boolean; 54 | key: string; 55 | numNominators: number; 56 | rewardPayout: BN; 57 | rewardSplit: BN; 58 | validatorPayment: BN; 59 | } 60 | 61 | export type TargetSortBy = keyof ValidatorInfoRank; 62 | 63 | export interface SortedTargets { 64 | calcWith?: BN; 65 | lastReward?: BN; 66 | nominators?: string[]; 67 | setCalcWith: (amount?: BN) => void; 68 | totalStaked?: BN; 69 | validators?: ValidatorInfo[]; 70 | validatorIds?: string[]; 71 | } 72 | -------------------------------------------------------------------------------- /dashboard/src/components/staking/utils.ts: -------------------------------------------------------------------------------- 1 | import BN from 'bn.js'; 2 | import { Balance } from '@polkadot/types/interfaces'; 3 | import { DeriveStakingQuery } from '@polkadot/api-derive/types'; 4 | import { BN_ZERO, formatBalance } from '@polkadot/util'; 5 | 6 | export interface StakingState { 7 | commission?: string; 8 | nominators: [string, Balance][]; 9 | stakeTotal?: BN; 10 | stakeOther?: BN; 11 | stakeOwn?: BN; 12 | } 13 | 14 | const PERBILL_PERCENT = 10_000_000; 15 | 16 | export function expandInfo ({ exposure, validatorPrefs }: DeriveStakingQuery): StakingState { 17 | let nominators: [string, Balance][] = []; 18 | let stakeTotal: BN | undefined; 19 | let stakeOther: BN | undefined; 20 | let stakeOwn: BN | undefined; 21 | 22 | if (exposure) { 23 | nominators = exposure.others.map(({ value, who }): [string, Balance] => [who.toString(), value.unwrap()]); 24 | stakeTotal = exposure.total.unwrap(); 25 | stakeOwn = exposure.own.unwrap(); 26 | stakeOther = stakeTotal.sub(stakeOwn); 27 | } 28 | 29 | let commission: BN = BN_ZERO 30 | 31 | if (validatorPrefs && validatorPrefs.commission) { 32 | commission = validatorPrefs.commission.unwrap(); 33 | } 34 | 35 | return { 36 | commission: commission 37 | ? `${(commission.toNumber() / PERBILL_PERCENT).toFixed(2)}%` 38 | : undefined, 39 | nominators, 40 | stakeOther, 41 | stakeOwn, 42 | stakeTotal 43 | }; 44 | } 45 | 46 | export function baseBalance (): BN { 47 | return new BN('1'.padEnd(formatBalance.getDefaults().decimals + 4, '0')); 48 | } 49 | -------------------------------------------------------------------------------- /dashboard/src/components/storage/Queries.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | -------------------------------------------------------------------------------- /dashboard/src/components/storage/Query.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | -------------------------------------------------------------------------------- /dashboard/src/components/storage/extractParams.ts: -------------------------------------------------------------------------------- 1 | import { StorageEntryBase } from '@polkadot/api/types'; 2 | import { getTypeDef } from '@polkadot/types'; 3 | import { TypeDef } from '@polkadot/types/types'; 4 | 5 | 6 | export type StorageEntryPromise = StorageEntryBase<'promise', any>; 7 | type Type = { type: TypeDef } 8 | 9 | const extractStorageParams = (key: StorageEntryPromise): Type[] => { 10 | const { creator: { meta: { type }, section } } = key; 11 | 12 | if (type.isDoubleMap) { 13 | return [ 14 | { type: getTypeDef(type.asDoubleMap.key1.toString()) }, 15 | { type: getTypeDef(type.asDoubleMap.key2.toString()) } 16 | ] 17 | } 18 | 19 | if (type.isMap) { 20 | return [{ 21 | type: getTypeDef( 22 | type.asMap.linked.isTrue 23 | ? `Option<${type.asMap.key.toString()}>` 24 | : type.asMap.key.toString() 25 | ) 26 | }] 27 | } 28 | 29 | return [] 30 | } 31 | 32 | export default extractStorageParams 33 | -------------------------------------------------------------------------------- /dashboard/src/components/storage/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2020 @polkadot/app-storage authors & contributors 2 | // This software may be modified and distributed under the terms 3 | // of the Apache-2.0 license. See the LICENSE file for details. 4 | 5 | import { StorageEntryBase } from '@polkadot/api/types'; 6 | 7 | export type StorageEntryPromise = StorageEntryBase<'promise', any>; 8 | 9 | interface Base { 10 | isConst: boolean; 11 | } 12 | 13 | interface IdQuery extends Base { 14 | id: number; 15 | } 16 | 17 | export interface PartialModuleQuery extends Base { 18 | key: StorageEntryPromise; 19 | params: any; 20 | } 21 | 22 | export type StorageModuleQuery = PartialModuleQuery & IdQuery; 23 | 24 | export interface PartialRawQuery extends Base { 25 | key: Uint8Array; 26 | } 27 | 28 | export type StorageRawQuery = PartialRawQuery & IdQuery; 29 | 30 | export interface PartialConstQuery extends Base { 31 | key: any; 32 | } 33 | 34 | export type ConstQuery = PartialConstQuery & IdQuery; 35 | 36 | export type QueryTypes = StorageModuleQuery | StorageRawQuery | ConstQuery; 37 | 38 | export type ParitalQueryTypes = PartialModuleQuery | PartialRawQuery | PartialConstQuery; 39 | 40 | -------------------------------------------------------------------------------- /dashboard/src/components/toolbox/ConvertAddress.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 66 | 67 | 72 | -------------------------------------------------------------------------------- /dashboard/src/components/toolbox/HashData.vue: -------------------------------------------------------------------------------- 1 | 20 | 56 | -------------------------------------------------------------------------------- /dashboard/src/components/toolbox/Toolbox.vue: -------------------------------------------------------------------------------- 1 | 19 | 61 | -------------------------------------------------------------------------------- /dashboard/src/components/treasury/Proposal.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 51 | 52 | 66 | -------------------------------------------------------------------------------- /dashboard/src/components/treasury/Proposals.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 23 | -------------------------------------------------------------------------------- /dashboard/src/components/treasury/Tips.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 46 | 47 | -------------------------------------------------------------------------------- /dashboard/src/components/treasury/Treasury.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 71 | 72 | 77 | 78 | -------------------------------------------------------------------------------- /dashboard/src/components/treasury/TreasuryWrapper.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 26 | -------------------------------------------------------------------------------- /dashboard/src/icons.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | import { 4 | faTrash, faKey, faSync, faRedo, 5 | faCloudDownloadAlt, faPlay, faFolderOpen, 6 | faUsers, faAddressBook, faPaperPlane, 7 | faCalendarCheck, faCogs, faEye, faEyeSlash, 8 | faExclamationCircle, faUpload, faCopy, faAngleDoubleLeft, 9 | faAngleDoubleRight, faPlus, faTimes, faCaretDown, 10 | faCaretUp, faMinus, faFile, faBook, 11 | faCodeBranch, faSearch, faQuestionCircle, faExternalLinkAlt, 12 | faArrowUp, faTools, faCheck, faSeedling, faDatabase, faGem, 13 | faInfoCircle, faExchangeAlt, faBug, faStop, faEllipsisV, faPercent, 14 | faUsersCog, faCoins, faAngleLeft, faAngleRight, 15 | faCreditCard, faStepForward 16 | } from '@fortawesome/free-solid-svg-icons'; 17 | 18 | import { faTwitter } from '@fortawesome/free-brands-svg-icons'; 19 | 20 | import { library } from '@fortawesome/fontawesome-svg-core'; 21 | 22 | library.add(faTrash, faKey, faSync, faRedo, 23 | faCloudDownloadAlt, faPlay, faFolderOpen, 24 | faUsers, faAddressBook, faPaperPlane, 25 | faCalendarCheck, faCogs, faEye, faEyeSlash, 26 | faExclamationCircle, faUpload, faCopy, faAngleDoubleLeft, 27 | faAngleDoubleRight, faPlus, faTimes, faCaretDown, 28 | faCaretUp, faMinus, faFile, faBook, 29 | faCodeBranch, faSearch, faQuestionCircle, faExternalLinkAlt, 30 | faTwitter, faArrowUp, faTools, faCheck, faSeedling, 31 | faDatabase, faGem, faInfoCircle, faExchangeAlt, 32 | faBug, faStop, faEllipsisV, faPercent, faUsersCog, faCoins, 33 | faAngleLeft, faAngleRight, faCreditCard, faStepForward 34 | ); 35 | 36 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; 37 | Vue.component('vue-fontawesome', FontAwesomeIcon); 38 | -------------------------------------------------------------------------------- /dashboard/src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Buefy from 'buefy'; 3 | import 'buefy/dist/buefy.css'; 4 | import './icons'; 5 | 6 | import shortAddress from './utils/shortAddress'; 7 | import VueClipboard from 'vue-clipboard2'; 8 | import formatBalance from '@/utils/formatBalance' 9 | import { toString, toNumber, toPercent } from '@/utils/filters' 10 | import keyring from '@polkadot/ui-keyring'; 11 | import './registerServiceWorker' 12 | import App from './App.vue'; 13 | import store from './store'; 14 | import router from './router'; 15 | import Connector from '@vue-polkadot/vue-api'; 16 | import 'setimmediate'; 17 | 18 | Vue.filter('shortAddress', shortAddress); 19 | 20 | (window as any).C = Connector; 21 | (window as any).K = keyring; 22 | // Connector.createInstance(store.state.setting.apiUrl); 23 | Vue.prototype.$http = Connector.getInstance(); 24 | 25 | 26 | Vue.use(Buefy, { 27 | defaultIconPack: 'fas', 28 | defaultIconComponent: 'vue-fontawesome', 29 | defaultFieldLabelPosition: 'inside', 30 | customIconPacks: { 31 | fas: { 32 | sizes: { 33 | 'default': '', 34 | 'is-small': '1x', 35 | 'is-medium': '2x', 36 | 'is-large': '3x', 37 | }, 38 | }, 39 | }, 40 | }); 41 | 42 | Vue.filter('formatBalance', formatBalance) 43 | Vue.filter('toString', toString) 44 | Vue.filter('toNumber', toNumber) 45 | Vue.filter('toPercent', toPercent) 46 | 47 | Vue.use(VueClipboard); 48 | 49 | Vue.config.productionTip = false; 50 | 51 | new Vue({ 52 | router, 53 | store, 54 | render: (h) => h(App), 55 | }).$mount('#app'); 56 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Account.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 38 | 39 | 50 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Amount.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 43 | 44 | 55 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Bool.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 48 | 49 | 60 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Bytes.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 58 | 59 | 74 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Call.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Code.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Data.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/DispatchError.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Enum.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 46 | 47 | 58 | -------------------------------------------------------------------------------- /dashboard/src/params/components/FileUpload.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 38 | 39 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Hash256.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | 46 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Hash512.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | 46 | -------------------------------------------------------------------------------- /dashboard/src/params/components/KeyValue.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/KeyValueArray.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Moment.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 34 | 35 | 46 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Null.vue: -------------------------------------------------------------------------------- 1 | 3 | 4 | 11 | -------------------------------------------------------------------------------- /dashboard/src/params/components/OpaqueCall.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Option.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 36 | 37 | 44 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Proposal.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Raw.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | 33 | 52 | -------------------------------------------------------------------------------- /dashboard/src/params/components/TextField.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 34 | 35 | 46 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Unknown.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 32 | 33 | 45 | -------------------------------------------------------------------------------- /dashboard/src/params/components/Vote.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 44 | -------------------------------------------------------------------------------- /dashboard/src/params/components/VoteThreshold.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 45 | 46 | 57 | -------------------------------------------------------------------------------- /dashboard/src/params/components/generator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file="./imports" 3 | while IFS=: read -r f1 4 | do 5 | touch "$f1".vue 6 | cat script.txt | sed s/Basic/"$f1"/g >> "$f1".vue 7 | printf 'Name: %s \n' "$f1".vue 8 | done <"$file" 9 | -------------------------------------------------------------------------------- /dashboard/src/params/components/imports: -------------------------------------------------------------------------------- 1 | Account 2 | Amount 3 | Balance 4 | Bool 5 | Bytes 6 | Code 7 | Data 8 | Enum 9 | Hash256 10 | Hash512 11 | Moment 12 | Proposal 13 | KeyValue 14 | KeyValueArray 15 | Null 16 | Option 17 | Struct 18 | Text 19 | Tuple 20 | Unknown 21 | Vector 22 | Vote 23 | VoteThreshold 24 | -------------------------------------------------------------------------------- /dashboard/src/params/components/newImports: -------------------------------------------------------------------------------- 1 | Call 2 | DispatchError 3 | OpaqueCall 4 | Raw 5 | -------------------------------------------------------------------------------- /dashboard/src/params/components/script.txt: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /dashboard/src/params/components/typeRegistry.ts: -------------------------------------------------------------------------------- 1 | import { TypeRegistry } from '@polkadot/types'; 2 | 3 | const registry = new TypeRegistry(); 4 | 5 | export default registry; 6 | -------------------------------------------------------------------------------- /dashboard/src/params/constants.ts: -------------------------------------------------------------------------------- 1 | import { Unit } from './types'; 2 | 3 | // TODO: use this in cleanup 4 | export const units: Unit[] = [ 5 | {name: 'femto', value: 1e-15}, {name: 'pico', value: 1e-12}, {name: 'nano', value: 1e-9}, 6 | {name: 'micro', value: 1e-6}, {name: 'mili', value: 1e-3}, {name: 'DOT', value: 1}, 7 | {name: 'Kilo', value: 1e3}, {name: 'Mega', value: 1e6}, {name: 'Giga', value: 1e9}, 8 | {name: 'Tera', value: 1e12}, {name: 'Peta', value: 1e15}, {name: 'Exa', value: 1e18}, 9 | {name: 'Zeta', value: 1e21}, {name: 'Yotta', value: 1e24}, 10 | ]; 11 | -------------------------------------------------------------------------------- /dashboard/src/params/types.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2017-2019 @polkadot/react-components authors & contributors 2 | // This software may be modified and distributed under the terms 3 | // of the Apache-2.0 license. See the LICENSE file for details. 4 | 5 | import { TypeDef } from '@polkadot/types/types'; 6 | // import { BareProps } from '@polkadot/react-components/types'; 7 | 8 | // FIXME Ideally, we want these as Base from api-codec - as a stop-gap, any this until we have 9 | // params returning types extending Base (i.e. anything from api-codec) 10 | export type RawParamValue = any | undefined; 11 | 12 | export type RawParamValueArray = (RawParamValue | RawParamValue[])[]; 13 | 14 | export type RawParamValues = RawParamValue | RawParamValueArray; 15 | 16 | export interface RawParam { 17 | isValid: boolean; 18 | value: RawParamValues; 19 | } 20 | 21 | export interface RawParamOnChangeValue { 22 | isValid: boolean; 23 | value: RawParamValues; 24 | } 25 | export type RawParamOnChange = (value: RawParamOnChangeValue) => void; 26 | export type RawParamOnEnter = () => void; 27 | 28 | export type RawParams = RawParam[]; 29 | 30 | // export interface BaseProps extends BareProps { 31 | // defaultValue: RawParam; 32 | // name?: string; 33 | // onChange?: RawParamOnChange; 34 | // onEnter?: RawParamOnEnter; 35 | // type: TypeDef; 36 | // } 37 | 38 | // export interface Props extends BaseProps { 39 | // isDisabled?: boolean; 40 | // isError?: boolean; 41 | // isReadOnly?: boolean; 42 | // label?: React.ReactNode; 43 | // withLabel?: boolean; 44 | // } 45 | 46 | export type Size = 'full' | 'large' | 'medium' | 'small'; 47 | 48 | export type ComponentMap = Record; 49 | 50 | export interface Unit { 51 | name: string; 52 | value: number; 53 | } 54 | 55 | export interface ParamDef { 56 | name?: string; 57 | type: TypeDef; 58 | } 59 | -------------------------------------------------------------------------------- /dashboard/src/registerServiceWorker.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from 'register-service-worker'; 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready() { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ); 12 | }, 13 | cached() { 14 | console.log('Content has been cached for offline use.'); 15 | }, 16 | updated() { 17 | console.log('New content is available; please refresh.'); 18 | }, 19 | offline() { 20 | console.log( 21 | 'No internet connection found. App is running in offline mode.' 22 | ); 23 | }, 24 | error(error) { 25 | console.error('Error during service worker registration:', error); 26 | } 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /dashboard/src/routeGuard.ts: -------------------------------------------------------------------------------- 1 | import Connector from '@vue-polkadot/vue-api'; 2 | import { NotificationProgrammatic as Notification } from 'buefy'; 3 | import Router from 'vue-router'; 4 | 5 | export const apiEnabled = (to: any, from: any, next: any) => { 6 | if (Connector.getInstance().api) { 7 | next(); 8 | } else { 9 | next({ name: 'landing' }) 10 | Notification.open({ 11 | duration: 7000, 12 | message: `API is not connected yet.
Please try later.`, 13 | queue: false, 14 | type: 'is-danger', 15 | position: 'is-top-right', 16 | }); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /dashboard/src/router/explorer.ts: -------------------------------------------------------------------------------- 1 | import { apiEnabled } from '@/routeGuard'; 2 | 3 | const Explorer = () => import(/* webpackChunkName:'explorer' */ '@/components/explorer/Explorer.vue'); 4 | const ExplorerDetails = () => import(/* webpackChunkName:'explorer' */ '@/components/explorer/NodeDetails.vue'); 5 | 6 | export default [ 7 | { 8 | path: '/explorer', 9 | name: 'explorer', 10 | component: Explorer, 11 | beforeEnter: apiEnabled, 12 | }, 13 | { 14 | path: '/explorer/:tab', 15 | name: 'explorerByTab', 16 | component: Explorer, 17 | beforeEnter: apiEnabled, 18 | }, 19 | { 20 | path: '/explorer/:tab/:hash', 21 | name: 'explorerByTabHash', 22 | component: Explorer, 23 | beforeEnter: apiEnabled, 24 | }, 25 | { 26 | path: '/explorer/peers', 27 | name: 'explorerPeers', 28 | component: ExplorerDetails, 29 | beforeEnter: apiEnabled, 30 | }, 31 | ] 32 | -------------------------------------------------------------------------------- /dashboard/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | Vue.use(Router); 4 | import { apiEnabled } from '@/routeGuard'; 5 | 6 | import Accounts from '@/router/accounts'; 7 | import Transfer from '@/router/transfer'; 8 | import Explorer from '@/router/explorer'; 9 | // import Staking from '@/router/staking'; 10 | import Toolbox from '@/router/toolbox'; 11 | 12 | const Landing = () => import('@/components/landing/Landing.vue'); 13 | const Democracy = () => import('@/components/democracy/DemocracyWrapper.vue'); 14 | const Settings = () => import('@/views/Settings.vue'); 15 | // const Toolbox = () => import('@/components/toolbox/Toolbox.vue'); 16 | const Chainstate = () => import('@/views/ChainState.vue'); 17 | const Extrinsics = () => import('@/views/Extrinsics.vue'); 18 | const Treasury = () => import('@/components/treasury/TreasuryWrapper.vue') 19 | const FourZeroFour = () => import('@/components/FourZeroFour.vue') 20 | const RPC = () => import('@/components/rpc/RPC.vue'); 21 | const Staking = () => import('@/views/Staking.vue'); 22 | 23 | export default new Router({ 24 | routes: [ 25 | { 26 | path: '/', 27 | name: 'landing', 28 | component: Landing, 29 | }, 30 | 31 | ...Accounts, 32 | ...Transfer, 33 | ...Explorer, 34 | // ...Staking, 35 | ...Toolbox, 36 | { 37 | path: '/democracy', 38 | name: 'democracy', 39 | component: Democracy, 40 | beforeEnter: apiEnabled, 41 | }, 42 | { 43 | path: '/settings', 44 | name: 'settings', 45 | component: Settings 46 | }, 47 | { 48 | path: '/rpc', 49 | name: 'rpc', 50 | component: RPC, 51 | beforeEnter: apiEnabled, 52 | }, 53 | { 54 | path: '/chainstate', 55 | name: 'chainstate', 56 | component: Chainstate 57 | }, 58 | { 59 | path: '/extrinsics', 60 | name: 'extrinsics', 61 | component: Extrinsics, 62 | beforeEnter: apiEnabled, 63 | }, 64 | { 65 | path: '/staking', 66 | name: 'staking', 67 | component: Staking 68 | }, 69 | { 70 | path: '/treasury', 71 | name: 'treasury', 72 | component: Treasury 73 | }, 74 | { 75 | path: '*', 76 | name: 'FourZeroFour', 77 | component: FourZeroFour, 78 | }, 79 | ], 80 | }); 81 | -------------------------------------------------------------------------------- /dashboard/src/router/staking.ts: -------------------------------------------------------------------------------- 1 | import { apiEnabled } from '@/routeGuard'; 2 | 3 | const Staking = () => import(/* webpackChunkName:'explorer' */ '@/views/Staking.vue'); 4 | const Overview = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Overview.vue'); 5 | const Targets = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Targets/Targets.vue'); 6 | const Waiting = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Waiting/Waiting.vue'); 7 | const Actions = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Actions/Actions.vue'); 8 | const Payouts = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Payouts/Payouts.vue'); 9 | 10 | export default [ 11 | { 12 | path: '/staking/0', 13 | component: Staking, 14 | beforeEnter: apiEnabled, 15 | children: [ 16 | { 17 | path: '', 18 | name: 'overview', 19 | component: Overview, 20 | }, 21 | ] 22 | }, 23 | { 24 | path: '/staking/1', 25 | component: Staking, 26 | beforeEnter: apiEnabled, 27 | children: [ 28 | { 29 | path: '', 30 | name: 'actions', 31 | component: Actions 32 | }, 33 | ] 34 | }, 35 | { 36 | path: '/staking/2', 37 | component: Staking, 38 | beforeEnter: apiEnabled, 39 | children: [ 40 | { 41 | path: '', 42 | name: 'targets', 43 | component: Targets 44 | } 45 | ] 46 | }, 47 | { 48 | path: '/staking/3', 49 | component: Staking, 50 | beforeEnter: apiEnabled, 51 | children: [ 52 | { 53 | path: '', 54 | name: 'waiting', 55 | component: Waiting 56 | } 57 | ] 58 | }, 59 | { 60 | path: '/staking/4', 61 | component: Staking, 62 | beforeEnter: apiEnabled, 63 | children: [ 64 | { 65 | path: '', 66 | name: 'payouts', 67 | component: Payouts 68 | } 69 | ] 70 | } 71 | ] 72 | -------------------------------------------------------------------------------- /dashboard/src/router/staking2.ts: -------------------------------------------------------------------------------- 1 | import { apiEnabled } from '@/routeGuard'; 2 | 3 | const Staking = () => import(/* webpackChunkName:'explorer' */ '@/views/Staking.vue'); 4 | const Overview = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Overview.vue'); 5 | const Targets = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Targets/Targets.vue'); 6 | const Waiting = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Waiting/Waiting.vue'); 7 | const Actions = () => import(/* webpackChunkName:'explorer' */ '@/components/staking/Actions/Actions.vue'); 8 | 9 | export default [ 10 | { 11 | path: '/staking/:tab', 12 | name: 'staking', 13 | component: Staking, 14 | children: [ 15 | { 16 | path: '', 17 | name: 'overview', 18 | component: Overview, 19 | }, 20 | ] 21 | }, 22 | { 23 | path: '/staking/1', 24 | name: 'staking', 25 | component: Staking, 26 | children: [ 27 | { 28 | path: '', 29 | name: 'actions', 30 | compoentn: Actions 31 | }, 32 | ] 33 | }, 34 | { 35 | path: '/staking/2', 36 | name: 'staking', 37 | component: Staking, 38 | children: [ 39 | { 40 | path: '', 41 | name: 'targets', 42 | component: Targets 43 | } 44 | ] 45 | }, 46 | { 47 | path: '/staking/3', 48 | name: 'staking', 49 | component: Staking, 50 | children: [ 51 | { 52 | path: '', 53 | name: 'waiting', 54 | component: Waiting 55 | } 56 | ] 57 | } 58 | ] 59 | -------------------------------------------------------------------------------- /dashboard/src/router/toolbox.ts: -------------------------------------------------------------------------------- 1 | const Toolbox = () => 2 | import(/* webpackChunkName:'toolbox' */ '@/components/toolbox/Toolbox.vue'); 3 | 4 | export default [ 5 | { 6 | path: '/toolbox', 7 | name: 'toolbox', 8 | component: Toolbox 9 | // beforeEnter: apiEnabled, 10 | }, 11 | { 12 | path: '/toolbox/:tab/:data', 13 | name: 'toolboxHash', 14 | component: Toolbox, 15 | } 16 | ]; 17 | -------------------------------------------------------------------------------- /dashboard/src/router/transfer.ts: -------------------------------------------------------------------------------- 1 | import { apiEnabled } from '@/routeGuard'; 2 | 3 | const Transfer = () => import(/* webpackChunkName:'transfer' */ '@/components/transfer/Transfer.vue'); 4 | 5 | export default [ 6 | { 7 | path: '/transfer', 8 | name: 'transfer', 9 | component: Transfer, 10 | // beforeEnter: apiEnabled, 11 | }, 12 | { 13 | path: '/transfer/f/:from/t/:to/a/:amount/:asset', 14 | name: 'transferSignSubmit', 15 | component: Transfer, 16 | beforeEnter: apiEnabled, 17 | }, 18 | { 19 | path: '/transfer/from/:from', 20 | name: 'transferFrom', 21 | component: Transfer, 22 | beforeEnter: apiEnabled, 23 | }, 24 | { 25 | path: '/transfer/to/:to', 26 | name: 'transferTo', 27 | component: Transfer, 28 | beforeEnter: apiEnabled, 29 | }, 30 | ] -------------------------------------------------------------------------------- /dashboard/src/shims-tsx.d.ts: -------------------------------------------------------------------------------- 1 | import Vue, { VNode } from 'vue'; 2 | 3 | declare global { 4 | namespace JSX { 5 | // tslint:disable no-empty-interface 6 | interface Element extends VNode {} 7 | // tslint:disable no-empty-interface 8 | interface ElementClass extends Vue {} 9 | interface IntrinsicElements { 10 | [elem: string]: any; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /dashboard/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue'; 3 | export default Vue; 4 | } 5 | -------------------------------------------------------------------------------- /dashboard/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface KeyringPair$Meta { 2 | [index: string]: any; 3 | } 4 | 5 | export interface KeyringAccount { 6 | address: string; 7 | meta: KeyringPair$Meta; 8 | publicKey: string; 9 | type: string; 10 | } 11 | -------------------------------------------------------------------------------- /dashboard/src/utils/WithKeyring.ts: -------------------------------------------------------------------------------- 1 | import { Component, Vue } from 'vue-property-decorator'; 2 | import keyring from '@polkadot/ui-keyring'; 3 | import { cryptoWaitReady } from '@polkadot/util-crypto'; 4 | import { KeyringPair } from '@polkadot/keyring/types'; 5 | import { u8aToHex } from '@polkadot/util'; 6 | 7 | @Component 8 | export default class WithKeyring extends Vue { 9 | protected keyringLoaded: boolean = false; 10 | protected keyringAccounts: KeyringPair[] = []; 11 | protected keys: any = ''; 12 | 13 | public async mountWasmCrypto(): Promise { 14 | await cryptoWaitReady(); 15 | // console.log('wasmCrypto loadedX'); 16 | this.loadKeyring(); 17 | // console.log('keyring initX'); 18 | } 19 | 20 | public loadKeyring(): void { 21 | this.keyringLoaded = true; 22 | this.keys = keyring; 23 | this.mapAccounts(); 24 | } 25 | 26 | public mapAccounts(): void { 27 | this.keyringAccounts = keyring.getPairs(); 28 | } 29 | 30 | public mounted(): void { 31 | this.mountWasmCrypto(); 32 | 33 | } 34 | 35 | public getPair(address: string): KeyringPair { 36 | return keyring.getPair(address); 37 | } 38 | 39 | public vueU8aToHex(publicKey: Uint8Array): string { 40 | return u8aToHex(publicKey); 41 | } 42 | 43 | 44 | } 45 | -------------------------------------------------------------------------------- /dashboard/src/utils/chainProperties.ts: -------------------------------------------------------------------------------- 1 | const shortAddress = (address: string): string => { 2 | if (address) { 3 | return `${address.slice(0, 6)}...${address.slice(-6)}`; 4 | } 5 | return ''; 6 | }; 7 | 8 | export default shortAddress; 9 | -------------------------------------------------------------------------------- /dashboard/src/utils/empty.ts: -------------------------------------------------------------------------------- 1 | export function emptyObject(): T { 2 | return ({} as T); 3 | } 4 | 5 | 6 | export function emptyArray(): T[] { 7 | return ([] as T[]); 8 | } 9 | -------------------------------------------------------------------------------- /dashboard/src/utils/explorerGuide.ts: -------------------------------------------------------------------------------- 1 | 2 | const urlBuilderBlockNumber = (value: string, chain: string, provider: string): any => { 3 | if (provider === 'subscan') { 4 | return `https://${chain}.${provider}.io/block/${value}` 5 | } 6 | 7 | if (provider === 'polkascan') { 8 | return `https://${provider}.io/pre/${chain}/block/${value}` 9 | } 10 | } 11 | 12 | const urlBuilderAccount = (value: string, chain: string, provider: string): any => { 13 | if (provider === 'subscan') { 14 | return `https://${chain}.${provider}.io/account/${value}` 15 | } 16 | 17 | if (provider === 'polkascan') { 18 | return `https://${provider}.io/pre/${chain}/account/${value}` 19 | } 20 | } 21 | 22 | const urlBuilderTransaction = (value: string, chain: string, provider: string): any => { 23 | if (provider === 'subscan') { 24 | return `https://${chain}.${provider}.io/extrinsic/${value}` 25 | } 26 | 27 | if (provider === 'polkascan') { 28 | return `https://${provider}.io/pre/${chain}/transaction/${value}` 29 | } 30 | } 31 | 32 | export { urlBuilderAccount, urlBuilderBlockNumber, urlBuilderTransaction } 33 | -------------------------------------------------------------------------------- /dashboard/src/utils/filters.ts: -------------------------------------------------------------------------------- 1 | import BN from 'bn.js'; 2 | import { isNumber } from '@polkadot/util'; 3 | const EMPTY = '0.00 %'; 4 | 5 | export const toNumber = (value: BN | number): number => BN.isBN(value) ? Number(value.toString()) : value || 0; 6 | 7 | export const toString = (value: any) => (value && value.toString()) || ''; 8 | 9 | export const toPercent = (value: number | undefined | BN): string => { 10 | if (!value) { 11 | return EMPTY; 12 | } 13 | 14 | if (isNumber(value)) { 15 | return Number.isInteger(value) ? `${value}.00 %` : `${value} %`; 16 | } 17 | 18 | if (BN.isBN(value)) { 19 | return `${value.toString()} %`; 20 | } 21 | 22 | return EMPTY; 23 | } 24 | -------------------------------------------------------------------------------- /dashboard/src/utils/formatBalance.ts: -------------------------------------------------------------------------------- 1 | import BN from 'bn.js'; 2 | import { formatBalance } from '@polkadot/util'; 3 | import { Compact } from '@polkadot/types'; 4 | import { Balance } from '@polkadot/types/interfaces'; 5 | 6 | const M_LENGTH = 6 + 1; 7 | const K_LENGTH = 3 + 1; 8 | 9 | 10 | function format(balance: number | string | BN | BigInt, decimals: number = 12, withUnit?: boolean | string, withSi?: boolean ) { 11 | return formatBalance(balance, { decimals , withUnit , forceUnit: '-', withSi }) 12 | } 13 | 14 | // Legacy 15 | // const format = (balance: Compact | BN | string, currency: string, withSi?: boolean): string => { 16 | // const value = typeof balance === 'object' ? balance.toString() : balance; 17 | 18 | // const [prefix, postfix] = formatBalance(value, { forceUnit: '-', withSi: false }).split('.'); 19 | // // console.log(`${prefix}.${`000${postfix || ''}`.slice(-3)} ${currency}`); 20 | 21 | // const isShort = withSi && prefix.length >= K_LENGTH; 22 | 23 | // if (prefix.length > M_LENGTH) { 24 | // return `${formatBalance(value.substring(0, value.length-12)).replace('Unit','')} ${currency}`; 25 | // } 26 | 27 | // return `${!isShort && value ? prefix : '0'}.000${''.slice(-3) } ${currency}` 28 | 29 | // } 30 | 31 | export default format 32 | -------------------------------------------------------------------------------- /dashboard/src/utils/isFunction.ts: -------------------------------------------------------------------------------- 1 | const isFunction = (fn: any) => typeof fn === 'function'; 2 | 3 | export default isFunction 4 | -------------------------------------------------------------------------------- /dashboard/src/utils/mixins/extrinsicsMixin.ts: -------------------------------------------------------------------------------- 1 | import { Component, Vue } from 'vue-property-decorator'; 2 | 3 | /* 4 | * refer to https://stackoverflow.com/questions/51873087/unable-to-use-mixins-in-vue-with-typescript 5 | * import { Component, Mixins } from 'vue-property-decorator'; 6 | * class ExtendedClass extends Mixins(ActualMixin) { 7 | */ 8 | @Component 9 | export default class ExtrinsicMixin extends Vue { 10 | private fnSection = ''; 11 | private fnMethod = ''; 12 | private args: any[] = []; 13 | private selectedArguments = {}; 14 | private section = {} 15 | 16 | get sections() { 17 | return Object.keys(this.section).sort(); 18 | } 19 | 20 | protected setSection(section: any) { 21 | this.section = section 22 | } 23 | 24 | get methods() { 25 | return this.fnSection 26 | // @ts-ignore: Method has always value 27 | ? Object.keys(this.section[this.fnSection]).sort() 28 | : []; 29 | } 30 | 31 | get params() { 32 | console.log(this.args) 33 | return this.args 34 | } 35 | 36 | protected handleSectionSelection(value: string) { 37 | this.fnSection = value; 38 | } 39 | 40 | protected handleMethodSelection(value: string) { 41 | this.fnMethod = value; 42 | } 43 | 44 | protected setArgs(args: any) { 45 | this.args = args; 46 | } 47 | 48 | protected handleSelectedArguments(value: any) { 49 | this.selectedArguments = { 50 | ...this.selectedArguments, 51 | ...value, 52 | }; 53 | } 54 | 55 | protected hasArgs(): boolean { 56 | return this.args && this.args.length > 0; 57 | } 58 | 59 | protected getSection(): any { 60 | // @ts-ignore: Method has always value 61 | return this.section[this.fnSection][this.fnMethod] 62 | } 63 | 64 | protected getFnSection(): any { 65 | // @ts-ignore: Method has always value 66 | return this.section[this.fnSection] 67 | } 68 | 69 | protected argMapper(arg: any): any { 70 | const accessor: string = arg.name.toString(); 71 | // @ts-ignore: Method has always value 72 | return this.selectedArguments[accessor]; 73 | } 74 | 75 | protected mapArgs(): any[] { 76 | return this.args.map(this.argMapper); 77 | } 78 | 79 | protected getFnMethodAndSection() { 80 | const { fnMethod, fnSection } = this; 81 | return { fnMethod, fnSection }; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /dashboard/src/utils/mixins/identityMixin.ts: -------------------------------------------------------------------------------- 1 | import { Registration } from '@polkadot/types/interfaces/identity/types'; 2 | import Vue from 'vue'; 3 | 4 | export default class IdentityMixin extends Vue { 5 | public async identityOf(address: string): Promise { 6 | const identity = this.$store.getters.getIdentityFor(address) 7 | 8 | if (identity) { 9 | return Promise.resolve(identity) 10 | } 11 | 12 | return await this.$store.dispatch('fetchIdentity', address) 13 | .then(() => this.$store.getters.getIdentityFor(address)) 14 | .then(id => id || {}) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dashboard/src/utils/mixins/keyringMixin.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import keyring from '@polkadot/ui-keyring'; 3 | import { cryptoWaitReady } from '@polkadot/util-crypto'; 4 | import { KeyringPair } from '@polkadot/keyring/types'; 5 | import { u8aToHex } from '@polkadot/util'; 6 | 7 | export default class KeyringMixin extends Vue { 8 | protected keyringLoaded: boolean = false; 9 | protected keyringAccounts: KeyringPair[] = []; 10 | protected keys: any = ''; 11 | 12 | public async mountWasmCrypto(): Promise { 13 | await cryptoWaitReady(); 14 | // console.log('wasmCrypto loadedX'); 15 | this.loadKeyring(); 16 | // console.log('keyring initX'); 17 | } 18 | 19 | public loadKeyring(): void { 20 | this.keyringLoaded = true; 21 | this.keys = keyring; 22 | this.mapAccounts(); 23 | } 24 | 25 | public mapAccounts(): void { 26 | this.keyringAccounts = keyring.getPairs(); 27 | } 28 | 29 | public mounted(): void { 30 | this.mountWasmCrypto(); 31 | 32 | } 33 | 34 | public getPair(address: string): KeyringPair { 35 | return keyring.getPair(address); 36 | } 37 | 38 | public vueU8aToHex(publicKey: Uint8Array): string { 39 | return u8aToHex(publicKey); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /dashboard/src/utils/mixins/subscribeMixin.ts: -------------------------------------------------------------------------------- 1 | import { Component, Vue } from 'vue-property-decorator'; 2 | // declare type UnsubscribePromise = Promise; 3 | declare type Unsubscribe = () => void; 4 | 5 | /* 6 | * refer to https://stackoverflow.com/questions/51873087/unable-to-use-mixins-in-vue-with-typescript 7 | * usage import Component, { mixins } from 'vue-class-component'; 8 | * class ExtendedClass extends mixins(SubscribeMixin) { 9 | */ 10 | @Component 11 | export default class SubscribeMixin extends Vue { 12 | private subs: Unsubscribe[] = []; 13 | 14 | public async subscribe(fn: any, args: any, callback: any) { 15 | this.subs.push(await fn(...args, callback)) 16 | } 17 | 18 | public beforeDestroy() { 19 | this.subs.forEach((sub) => sub()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/src/utils/notification.ts: -------------------------------------------------------------------------------- 1 | import { NotificationProgrammatic as Notification } from 'buefy'; 2 | 3 | export const notificationTypes: any = { 4 | success: { 5 | type: 'is-success', 6 | actionText: 'OK', 7 | // onAction: () => window.open(this.explorer + this.tx, '_blank'), 8 | }, 9 | info: { 10 | type: 'is-info', 11 | actionText: 'OK', 12 | }, 13 | danger: { 14 | type: 'is-danger', 15 | actionText: 'Oh no!', 16 | }, 17 | }; 18 | 19 | 20 | export const showNotification = (message: string | null, params: any = notificationTypes.info) => { 21 | Notification.open({ 22 | duration: 5000, 23 | message, 24 | type: 'is-success', 25 | position: 'is-top-right', 26 | actionText: 'OK', 27 | queue: false, 28 | ...params, 29 | }); 30 | }; 31 | 32 | -------------------------------------------------------------------------------- /dashboard/src/utils/shortAddress.ts: -------------------------------------------------------------------------------- 1 | const shortAddress = (address: string, begin?: number, end?: number): string => { 2 | begin = begin ? begin : 6 3 | end = end ? end : -6 4 | 5 | if (address) { 6 | return `${address.slice(0, begin)}...${address.slice(end)}`; 7 | } 8 | return ''; 9 | }; 10 | 11 | export default shortAddress; 12 | -------------------------------------------------------------------------------- /dashboard/src/utils/transactionExecutor.ts: -------------------------------------------------------------------------------- 1 | import keyring from '@polkadot/ui-keyring'; 2 | import { KeyringAccount } from '@/types'; 3 | import { SubmittableExtrinsic } from '@polkadot/api/types'; 4 | 5 | const exec = async (account: KeyringAccount | string, password: string | null, callback: (...params: any) => SubmittableExtrinsic<'promise'>, params: any[]) => { 6 | try { 7 | const transfer = await callback(...params); 8 | const alicePair = keyring.getPair(typeof account === 'string' ? account : account.address); 9 | if (password) { 10 | alicePair.decodePkcs8(password); 11 | } 12 | const hash = await transfer.signAndSend(alicePair); 13 | return hash.toHex(); 14 | 15 | } catch (err) { 16 | throw err; 17 | } 18 | 19 | }; 20 | 21 | export default exec; 22 | -------------------------------------------------------------------------------- /dashboard/src/utils/vueNotification.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | /** 4 | * NotificationService for vue 5 | * @example 6 | * // Show success message 7 | * NS.success('Success') 8 | * @example 9 | * // Show info message 10 | * NS.info('This is info message'); 11 | */ 12 | class NotificationService extends Vue { 13 | private snackbarTypes: any = { 14 | success: { 15 | type: 'is-success', 16 | actionText: 'View', 17 | }, 18 | info: { 19 | type: 'is-info', 20 | actionText: 'OK', 21 | }, 22 | danger: { 23 | type: 'is-danger', 24 | actionText: 'Oh no!', 25 | }, 26 | }; 27 | 28 | public success(message: string | null, params?: any) { 29 | this.showNotification(message, { ...this.snackbarTypes.success, ...params }) 30 | } 31 | 32 | public info(message: string | null, params?: any) { 33 | this.showNotification(message, { ...this.snackbarTypes.info, ...params }) 34 | } 35 | 36 | public danger(message: string | null, params?: any) { 37 | this.showNotification(message, { ...this.snackbarTypes.danger, ...params }) 38 | } 39 | 40 | /** 41 | * Show error message 42 | */ 43 | public error(message: string | null, params?: any) { 44 | this.danger(message, params); 45 | } 46 | 47 | private showNotification(message: string | null, params = this.snackbarTypes.info) { 48 | this.$buefy.snackbar.open({ 49 | duration: 10000, 50 | message, 51 | type: 'is-success', 52 | position: 'is-top-right', 53 | actionText: 'OK', 54 | queue: false, 55 | ...params, 56 | }); 57 | } 58 | 59 | } 60 | 61 | 62 | const bus = new NotificationService(); 63 | export default bus 64 | -------------------------------------------------------------------------------- /dashboard/src/views/Debug.vue: -------------------------------------------------------------------------------- 1 | 28 | 65 | -------------------------------------------------------------------------------- /dashboard/src/views/Settings.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 31 | 32 | -------------------------------------------------------------------------------- /dashboard/src/views/Staking.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 32 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/Accounts.vue: -------------------------------------------------------------------------------- 1 | 17 | 48 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/AccountsBackup.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/AccountsChangePassword.vue: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/AccountsCreate.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/AccountsRestore.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /dashboard/src/views/accounts/AddressbookCreate.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /dashboard/src/vuex/IdentityModule.ts: -------------------------------------------------------------------------------- 1 | import { Registration, IdentityInfo } from '@polkadot/types/interfaces/identity/types'; 2 | import Connector from '@vue-polkadot/vue-api'; 3 | import Vue from 'vue' 4 | 5 | 6 | export interface IdentityMap { 7 | [address: string]: Registration 8 | } 9 | 10 | export interface IdentityStruct { 11 | identities: IdentityMap; 12 | } 13 | 14 | export interface IdenityRequest { 15 | address: string; 16 | identity: Registration 17 | } 18 | 19 | const defaultState: IdentityStruct = { 20 | identities: {}, 21 | }; 22 | 23 | 24 | const IdentityModule = { 25 | state: { ...defaultState }, 26 | mutations: { 27 | addIdentity(state: IdentityStruct, identityRequest: IdenityRequest) { 28 | const { address, identity } = identityRequest; 29 | if (!state.identities[address]) { 30 | Vue.set(state.identities, address, identity) 31 | } 32 | } 33 | // addAvaibleOption(state: SettingsStruct, settings: Partial) { 34 | 35 | // } 36 | }, 37 | actions: { 38 | setIdentity({commit}: any, identityRequest: IdenityRequest) { 39 | commit('addIdentity', identityRequest); 40 | }, 41 | async fetchIdentity({dispatch}: any, address: string) { 42 | const { api } = Connector.getInstance() 43 | try { 44 | const optionIdentity = await api.query.identity.identityOf(address) 45 | console.log(optionIdentity); 46 | 47 | const identity = optionIdentity.unwrapOr(null) 48 | 49 | if (identity) { 50 | dispatch('setIdentity', { address, identity }) 51 | } 52 | } catch(e) { 53 | console.error('[FETCH IDENTITY] Unable to get identity', e) 54 | } 55 | } 56 | }, 57 | getters: { 58 | availableIdentities(state: IdentityStruct): IdentityMap { 59 | return state.identities 60 | }, 61 | getIdentityFor(state: IdentityStruct): (address: string) => Registration | undefined { 62 | return (address: string) => state.identities[address]; 63 | } 64 | } 65 | } 66 | 67 | 68 | export default IdentityModule 69 | -------------------------------------------------------------------------------- /dashboard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2020", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "skipLibCheck": true, 15 | "types": [ 16 | "webpack-env" 17 | ], 18 | "paths": { 19 | "@/*": [ 20 | "src/*" 21 | ] 22 | }, 23 | "lib": [ 24 | "es2020", 25 | "dom", 26 | "dom.iterable", 27 | "scripthost" 28 | ] 29 | }, 30 | "include": [ 31 | "src/**/*.ts", 32 | "src/**/*.tsx", 33 | "src/**/*.vue", 34 | "tests/**/*.ts", 35 | "tests/**/*.tsx", "src/sw.js" 36 | ], 37 | "exclude": [ 38 | "node_modules" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /dashboard/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "warning", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "linterOptions": { 7 | "exclude": [ 8 | "node_modules/**" 9 | ] 10 | }, 11 | "rules": { 12 | "indent": [true, "tab", 1], 13 | "interface-name": false, 14 | "no-consecutive-blank-lines": false, 15 | "object-literal-sort-keys": false, 16 | "ordered-imports": false, 17 | "quotemark": [true, "single"], 18 | "no-console": false, 19 | "no-trailing-whitespace": false 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dashboard/vue.config.js: -------------------------------------------------------------------------------- 1 | // vue.config.js 2 | module.exports = { 3 | publicPath: './', 4 | // https://webpack.js.org/configuration/dev-server/ 5 | // https://cli.vuejs.org/config/#devserver 6 | devServer: { 7 | host: '127.0.0.1', 8 | port: 9090, 9 | hot: true, 10 | disableHostCheck: true, 11 | }, 12 | } 13 | --------------------------------------------------------------------------------