├── .gitignore ├── LICENSE ├── README.md ├── dfx.json ├── package.json ├── postcss.config.js ├── screenshots ├── screenshot1.png ├── screenshot2.png ├── screenshot3.png └── screenshot4.png ├── scripts ├── data.json └── test.js ├── src ├── nnsexplorer │ ├── database │ │ ├── accountdb.mo │ │ ├── neurondb.mo │ │ └── proposaldb.mo │ ├── key │ │ ├── id.mo │ │ ├── key.mo │ │ └── ord.mo │ ├── log │ │ └── log.mo │ ├── main.mo │ ├── types.mo │ └── vendor │ │ ├── crc │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── NOTICE │ │ ├── README.md │ │ ├── dfx.json │ │ ├── src │ │ │ └── CRC8.mo │ │ └── test │ │ │ └── Main.mo │ │ ├── hex │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── NOTICE │ │ ├── README.md │ │ ├── dfx.json │ │ ├── src │ │ │ └── Hex.mo │ │ └── test │ │ │ └── Main.mo │ │ └── sha │ │ ├── .gitignore │ │ ├── .travis.yml │ │ ├── LICENSE │ │ ├── NOTICE │ │ ├── README.md │ │ ├── dfx.json │ │ ├── src │ │ └── SHA256.mo │ │ └── test │ │ └── Main.mo ├── nnsexplorer_assets │ ├── App.vue │ ├── assets │ │ ├── css │ │ │ ├── color-dark.css │ │ │ ├── icon.css │ │ │ ├── main.css │ │ │ └── theme-green │ │ │ │ ├── color-green.css │ │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ │ └── index.css │ │ └── img │ │ │ ├── img.jpg │ │ │ ├── login-bg.jpg │ │ │ └── visitor.jpg │ ├── components │ │ ├── chart │ │ │ ├── dailyDelegate.vue │ │ │ ├── dailyRewards.vue │ │ │ ├── delegateChart.vue │ │ │ └── resize.js │ │ ├── common │ │ │ ├── Header.vue │ │ │ ├── Home.vue │ │ │ ├── Sidebar.vue │ │ │ ├── bus.js │ │ │ ├── i18n.js │ │ │ └── utils.js │ │ ├── dialog │ │ │ ├── BeDelegator.vue │ │ │ ├── BeNeuron.vue │ │ │ └── ProposalInfo.vue │ │ └── page │ │ │ ├── 404.vue │ │ │ ├── I18n.vue │ │ │ ├── NeuronInfo.vue │ │ │ ├── Overview.vue │ │ │ ├── Profile.vue │ │ │ └── Proposals.vue │ ├── main.js │ ├── public │ │ └── index.html │ └── router │ │ └── index.js └── nnsexplorer_sim │ └── main.mo ├── webpack.config.js └── webpack ├── configs.js ├── prod.env.js ├── utils.js └── vue-loader.conf.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | example.html 5 | favicon.ico 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 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 DFINITY NNS Explorer 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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## An open demo for DFINITY NNS Explorer. 2 | 3 | ## Screenshots 4 | 5 | ### Overview 6 | 7 | ![Screenshots](screenshots/screenshot1.png) 8 | 9 | ### Profile page 10 | 11 | ![Screenshots](screenshots/screenshot2.png) 12 | 13 | ### Neuron details 14 | 15 | ![Screenshots](screenshots/screenshot3.png) 16 | 17 | ### Proposal page 18 | 19 | ![Screenshots](screenshots/screenshot4.png) 20 | 21 | ## Installation steps 22 | 23 | Install the required Node modules (only needed the first time). 24 | 25 | ```bash 26 | npm install 27 | ``` 28 | 29 | Start the replica, then build and install the canisters. 30 | 31 | ```bash 32 | dfx start --background 33 | dfx canister create --all 34 | dfx build 35 | dfx canister install --all 36 | ``` 37 | 38 | Open the URL printed by following command in your web browser. (http://127.0.0.1:8000/?canisterId=*******************) 39 | 40 | ```bash 41 | echo "http://localhost:8000/?canisterId=$(dfx canister id nnsexplorer_assets)" 42 | ``` 43 | 44 | ## Description and presentation 45 | 46 | This demo runs [Internet Computer] as a canister with mock data for DFINITY NNS(Network Nervous System), but it's still a WIP. It shows informations about the system(now mock data), and you can use it to do delegation, withdraw rewards, and even to become a neuron and earn rewards. To start or stop the simulation for running with mock data, use following commands: 47 | 48 | ```bash 49 | dfx canister call nnsexplorer_sim start // Start simulation 50 | dfx canister call nnsexplorer_sim stop // Stop simulation 51 | ``` 52 | 53 | [Internet Computer]: https://dfinity.org/ -------------------------------------------------------------------------------- /dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "nnsexplorer": { 4 | "main": "src/nnsexplorer/main.mo", 5 | "type": "motoko" 6 | }, 7 | "nnsexplorer_assets": { 8 | "dependencies": [ 9 | "nnsexplorer" 10 | ], 11 | "frontend": { 12 | "entrypoint": "src/nnsexplorer_assets/main.js" 13 | }, 14 | "source": [ 15 | "dist/nnsexplorer_assets/" 16 | ], 17 | "type": "assets" 18 | }, 19 | "nnsexplorer_sim": { 20 | "main": "src/nnsexplorer_sim/main.mo", 21 | "type": "motoko" 22 | } 23 | }, 24 | "defaults": { 25 | "build": { 26 | "packtool": "" 27 | } 28 | }, 29 | "dfx": "0.6.12", 30 | "networks": { 31 | "ic": { 32 | "providers": [ 33 | "https://gw.dfinity.network" 34 | ], 35 | "type": "persistent" 36 | }, 37 | "local": { 38 | "bind": "127.0.0.1:8000", 39 | "type": "ephemeral" 40 | } 41 | }, 42 | "version": 1 43 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "manage_assets", 3 | "version": "0.2.0", 4 | "author": "Flanker@Hashquark", 5 | "scripts": { 6 | "build": "webpack", 7 | "test": "node scripts/test" 8 | }, 9 | "dependencies": { 10 | "axios": "^0.18.0", 11 | "babel-polyfill": "^6.26.0", 12 | "big.js": "^5.2.2", 13 | "element-ui": "^2.13.2", 14 | "moment": "^2.27.0", 15 | "vue": "^2.6.10", 16 | "vue-cropperjs": "^3.0.0", 17 | "vue-i18n": "^8.10.0", 18 | "vue-quill-editor": "^3.0.6", 19 | "vue-router": "^3.0.3", 20 | "vue-schart": "^2.0.0", 21 | "vuedraggable": "^2.17.0" 22 | }, 23 | "devDependencies": { 24 | "@dfinity/agent": "0.6.4", 25 | "terser-webpack-plugin": "2.2.2", 26 | "autoprefixer": "^7.1.2", 27 | "babel-core": "^6.22.1", 28 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 29 | "babel-loader": "^7.1.1", 30 | "babel-plugin-dynamic-import-webpack": "^1.1.0", 31 | "babel-plugin-syntax-jsx": "^6.18.0", 32 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 33 | "babel-plugin-transform-runtime": "^6.22.0", 34 | "babel-plugin-transform-vue-jsx": "^3.5.0", 35 | "babel-preset-env": "^1.3.2", 36 | "babel-preset-stage-2": "^6.22.0", 37 | "chalk": "^2.0.1", 38 | "copy-webpack-plugin": "^4.0.1", 39 | "css-loader": "^3.6.0", 40 | "echarts": "^4.1.0", 41 | "file-loader": "^1.1.4", 42 | "friendly-errors-webpack-plugin": "^1.6.1", 43 | "html-webpack-plugin": "^4.3.0", 44 | "mini-css-extract-plugin": "^0.9.0", 45 | "node-fetch": "^2.6.0", 46 | "node-notifier": "^5.1.2", 47 | "node-webcrypto-ossl": "^2.0.1", 48 | "optimize-css-assets-webpack-plugin": "^3.2.0", 49 | "ora": "^1.2.0", 50 | "portfinder": "^1.0.13", 51 | "postcss-import": "^11.0.0", 52 | "postcss-loader": "^3.0.0", 53 | "postcss-url": "^7.2.1", 54 | "rimraf": "^2.6.0", 55 | "semver": "^5.3.0", 56 | "shelljs": "^0.7.6", 57 | "url-loader": "^0.5.8", 58 | "vue-loader": "^15.9.3", 59 | "vue-style-loader": "^3.0.1", 60 | "vue-template-compiler": "^2.5.2", 61 | "webpack": "^4.43.0", 62 | "webpack-bundle-analyzer": "^3.3.2", 63 | "webpack-cli": "^3.3.12", 64 | "webpack-dev-server": "^3.11.0", 65 | "webpack-merge": "^4.1.0" 66 | } 67 | } -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/screenshots/screenshot2.png -------------------------------------------------------------------------------- /screenshots/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/screenshots/screenshot3.png -------------------------------------------------------------------------------- /screenshots/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/screenshots/screenshot4.png -------------------------------------------------------------------------------- /scripts/data.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "accountAddr": "A5AEC167AC201B67C6EF6B267361B3D2595C2EC798EB8D7DD52489BC02DC", 3 | "description": "Dominic Williams - Founder & Chief Scientist", 4 | "commissionRate": 5, 5 | "selfStaking": 300000 6 | }, 7 | { 8 | "accountAddr": "A19BA9C73839E92644491D0901071267D115D1FE1A1A4870C3DB5CA50228", 9 | "description": "Diego Prats - Director of Product", 10 | "commissionRate": 10, 11 | "selfStaking": 200000 12 | }, 13 | { 14 | "accountAddr": "CE1D6EDC4B7383D84187BB9056659DC6135EDF239F0E8DD0FB518A510257", 15 | "description": "Jan Camenisch - VP of Research", 16 | "commissionRate": 10, 17 | "selfStaking": 50000 18 | }, 19 | { 20 | "accountAddr": "CEDDBCA8FA100E5E177F1E3934E98A366CEDFB3968D8915E6E1933970224", 21 | "description": "Donald Trump - President", 22 | "commissionRate": 5, 23 | "selfStaking": 900000 24 | }, 25 | { 26 | "accountAddr": "B5B5E0924288954CE5427AC456366E7DD50837723DA10D04998AD7CE0273", 27 | "description": "Sanam Saaber - General Counsel", 28 | "commissionRate": 10, 29 | "selfStaking": 100000 30 | }, 31 | { 32 | "accountAddr": "3BA830E39688DE354E40084C21FCB0C86E190DBDB322021C2A4843C002D5", 33 | "description": "Barack Obama - President (Retired)", 34 | "commissionRate": 20, 35 | "selfStaking": 600000 36 | } 37 | ] -------------------------------------------------------------------------------- /scripts/test.js: -------------------------------------------------------------------------------- 1 | const fetch = require("node-fetch"); 2 | const fs = require("fs"); 3 | const path = require("path"); 4 | const exec = require('child_process').execSync; 5 | const { Crypto } = require("node-webcrypto-ossl"); 6 | 7 | global.crypto = new Crypto(); 8 | 9 | const decode = s => (new TextDecoder()).decode(s); 10 | 11 | const dfxJson = require("../dfx.json"); 12 | const DEFAULT_HOST = `http://${dfxJson.networks.local.bind}`; 13 | const OUTPUT_DIR = "canisters"; 14 | const { 15 | generateKeyPair, 16 | HttpAgent, 17 | makeActorFactory, 18 | makeAuthTransform, 19 | makeNonceTransform, 20 | Principal 21 | } = require('@dfinity/agent'); 22 | 23 | // Main 24 | 25 | const main = async() => { 26 | console.log("Adding neurons..."); 27 | const neurons = require("./data"); 28 | neurons.forEach(async(neuron) => { 29 | const nnsexplorer = getActor("nnsexplorer"); 30 | await nnsexplorer.createTestNeuron(neuron); 31 | console.log("...neuron added"); 32 | }); 33 | }; 34 | 35 | // Helpers 36 | 37 | const getActor = ( 38 | canisterName, 39 | host = DEFAULT_HOST, 40 | keypair = generateKeyPair() 41 | ) => { 42 | const candid = eval(getCandid(canisterName)); 43 | const canisterId = getCanisterId(canisterName); 44 | const principal = Principal.selfAuthenticating(keypair.publicKey) 45 | const agent = new HttpAgent({ fetch, host, principal }); 46 | agent.addTransform(makeNonceTransform()); 47 | agent.addTransform(makeAuthTransform(keypair)); 48 | return makeActorFactory(candid)({ canisterId, agent }); 49 | }; 50 | 51 | const getCanisterPath = (canisterName) => path.join(__dirname, '..', '.dfx', 'local', OUTPUT_DIR, canisterName); 52 | 53 | const getCandid = (canisterName) => 54 | fs 55 | .readFileSync(`${getCanisterPath(canisterName)}/${canisterName}.did.js`) 56 | .toString() 57 | .replace("export default ", ""); 58 | 59 | const getCanisterId = (canisterName) => { 60 | if (process.env.DFX_NETWORK === 'tungsten') { 61 | let id = exec(`dfx canister --network=tungsten id ${canisterName}`) 62 | return decode(id).trim(); 63 | } else { 64 | let id = exec(`dfx canister --network=local id ${canisterName}`) 65 | return decode(id).trim(); 66 | } 67 | }; 68 | 69 | // Run main() 70 | 71 | main(); -------------------------------------------------------------------------------- /src/nnsexplorer/database/accountdb.mo: -------------------------------------------------------------------------------- 1 | import Array "mo:base/Array"; 2 | import HashMap "mo:base/HashMap"; 3 | import Iter "mo:base/Iter"; 4 | import Option "mo:base/Option"; 5 | import Text "mo:base/Text"; 6 | import Nat64 "mo:base/Nat64"; 7 | import Types "../types"; 8 | 9 | module { 10 | type DFNAccount = Types.DFNAccount; 11 | 12 | public class AccountHashMap() { 13 | // The "database" is just a local hash map 14 | let hashMap = HashMap.HashMap(1, Text.equal, Text.hash); 15 | 16 | public func createAccount(account: DFNAccount) { 17 | hashMap.put(account.accountAddr, account); 18 | }; 19 | 20 | public func updateAccount(account: DFNAccount) { 21 | let existing = findAccount(account.accountAddr); 22 | switch (existing) { 23 | case (null) { }; 24 | case (?existing) { 25 | hashMap.put(account.accountAddr, account); 26 | }; 27 | }; 28 | }; 29 | 30 | public func findAccount(address: Text): ?DFNAccount { 31 | hashMap.get(address) 32 | }; 33 | 34 | public func existAccount(accountAddr: Text): Bool { 35 | let existing = findAccount(accountAddr); 36 | switch (existing) { 37 | case (?existing) { true }; 38 | case (null) { false }; 39 | }; 40 | }; 41 | 42 | public func setDelegator(accountAddr: Text, value: Bool): Bool { 43 | let existing = findAccount(accountAddr); 44 | switch (existing) { 45 | case (?existing) { 46 | var new = { 47 | accountAddr = existing.accountAddr; 48 | signature = existing.signature; 49 | balance = existing.balance; 50 | rewards = existing.rewards; 51 | isDelegator = value; 52 | }; 53 | hashMap.put(accountAddr, new); 54 | true 55 | }; 56 | case (null) { false }; 57 | }; 58 | }; 59 | 60 | public func balance(accountAddr: Text): Nat64 { 61 | let existing = findAccount(accountAddr); 62 | switch (existing) { 63 | case (?existing) { existing.balance }; 64 | case (null) { Nat64.fromNat(0) }; 65 | }; 66 | }; 67 | 68 | public func updateBalance(accountAddr: Text, newValue: Nat64): Bool { 69 | let existing = findAccount(accountAddr); 70 | switch (existing) { 71 | case (?existing) { 72 | var new = { 73 | accountAddr = existing.accountAddr; 74 | signature = existing.signature; 75 | balance = newValue; 76 | rewards = existing.rewards; 77 | isDelegator = existing.isDelegator; 78 | }; 79 | hashMap.put(accountAddr, new); 80 | true 81 | }; 82 | case (null) { false }; 83 | }; 84 | }; 85 | 86 | public func addBalance(accountAddr: Text, value: Nat64): Bool { 87 | let existing = findAccount(accountAddr); 88 | switch (existing) { 89 | case (?existing) { 90 | var new = { 91 | accountAddr = existing.accountAddr; 92 | signature = existing.signature; 93 | balance = existing.balance + value; 94 | rewards = existing.rewards; 95 | isDelegator = existing.isDelegator; 96 | }; 97 | hashMap.put(accountAddr, new); 98 | true 99 | }; 100 | case (null) { false }; 101 | }; 102 | }; 103 | 104 | public func subBalance(accountAddr: Text, value: Nat64): Bool { 105 | let existing = findAccount(accountAddr); 106 | switch (existing) { 107 | case (?existing) { 108 | if (existing.balance < value) { 109 | return false; 110 | }; 111 | var new = { 112 | accountAddr = existing.accountAddr; 113 | signature = existing.signature; 114 | balance = existing.balance - value; 115 | rewards = existing.rewards; 116 | isDelegator = existing.isDelegator; 117 | }; 118 | hashMap.put(accountAddr, new); 119 | true 120 | }; 121 | case (null) { false }; 122 | }; 123 | }; 124 | 125 | public func rewards(accountAddr: Text): Nat64 { 126 | let existing = findAccount(accountAddr); 127 | switch (existing) { 128 | case (?existing) { existing.rewards }; 129 | case (null) { Nat64.fromNat(0) }; 130 | }; 131 | }; 132 | 133 | public func updateRewards(accountAddr: Text, newValue: Nat64): Bool { 134 | let existing = findAccount(accountAddr); 135 | switch (existing) { 136 | case (?existing) { 137 | var new = { 138 | accountAddr = existing.accountAddr; 139 | signature = existing.signature; 140 | balance = existing.balance; 141 | rewards = newValue; 142 | isDelegator = existing.isDelegator; 143 | }; 144 | hashMap.put(accountAddr, new); 145 | true 146 | }; 147 | case (null) { false }; 148 | }; 149 | }; 150 | 151 | public func addRewards(accountAddr: Text, value: Nat64): Bool { 152 | let existing = findAccount(accountAddr); 153 | switch (existing) { 154 | case (?existing) { 155 | var new = { 156 | accountAddr = existing.accountAddr; 157 | signature = existing.signature; 158 | balance = existing.balance; 159 | rewards = existing.rewards + value; 160 | isDelegator = existing.isDelegator; 161 | }; 162 | hashMap.put(accountAddr, new); 163 | true 164 | }; 165 | case (null) { false }; 166 | }; 167 | }; 168 | 169 | }; 170 | }; 171 | -------------------------------------------------------------------------------- /src/nnsexplorer/database/neurondb.mo: -------------------------------------------------------------------------------- 1 | import Array "mo:base/Array"; 2 | import HashMap "mo:base/HashMap"; 3 | import Iter "mo:base/Iter"; 4 | import Option "mo:base/Option"; 5 | import Nat64 "mo:base/Nat64"; 6 | import Text "mo:base/Text"; 7 | import List "mo:base/List"; 8 | import Assoc "mo:base/AssocList"; 9 | import Types "../types"; 10 | 11 | module { 12 | type NewNeuron = Types.NewNeuron; 13 | type Neuron = Types.Neuron; 14 | 15 | public class NeuronHashMap() { 16 | // The "database" is just a local hash map 17 | let hashMap = HashMap.HashMap(1, Text.equal, Text.hash); 18 | 19 | public func createNeuron(neuron: NewNeuron) { 20 | hashMap.put(neuron.accountAddr, makeNeuron(neuron)); 21 | }; 22 | 23 | public func updateDelegation(fromAddr: Text, toAddr: Text, amt: Nat64): Bool { 24 | let existing = findNeuron(toAddr); 25 | switch (existing) { 26 | case (?existing) { 27 | var selfStakingNew = existing.selfStaking; 28 | var totalDelegationsNew = existing.totalDelegations; 29 | var delegationsNew = existing.delegations; 30 | if (fromAddr == toAddr) { 31 | selfStakingNew += amt; 32 | } else { 33 | totalDelegationsNew += amt; 34 | 35 | var exist = false; 36 | var amountNew: Nat64 = 0: Nat64; 37 | var amountOld = Assoc.find(existing.delegations, fromAddr, Text.equal); 38 | switch (amountOld) { 39 | case (null) { amountNew := amt; }; 40 | case (?amountOld) { 41 | exist := true; 42 | amountNew := amountOld + amt; 43 | }; 44 | }; 45 | 46 | let (delegationsNewTemp, _) = 47 | Assoc.replace(existing.delegations, fromAddr, Text.equal, ?amountNew); 48 | delegationsNew := delegationsNewTemp; 49 | }; 50 | 51 | let neuron: Neuron = { 52 | accountAddr = existing.accountAddr; 53 | description = existing.description; 54 | commissionRate = existing.commissionRate; 55 | selfStaking = selfStakingNew; 56 | totalDelegations = totalDelegationsNew; 57 | delegations = delegationsNew; 58 | }; 59 | hashMap.put(toAddr, neuron); 60 | 61 | true 62 | }; 63 | case (null) { false }; 64 | }; 65 | }; 66 | 67 | public func updateUnDelegation(fromAddr: Text, toAddr: Text, amt: Nat64): Bool { 68 | let existing = findNeuron(toAddr); 69 | switch (existing) { 70 | case (?existing) { 71 | var selfStakingNew = existing.selfStaking; 72 | var totalDelegationsNew = existing.totalDelegations; 73 | var delegationsNew = existing.delegations; 74 | if (fromAddr == toAddr) { 75 | selfStakingNew += amt; //TODO: update other delegators 76 | } else { 77 | totalDelegationsNew -= amt; 78 | 79 | var exist = false; 80 | var amountNew: Nat64 = 0: Nat64; 81 | var amountOld = Assoc.find(existing.delegations, fromAddr, Text.equal); 82 | switch (amountOld) { 83 | case (null) { return false; }; 84 | case (?amountOld) { 85 | exist := true; 86 | amountNew := amountOld - amt; 87 | }; 88 | }; 89 | 90 | if (amountNew == Nat64.fromNat(0)) { 91 | let (delegationsNewTemp, _) = 92 | Assoc.replace(existing.delegations, fromAddr, Text.equal, null); 93 | delegationsNew := delegationsNewTemp; 94 | } else { 95 | let (delegationsNewTemp, _) = 96 | Assoc.replace(existing.delegations, fromAddr, Text.equal, ?amountNew); 97 | delegationsNew := delegationsNewTemp; 98 | }; 99 | 100 | }; 101 | 102 | let neuron: Neuron = { 103 | accountAddr = existing.accountAddr; 104 | description = existing.description; 105 | commissionRate = existing.commissionRate; 106 | selfStaking = selfStakingNew; 107 | totalDelegations = totalDelegationsNew; 108 | delegations = delegationsNew; 109 | }; 110 | hashMap.put(toAddr, neuron); 111 | 112 | true 113 | }; 114 | case (null) { false }; 115 | }; 116 | }; 117 | 118 | public func updateNeuron(neuron: Neuron) { 119 | let existing = findNeuron(neuron.accountAddr); 120 | switch (existing) { 121 | case (null) { }; 122 | case (?existing) { 123 | hashMap.put(neuron.accountAddr, neuron); 124 | }; 125 | }; 126 | }; 127 | 128 | public func findNeuron(accountAddr: Text): ?Neuron { 129 | hashMap.get(accountAddr) 130 | }; 131 | 132 | public func findMany(accountAddrs: [Text]): [Neuron] { 133 | func getNeuron(addr: Text): Neuron { 134 | Option.unwrap(hashMap.get(addr)) 135 | }; 136 | Array.map(accountAddrs, getNeuron) 137 | }; 138 | 139 | public func findBy(term: Text): [Neuron] { 140 | var neurons: [Neuron] = []; 141 | for ((id, neuron) in hashMap.entries()) { 142 | let address = neuron.accountAddr; // # " " #; 143 | if (includesText(address, term)) { 144 | neurons := Array.append(neurons, [neuron]); 145 | }; 146 | }; 147 | neurons 148 | }; 149 | 150 | public func findList(): [Neuron] { 151 | var neurons: [Neuron] = []; 152 | for ((id, neuron) in hashMap.entries()) { 153 | neurons := Array.append(neurons, [neuron]); 154 | }; 155 | neurons 156 | }; 157 | 158 | // Helpers 159 | 160 | func makeNeuron(neuron: NewNeuron): Neuron { 161 | { 162 | accountAddr = neuron.accountAddr; 163 | description = neuron.description; 164 | commissionRate = neuron.commissionRate; 165 | selfStaking = neuron.selfStaking; 166 | totalDelegations = Nat64.fromNat(0); 167 | delegations = List.nil<(Text, Nat64)>(); 168 | } 169 | }; 170 | 171 | func includesText(string: Text, term: Text): Bool { 172 | let stringArray = Iter.toArray(string.chars()); 173 | let termArray = Iter.toArray(term.chars()); 174 | 175 | var i = 0; 176 | var j = 0; 177 | 178 | while (i < stringArray.size() and j < termArray.size()) { 179 | if (stringArray[i] == termArray[j]) { 180 | i += 1; 181 | j += 1; 182 | if (j == termArray.size()) { return true; } 183 | } else { 184 | i += 1; 185 | j := 0; 186 | } 187 | }; 188 | false 189 | }; 190 | }; 191 | }; 192 | -------------------------------------------------------------------------------- /src/nnsexplorer/database/proposaldb.mo: -------------------------------------------------------------------------------- 1 | import Prim "mo:prim"; 2 | import Array "mo:base/Array"; 3 | import HashMap "mo:base/HashMap"; 4 | import Iter "mo:base/Iter"; 5 | import Option "mo:base/Option"; 6 | import Nat64 "mo:base/Nat64"; 7 | import Word32 "mo:base/Word32"; 8 | import List "mo:base/List"; 9 | import Assoc "mo:base/AssocList"; 10 | import Text "mo:base/Text"; 11 | import Types "../types"; 12 | import KeyID "../key/id"; 13 | 14 | module { 15 | type NewProposal = Types.NewDFNProposal; 16 | type Proposal = Types.DFNProposal; 17 | type ProposalID = Text; 18 | 19 | public class ProposalHashMap() { 20 | // The "database" is just a local hash map 21 | let hashMap = HashMap.HashMap(1, Text.equal, Text.hash); 22 | 23 | public func createProposal(newProposal: NewProposal) { 24 | let proposal = makeProposal(newProposal); 25 | hashMap.put(calProposalID(proposal), proposal); 26 | }; 27 | 28 | public func updateProposal(proposal: Proposal) { 29 | hashMap.put(calProposalID(proposal), proposal); 30 | }; 31 | 32 | public func voteProposal(account: Text, id: Text, approve: Bool) { 33 | let existing = hashMap.get(id); 34 | switch (existing) { 35 | case (?existing) { 36 | let (newVotes, _) = 37 | Assoc.replace(existing.votes, account, Text.equal, ?approve); 38 | let new = { 39 | title = existing.title; 40 | details = existing.details; 41 | created = existing.created; 42 | votes = newVotes; 43 | excutionTime = existing.excutionTime; 44 | status = existing.status; 45 | }; 46 | hashMap.put(id, new); 47 | }; 48 | case (null) { }; 49 | }; 50 | }; 51 | 52 | public func updateStatus(id: Text, newStatus: Text) { 53 | let existing = hashMap.get(id); 54 | switch (existing) { 55 | case (?existing) { 56 | let new = { 57 | title = existing.title; 58 | details = existing.details; 59 | created = existing.created; 60 | votes = existing.votes; 61 | excutionTime = existing.excutionTime; 62 | status = newStatus; 63 | }; 64 | hashMap.put(id, new); 65 | }; 66 | case (null) { }; 67 | }; 68 | }; 69 | 70 | public func findProposalByID(id: Text): ?Proposal { 71 | hashMap.get(id) 72 | }; 73 | 74 | public func findByTitle(term: Text): [Proposal] { 75 | var proposals: [Proposal] = []; 76 | for ((id, proposal) in hashMap.entries()) { 77 | let title = proposal.title; // # " " #; 78 | if (includesText(title, term)) { 79 | proposals := Array.append(proposals, [proposal]); 80 | }; 81 | }; 82 | proposals 83 | }; 84 | 85 | public func findList(): [Proposal] { 86 | var proposals: [Proposal] = []; 87 | for ((id, proposal) in hashMap.entries()) { 88 | proposals := Array.append(proposals, [proposal]); 89 | }; 90 | proposals 91 | }; 92 | 93 | // Helpers 94 | 95 | func makeProposal(newProposal: NewProposal): Proposal { 96 | var approve = true; 97 | let (selfVote, _) = 98 | Assoc.replace(List.nil<(Text, Bool)>(), newProposal.createdBy, Text.equal, ?approve); 99 | { 100 | title = newProposal.title; 101 | details = newProposal.details; 102 | created = (newProposal.createdBy, Prim.nat64ToNat(Prim.time()/1000000000)); //ns to s 103 | votes = selfVote; 104 | excutionTime = newProposal.excutionTime; 105 | status = "active"; 106 | } 107 | }; 108 | 109 | public func calProposalID(proposal: Proposal): ProposalID { 110 | let (account, time) = proposal.created; 111 | account # Word32.toText(Word32.fromInt(time)) 112 | }; 113 | 114 | func includesText(string: Text, term: Text): Bool { 115 | let stringArray = Iter.toArray(string.chars()); 116 | let termArray = Iter.toArray(term.chars()); 117 | 118 | var i = 0; 119 | var j = 0; 120 | 121 | while (i < stringArray.size() and j < termArray.size()) { 122 | if (stringArray[i] == termArray[j]) { 123 | i += 1; 124 | j += 1; 125 | if (j == termArray.size()) { return true; } 126 | } else { 127 | i += 1; 128 | j := 0; 129 | } 130 | }; 131 | false 132 | }; 133 | }; 134 | }; 135 | -------------------------------------------------------------------------------- /src/nnsexplorer/key/id.mo: -------------------------------------------------------------------------------- 1 | import Array "mo:base/Array"; 2 | import CRC8 "../vendor/crc/src/CRC8"; 3 | import Hex "../vendor/hex/src/Hex"; 4 | import Iter "mo:base/Iter"; 5 | import Key "key"; 6 | import Nat "mo:base/Nat"; 7 | import Ord "ord"; 8 | import Prim "mo:prim"; 9 | import Result "mo:base/Result"; 10 | 11 | module { 12 | 13 | private type Id = Text; 14 | private type Key = Key.Key; 15 | private type Ordering = Ord.Ordering; 16 | private type Result = Result.Result; 17 | 18 | public func compare(a : [Word8], b : [Word8]) : Ordering { 19 | let na = a.size(); 20 | let nb = b.size(); 21 | var i = 0; 22 | let n = Nat.min(na, nb); 23 | while (i < n) { 24 | if (a[i] < b[i]) { 25 | return #lt; 26 | }; 27 | if (a[i] > b[i]) { 28 | return #gt; 29 | }; 30 | i += 1; 31 | }; 32 | if (na < nb) { 33 | return #lt; 34 | }; 35 | if (na > nb) { 36 | return #gt; 37 | }; 38 | return #eq; 39 | }; 40 | 41 | public func isId(id : Id) : Bool { 42 | switch (Hex.decode(id)) { 43 | case (#ok buf) { 44 | if (buf.size() != 9) { 45 | return false; 46 | } else { 47 | let prefix = Array.tabulate(8, func (i) { 48 | buf[i]; 49 | }); 50 | return CRC8.crc8(prefix) == buf[8]; 51 | }; 52 | }; 53 | case _ { 54 | return false; 55 | }; 56 | }; 57 | }; 58 | 59 | public func hexToKey(hex : Text) : Result { 60 | Result.mapOk<[Word8], Key, Hex.DecodeError>(Hex.decode(hex), Key.key); 61 | }; 62 | 63 | // public func hexToKeyOrTrap(hex : Text) : Key { 64 | // Result.assertUnwrapAny(hexToKey(hex)); 65 | // }; 66 | 67 | public func keyToHex(key : Key) : Text { 68 | Hex.encode(key.preimage); 69 | }; 70 | 71 | public func principalToId(principal : Principal) : Text { 72 | let base = Iter.toArray(Prim.blobOfPrincipal(principal).bytes()); 73 | let crc8 = CRC8.crc8(base); 74 | return Hex.encode(Array.append(base, [crc8])); 75 | }; 76 | }; 77 | -------------------------------------------------------------------------------- /src/nnsexplorer/key/key.mo: -------------------------------------------------------------------------------- 1 | import Array "mo:base/Array"; 2 | import Hex "../vendor/hex/src/Hex"; 3 | import Iter "mo:base/Iter"; 4 | import Prim "mo:prim"; 5 | import SHA256 "../vendor/sha/src/SHA256"; 6 | 7 | module { 8 | 9 | public type Key = { 10 | image : [Word8]; 11 | preimage : [Word8]; 12 | }; 13 | 14 | public func key(data : [Word8]) : Key { 15 | { image = SHA256.sha256(data); 16 | preimage = data; 17 | }; 18 | }; 19 | 20 | public func equal(k1 : Key, k2 : Key) : Bool { 21 | for (i in Iter.range(0, k1.image.size() - 1)) { 22 | if (k1.image[i] != k2.image[i]) { 23 | return false; 24 | }; 25 | }; 26 | return true; 27 | }; 28 | 29 | public func compare(k1 : Key, k2 : Key) : Int { 30 | for (i in Iter.range(0, k1.image.size() - 1)) { 31 | if (k1.image[i] < k2.image[i]) { 32 | return -1; 33 | }; 34 | if (k1.image[i] > k2.image[i]) { 35 | return 1; 36 | }; 37 | }; 38 | return 0; 39 | }; 40 | 41 | public func show(key : Key) : Text { 42 | "{\n preimage = " # 43 | Hex.encode(key.preimage) # 44 | ";\n image = " # 45 | Hex.encode(key.image) # 46 | ";\n}" 47 | }; 48 | 49 | public func sort(keys : [Key]) : [Key] { 50 | let n = keys.size(); 51 | if (n < 2) { 52 | return keys 53 | } else { 54 | let result = Array.thaw(keys); 55 | sortBy(compare, result, 0, n - 1); 56 | return Array.freeze(result); 57 | }; 58 | }; 59 | 60 | public func distance(k1 : Key, k2 : Key) : Nat { 61 | var n = 0; 62 | for (i in Iter.range(0, k1.image.size() - 1)) { 63 | n += Prim.word8ToNat(k1.image[i] ^ k2.image[i]) * 256 ** i; 64 | }; 65 | return n; 66 | }; 67 | 68 | public func compareByDistance(to : Key, k1 : Key, k2 : Key) : Int { 69 | let a = distance(to, k1); 70 | let b = distance(to, k2); 71 | if (a < b) { 72 | return -1; 73 | }; 74 | if (a > b) { 75 | return 1; 76 | }; 77 | return 0; 78 | }; 79 | 80 | public func sortByDistance(to : Key, keys : [Key]) : [Key] { 81 | let n = keys.size(); 82 | if (n < 2) { 83 | return keys 84 | } else { 85 | let result = Array.thaw(keys); 86 | sortBy(func (k1, k2) { 87 | return compareByDistance(to, k1, k2); 88 | }, result, 0, n - 1); 89 | return Array.freeze(result); 90 | }; 91 | }; 92 | 93 | private func sortBy(f : (X, X) -> Int, xs : [var X], l : Int, r : Int) { 94 | if (l < r) { 95 | var i = l; 96 | var j = r; 97 | var swap = xs[0]; 98 | let pivot = xs[Prim.abs(l + r) / 2]; 99 | while (i <= j) { 100 | while (f(xs[Prim.abs(i)], pivot) < 0) { 101 | i += 1; 102 | }; 103 | while (f(xs[Prim.abs(j)], pivot) > 0) { 104 | j -= 1; 105 | }; 106 | if (i <= j) { 107 | swap := xs[Prim.abs(i)]; 108 | xs[Prim.abs(i)] := xs[Prim.abs(j)]; 109 | xs[Prim.abs(j)] := swap; 110 | i += 1; 111 | j -= 1; 112 | }; 113 | }; 114 | if (l < j) { 115 | sortBy(f, xs, l, j); 116 | }; 117 | if (i < r) { 118 | sortBy(f, xs, i, r); 119 | }; 120 | }; 121 | }; 122 | }; 123 | -------------------------------------------------------------------------------- /src/nnsexplorer/key/ord.mo: -------------------------------------------------------------------------------- 1 | /** 2 | [#mod-Ord] 3 | = `Ord` -- Orderings 4 | */ 5 | 6 | module { 7 | 8 | /** 9 | A type to represent an ordering. 10 | */ 11 | public type Ordering = { 12 | #lt; 13 | #eq; 14 | #gt; 15 | }; 16 | 17 | /** 18 | Check if an ordering is less than. 19 | */ 20 | public let isLT : Ordering -> Bool = 21 | func(ordering : Ordering) : Bool { 22 | switch ordering { 23 | case (#lt) true; 24 | case _ false; 25 | }; 26 | }; 27 | 28 | /** 29 | Check if an ordering is equal. 30 | */ 31 | public let isEQ : Ordering -> Bool = 32 | func(ordering : Ordering) : Bool { 33 | switch ordering { 34 | case (#eq) true; 35 | case _ false; 36 | }; 37 | }; 38 | 39 | /** 40 | Check if an ordering is greater than. 41 | */ 42 | public let isGT : Ordering -> Bool = 43 | func(ordering : Ordering) : Bool { 44 | switch ordering { 45 | case (#gt) true; 46 | case _ false; 47 | }; 48 | }; 49 | 50 | }; 51 | -------------------------------------------------------------------------------- /src/nnsexplorer/log/log.mo: -------------------------------------------------------------------------------- 1 | import Prelude "mo:base/Prelude"; 2 | 3 | module { 4 | 5 | public func trace(message : Text) { 6 | Prelude.printLn("TRACE: " # message); 7 | }; 8 | 9 | public func info(message : Text) { 10 | Prelude.printLn("INFO: " # message); 11 | }; 12 | 13 | public func warn(message : Text) { 14 | Prelude.printLn("WARN: " # message); 15 | }; 16 | 17 | public func error(message : Text) { 18 | Prelude.printLn("ERROR: " # message); 19 | Prelude.unreachable(); 20 | }; 21 | }; -------------------------------------------------------------------------------- /src/nnsexplorer/main.mo: -------------------------------------------------------------------------------- 1 | // Make the Connectd app's public methods available locally 2 | import Prelude "mo:base/Prelude"; 3 | import Prim "mo:prim"; 4 | import Nat "mo:base/Nat"; 5 | import Nat64 "mo:base/Nat64"; 6 | import Int "mo:base/Int"; 7 | import List "mo:base/List"; 8 | import Principal "mo:base/Principal"; 9 | import AccountDB "./database/accountdb"; 10 | import NeuronDB "./database/neurondb"; 11 | import ProposalDB "./database/proposaldb"; 12 | import Types "./types"; 13 | import KeyID "./key/id"; 14 | 15 | actor nnsexplorer { 16 | type DFNAccount = Types.DFNAccount; 17 | type NewNeuron = Types.NewNeuron; 18 | type NewDFNProposal = Types.NewDFNProposal; 19 | type Neuron = Types.Neuron; 20 | type Proposal = Types.DFNProposal; 21 | 22 | var accountDb: AccountDB.AccountHashMap = AccountDB.AccountHashMap(); 23 | var neuronDb: NeuronDB.NeuronHashMap = NeuronDB.NeuronHashMap(); 24 | var proposaldb: ProposalDB.ProposalHashMap = ProposalDB.ProposalHashMap(); 25 | 26 | // Healthcheck 27 | 28 | public query func healthcheck(): async Bool { true }; 29 | 30 | // Account 31 | 32 | public shared query{ 33 | caller = caller; 34 | } func getcid(): async Text { 35 | KeyID.principalToId(caller); 36 | }; 37 | 38 | public shared { 39 | caller = caller; 40 | } func signup(account: DFNAccount): async Bool { 41 | if (accountDb.existAccount(account.accountAddr)) { return false; }; 42 | accountDb.createAccount(account); 43 | true 44 | }; 45 | 46 | public shared query{ 47 | caller = caller; 48 | } func existAccount(accountAddr: Text): async Bool { 49 | accountDb.existAccount(accountAddr) 50 | }; 51 | 52 | public shared query{ 53 | caller = caller; 54 | } func verifyAccount(accountAddr: Text, signature: Text): async Bool { 55 | let existing = accountDb.findAccount(accountAddr); 56 | switch (existing) { 57 | case (?existing) { existing.signature == signature }; 58 | case (null) { false }; 59 | }; 60 | }; 61 | 62 | public shared query func getAccount(addr: Text): async ?DFNAccount { 63 | accountDb.findAccount(addr) 64 | }; 65 | 66 | public shared query func getBalance(addr: Text): async Text { 67 | Nat64.toText(accountDb.balance(addr)) 68 | }; 69 | 70 | public shared query func getRewards(addr: Text): async Text { 71 | Nat64.toText(accountDb.rewards(addr)) 72 | }; 73 | 74 | public shared query func getDelegations(addr: Text): async Text { 75 | let neuronList = neuronDb.findList(); 76 | var fullResultStr = "["; 77 | var i = 0; 78 | for (neuron in neuronList.vals()) { 79 | func getDelegationInfo((addrDele, amount): (Text, Nat64)) { 80 | if (addrDele == addr) { 81 | if (i > 0) { 82 | fullResultStr #= ","; 83 | }; 84 | i += 1; 85 | 86 | let str = "{\n\"Neuron Account\": \"" # neuron.accountAddr # "\",\n\"Description\": \"" # neuron.description # "\",\n\"Commission Rate\": \"" # Nat.toText(neuron.commissionRate) # "%" # "\",\n\"Amount\": \"" # Nat64.toText(amount) # "\"\n}"; 87 | fullResultStr #= str; 88 | }; 89 | }; 90 | List.iterate<(Text, Nat64)>(neuron.delegations, getDelegationInfo); 91 | }; 92 | 93 | fullResultStr #= "]"; 94 | return fullResultStr; 95 | }; 96 | 97 | public shared(msg) func withdrawRewards(addr: Text): async Bool { 98 | let existing = accountDb.findAccount(addr); 99 | switch (existing) { 100 | case (?existing) { 101 | let new = { 102 | accountAddr = existing.accountAddr; 103 | signature = existing.signature; 104 | balance = existing.balance + existing.rewards; 105 | rewards = 0: Nat64; 106 | isDelegator = existing.isDelegator; 107 | }; 108 | accountDb.updateAccount(new); 109 | true 110 | }; 111 | case (null) { false }; 112 | }; 113 | }; 114 | 115 | public shared(msg) func updateAccount(account: DFNAccount): async () { 116 | accountDb.updateAccount(account); 117 | }; 118 | 119 | public shared(msg) func updateAccounts(accounts: [DFNAccount]): async () { 120 | for (account in accounts.vals()) { 121 | accountDb.updateAccount(account); 122 | }; 123 | }; 124 | 125 | // Neurons 126 | 127 | public shared(msg) func createNeuron(newNeuron: NewNeuron): async Bool { 128 | let account = accountDb.findAccount(newNeuron.accountAddr); 129 | switch (account) { 130 | case (?account) { 131 | if (account.isDelegator) { false } else { 132 | let existing = neuronDb.findNeuron(newNeuron.accountAddr); 133 | switch (existing) { 134 | case (?existing) { false }; 135 | case (null) { 136 | if (accountDb.subBalance(newNeuron.accountAddr, newNeuron.selfStaking)) { 137 | neuronDb.createNeuron(newNeuron); 138 | true 139 | } else { 140 | false 141 | }; 142 | }; 143 | }; 144 | }; 145 | }; 146 | case (null) { false }; 147 | }; 148 | }; 149 | 150 | public shared(msg) func updateByDelegation(fromAddr: Text, toAddr: Text, amount: Nat64): async Bool { 151 | let existing = neuronDb.findNeuron(fromAddr); 152 | switch (existing) { 153 | case (?existing) { false }; 154 | case (null) { 155 | let account = accountDb.findAccount(fromAddr); 156 | if (accountDb.subBalance(fromAddr, amount) and accountDb.setDelegator(fromAddr, true)) { 157 | if (neuronDb.updateDelegation(fromAddr, toAddr, amount)) { 158 | true 159 | } else { 160 | switch (account) { 161 | case (?account) { accountDb.updateAccount(account) }; 162 | case (null) { assert(false) }; 163 | }; 164 | false 165 | }; 166 | } else { 167 | false 168 | }; 169 | }; 170 | }; 171 | }; 172 | 173 | public shared(msg) func updateByUnDelegation(fromAddr: Text, toAddr: Text, amount: Nat64): async Bool { 174 | let existing = neuronDb.findNeuron(fromAddr); 175 | switch (existing) { 176 | case (?existing) { false }; 177 | case (null) { 178 | let account = accountDb.findAccount(fromAddr); 179 | if (neuronDb.updateUnDelegation(fromAddr, toAddr, amount)) { 180 | if (accountDb.addBalance(fromAddr, amount)) { 181 | true 182 | } else { 183 | assert(false); 184 | false 185 | }; 186 | } else { 187 | false 188 | }; 189 | }; 190 | }; 191 | }; 192 | 193 | public shared(msg) func updateNeuron(neuron: Neuron): async () { 194 | neuronDb.updateNeuron(neuron); 195 | }; 196 | 197 | public shared(msg) func updateNeurons(neurons: [Neuron]): async () { 198 | for (neuron in neurons.vals()) { 199 | neuronDb.updateNeuron(neuron); 200 | }; 201 | }; 202 | 203 | public shared query func getNeuron(addr: Text): async Neuron { 204 | let existing = neuronDb.findNeuron(addr); 205 | switch (existing) { 206 | case (?existing) { existing }; 207 | case (null) { 208 | { 209 | accountAddr = ""; 210 | description = ""; 211 | commissionRate = 0; 212 | selfStaking = Nat64.fromNat(0); 213 | totalDelegations = Nat64.fromNat(0); 214 | delegations = List.nil<(Text, Nat64)>(); 215 | } 216 | }; 217 | }; 218 | }; 219 | 220 | public shared query func search(term: Text): async [Neuron] { 221 | neuronDb.findBy(term) 222 | }; 223 | 224 | public shared query func getNeuronList(): async Text { 225 | var results = neuronDb.findList(); 226 | var fullResultStr = "["; 227 | var i = 0; 228 | for (result in results.vals()) { 229 | if (i > 0) { 230 | fullResultStr #= ","; 231 | }; 232 | i += 1; 233 | 234 | var delegatorsNum = 0; 235 | func getDelegatorsNum((addr, amount): (Text, Nat64)) { 236 | delegatorsNum += 1; 237 | }; 238 | List.iterate<(Text, Nat64)>(result.delegations, getDelegatorsNum); 239 | 240 | let str = "{\n\"Account Address\": \"" # result.accountAddr # "\",\n\"Description\": \"" # result.description # "\",\n\"Commission Rate\": \"" # Nat.toText(result.commissionRate) # "%" # "\",\n\"Self Staking\": \"" # Nat64.toText(result.selfStaking) # "\",\n\"Total Delegations\": \"" # Nat64.toText(result.totalDelegations) # "\",\n\"Delegators\": \"" # Nat.toText(delegatorsNum) # "\"\n}"; 241 | fullResultStr #= str; 242 | }; 243 | fullResultStr #= "]"; 244 | return fullResultStr; 245 | }; 246 | 247 | // Proposals 248 | 249 | public shared(msg) func createProposal(newProposal: NewDFNProposal): async () { 250 | proposaldb.createProposal(newProposal); 251 | }; 252 | 253 | public shared(msg) func updateProposalStatus(id: Text, newStatus: Text): async () { 254 | proposaldb.updateStatus(id, newStatus); 255 | }; 256 | 257 | public shared(msg) func voteForProposal(account: Text, id: Text, approve: Bool): async Bool { 258 | let existing = proposaldb.findProposalByID(id); 259 | switch (existing) { 260 | case (?existing) { 261 | proposaldb.voteProposal(account, id, approve); 262 | true 263 | }; 264 | case (null) { false }; 265 | }; 266 | }; 267 | 268 | public shared query func getProposalID(proposal: Proposal): async Text { 269 | proposaldb.calProposalID(proposal); 270 | }; 271 | 272 | public shared query func getProposalContent(id: Text): async Text { 273 | let existing = proposaldb.findProposalByID(id); 274 | switch (existing) { 275 | case (?existing) { existing.details }; 276 | case (null) { "" }; 277 | }; 278 | }; 279 | 280 | public shared query func getProposalApprovals(id: Text): async Text { 281 | let existing = proposaldb.findProposalByID(id); 282 | switch (existing) { 283 | case (null) { "" }; 284 | case (?existing) { 285 | var fullResultStr = "["; 286 | 287 | var str = ""; 288 | var i = 0; 289 | func getApprovals((addr, approve): (Text, Bool)) { 290 | if (approve != true) { 291 | return 292 | }; 293 | let neuron = neuronDb.findNeuron(addr); 294 | switch (neuron) { 295 | case (null) { }; 296 | case (?neuron) { 297 | if (i > 0) { 298 | fullResultStr #= ","; 299 | }; 300 | i += 1; 301 | 302 | str := "{\n\"Account\": \"" # addr # "\",\n\"Votes\": \"" # Nat64.toText(neuron.selfStaking + neuron.totalDelegations) # "\"\n}"; 303 | fullResultStr #= str; 304 | }; 305 | }; 306 | }; 307 | List.iterate<(Text, Bool)>(existing.votes, getApprovals); 308 | 309 | fullResultStr #= "]"; 310 | return fullResultStr 311 | }; 312 | }; 313 | }; 314 | 315 | public shared query func getProposalDisapprovals(id: Text): async Text { 316 | let existing = proposaldb.findProposalByID(id); 317 | switch (existing) { 318 | case (null) { "" }; 319 | case (?existing) { 320 | var fullResultStr = "["; 321 | 322 | var str = ""; 323 | var i = 0; 324 | func getDisapprovals((addr, approve): (Text, Bool)) { 325 | if (approve == true) { 326 | return 327 | }; 328 | let neuron = neuronDb.findNeuron(addr); 329 | switch (neuron) { 330 | case (null) { }; 331 | case (?neuron) { 332 | if (i > 0) { 333 | fullResultStr #= ","; 334 | }; 335 | i += 1; 336 | 337 | str := "{\n\"Account\": \"" # addr # "\",\n\"Votes\": \"" # Nat64.toText(neuron.selfStaking + neuron.totalDelegations) # "\"\n}"; 338 | fullResultStr #= str; 339 | }; 340 | }; 341 | }; 342 | List.iterate<(Text, Bool)>(existing.votes, getDisapprovals); 343 | 344 | fullResultStr #= "]"; 345 | return fullResultStr 346 | }; 347 | }; 348 | }; 349 | 350 | public shared query func getProposalList(): async Text { 351 | var results = proposaldb.findList(); 352 | var fullResultStr = "["; 353 | var i = 0; 354 | for (result in results.vals()) { 355 | if (i > 0) { 356 | fullResultStr #= ","; 357 | }; 358 | i += 1; 359 | 360 | let (account, time) = result.created; 361 | let str = "{\n\"Title\": \"" # result.title # "\",\n\"Created By\": \"" # account # "\",\n\"Create Time\": \"" # Int.toText(time) # "\",\n\"Proposal ID\": \"" # proposaldb.calProposalID(result) # "\",\n\"Status\": \"" # result.status # "\",\n\"Excution Time\": \"" # Int.toText(result.excutionTime) # "\"\n}"; 362 | fullResultStr #= str; 363 | }; 364 | fullResultStr #= "]"; 365 | return fullResultStr; 366 | }; 367 | 368 | // nnsexplorer_sim for test 369 | 370 | public shared func signupTest(account: DFNAccount): async () { 371 | accountDb.createAccount(account) 372 | }; 373 | 374 | public shared func signupTests(accounts: [DFNAccount]): async () { 375 | for (account in accounts.vals()) { 376 | accountDb.createAccount(account); 377 | }; 378 | }; 379 | 380 | public shared(msg) func createTestNeuron(newNeuron: NewNeuron): async () { 381 | neuronDb.createNeuron(newNeuron) 382 | }; 383 | 384 | public shared(msg) func createTestNeurons(newNeurons: [NewNeuron]): async () { 385 | for (neuron in newNeurons.vals()) { 386 | neuronDb.createNeuron(neuron); 387 | }; 388 | }; 389 | 390 | public query func getNeuronListTest(): async [Neuron] { 391 | neuronDb.findList() 392 | }; 393 | 394 | public shared(msg) func createProposalTest(newProposal: NewDFNProposal): async () { 395 | proposaldb.createProposal(newProposal); 396 | }; 397 | 398 | public shared(msg) func createProposalsTest(newProposals: [NewDFNProposal]): async () { 399 | for (newProposal in newProposals.vals()) { 400 | proposaldb.createProposal(newProposal); 401 | }; 402 | }; 403 | 404 | // User Auth 405 | 406 | public shared query(msg) func getOwnId(): async Principal { msg.caller }; 407 | }; 408 | -------------------------------------------------------------------------------- /src/nnsexplorer/types.mo: -------------------------------------------------------------------------------- 1 | import Assoc "mo:base/AssocList"; 2 | 3 | module { 4 | public type DFNAccount = { 5 | accountAddr: Text; 6 | signature: Text; 7 | balance: Nat64; 8 | rewards: Nat64; 9 | 10 | isDelegator: Bool; 11 | }; 12 | 13 | public type NewNeuron = { 14 | accountAddr: Text; 15 | description: Text; 16 | commissionRate: Nat; 17 | selfStaking: Nat64; 18 | }; 19 | 20 | public type Neuron = { 21 | accountAddr: Text; 22 | description: Text; 23 | commissionRate: Nat; 24 | selfStaking: Nat64; 25 | totalDelegations: Nat64; 26 | delegations: Assoc.AssocList; 27 | }; 28 | 29 | type Time = Int; 30 | public type NewDFNProposal = { 31 | title: Text; 32 | details: Text; 33 | createdBy: Text; 34 | excutionTime: Time; 35 | }; 36 | 37 | public type DFNProposal = { 38 | title: Text; 39 | details: Text; 40 | created: (Text, Time); 41 | votes: Assoc.AssocList; 42 | excutionTime: Time; 43 | status: Text; // "active", "passed", "failed", "excuted" 44 | }; 45 | }; 46 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/.gitignore: -------------------------------------------------------------------------------- 1 | .dfx 2 | build 3 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | install: 3 | - travis_retry wget https://sdk.dfinity.org/install.sh 4 | - yes Y | sh install.sh 5 | script: 6 | - dfx start & 7 | - sleep 5 8 | - dfx build 9 | - dfx canister install --all 10 | - dfx canister call test run 11 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the 13 | copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other 16 | entities that control, are controlled by, or are under common control with 17 | that entity. For the purposes of this definition, "control" means (i) the 18 | power, direct or indirect, to cause the direction or management of such 19 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 20 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of 21 | such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation source, and 28 | configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation 31 | or translation of a Source form, including but not limited to compiled 32 | object code, generated documentation, and conversions to other media types. 33 | 34 | "Work" shall mean the work of authorship, whether in Source or Object form, 35 | made available under the License, as indicated by a copyright notice that is 36 | included in or attached to the work (an example is provided in the Appendix 37 | below). 38 | 39 | "Derivative Works" shall mean any work, whether in Source or Object form, 40 | that is based on (or derived from) the Work and for which the editorial 41 | revisions, annotations, elaborations, or other modifications represent, as a 42 | whole, an original work of authorship. For the purposes of this License, 43 | Derivative Works shall not include works that remain separable from, or 44 | merely link (or bind by name) to the interfaces of, the Work and Derivative 45 | Works thereof. 46 | 47 | "Contribution" shall mean any work of authorship, including the original 48 | version of the Work and any modifications or additions to that Work or 49 | Derivative Works thereof, that is intentionally submitted to Licensor for 50 | inclusion in the Work by the copyright owner or by an individual or Legal 51 | Entity authorized to submit on behalf of the copyright owner. For the 52 | purposes of this definition, "submitted" means any form of electronic, 53 | verbal, or written communication sent to the Licensor or its 54 | representatives, including but not limited to communication on electronic 55 | mailing lists, source code control systems, and issue tracking systems that 56 | are managed by, or on behalf of, the Licensor for the purpose of discussing 57 | and improving the Work, but excluding communication that is conspicuously 58 | marked or otherwise designated in writing by the copyright owner as "Not a 59 | Contribution." 60 | 61 | "Contributor" shall mean Licensor and any individual or Legal Entity on 62 | behalf of whom a Contribution has been received by Licensor and subsequently 63 | incorporated within the Work. 64 | 65 | 2. Grant of Copyright License. Subject to the terms and conditions of this 66 | License, each Contributor hereby grants to You a perpetual, worldwide, 67 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 68 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 69 | sublicense, and distribute the Work and such Derivative Works in Source or 70 | Object form. 71 | 72 | 3. Grant of Patent License. Subject to the terms and conditions of this 73 | License, each Contributor hereby grants to You a perpetual, worldwide, 74 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 75 | this section) patent license to make, have made, use, offer to sell, sell, 76 | import, and otherwise transfer the Work, where such license applies only to 77 | those patent claims licensable by such Contributor that are necessarily 78 | infringed by their Contribution(s) alone or by combination of their 79 | Contribution(s) with the Work to which such Contribution(s) was submitted. 80 | If You institute patent litigation against any entity (including a 81 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 82 | Contribution incorporated within the Work constitutes direct or contributory 83 | patent infringement, then any patent licenses granted to You under this 84 | License for that Work shall terminate as of the date such litigation is 85 | filed. 86 | 87 | 4. Redistribution. You may reproduce and distribute copies of the Work or 88 | Derivative Works thereof in any medium, with or without modifications, and 89 | in Source or Object form, provided that You meet the following conditions: 90 | 91 | a. You must give any other recipients of the Work or Derivative Works a 92 | copy of this License; and 93 | 94 | b. You must cause any modified files to carry prominent notices stating 95 | that You changed the files; and 96 | 97 | c. You must retain, in the Source form of any Derivative Works that You 98 | distribute, all copyright, patent, trademark, and attribution notices 99 | from the Source form of the Work, excluding those notices that do not 100 | pertain to any part of the Derivative Works; and 101 | 102 | d. If the Work includes a "NOTICE" text file as part of its distribution, 103 | then any Derivative Works that You distribute must include a readable 104 | copy of the attribution notices contained within such NOTICE file, 105 | excluding those notices that do not pertain to any part of the Derivative 106 | Works, in at least one of the following places: within a NOTICE text file 107 | distributed as part of the Derivative Works; within the Source form or 108 | documentation, if provided along with the Derivative Works; or, within a 109 | display generated by the Derivative Works, if and wherever such 110 | third-party notices normally appear. The contents of the NOTICE file are 111 | for informational purposes only and do not modify the License. You may 112 | add Your own attribution notices within Derivative Works that You 113 | distribute, alongside or as an addendum to the NOTICE text from the Work, 114 | provided that such additional attribution notices cannot be construed as 115 | modifying the License. 116 | 117 | You may add Your own copyright statement to Your modifications and may 118 | provide additional or different license terms and conditions for use, 119 | reproduction, or distribution of Your modifications, or for any such 120 | Derivative Works as a whole, provided Your use, reproduction, and 121 | distribution of the Work otherwise complies with the conditions stated in 122 | this License. 123 | 124 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 125 | Contribution intentionally submitted for inclusion in the Work by You to the 126 | Licensor shall be under the terms and conditions of this License, without 127 | any additional terms or conditions. Notwithstanding the above, nothing 128 | herein shall supersede or modify the terms of any separate license agreement 129 | you may have executed with Licensor regarding such Contributions. 130 | 131 | 6. Trademarks. This License does not grant permission to use the trade names, 132 | trademarks, service marks, or product names of the Licensor, except as 133 | required for reasonable and customary use in describing the origin of the 134 | Work and reproducing the content of the NOTICE file. 135 | 136 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 137 | writing, Licensor provides the Work (and each Contributor provides its 138 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 139 | KIND, either express or implied, including, without limitation, any 140 | warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or 141 | FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining 142 | the appropriateness of using or redistributing the Work and assume any risks 143 | associated with Your exercise of permissions under this License. 144 | 145 | 8. Limitation of Liability. In no event and under no legal theory, whether in 146 | tort (including negligence), contract, or otherwise, unless required by 147 | applicable law (such as deliberate and grossly negligent acts) or agreed to 148 | in writing, shall any Contributor be liable to You for damages, including 149 | any direct, indirect, special, incidental, or consequential damages of any 150 | character arising as a result of this License or out of the use or inability 151 | to use the Work (including but not limited to damages for loss of goodwill, 152 | work stoppage, computer failure or malfunction, or any and all other 153 | commercial damages or losses), even if such Contributor has been advised of 154 | the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 157 | Derivative Works thereof, You may choose to offer, and charge a fee for, 158 | acceptance of support, warranty, indemnity, or other liability obligations 159 | and/or rights consistent with this License. However, in accepting such 160 | obligations, You may act only on Your own behalf and on Your sole 161 | responsibility, not on behalf of any other Contributor, and only if You 162 | agree to indemnify, defend, and hold each Contributor harmless for any 163 | liability incurred by, or claims asserted against, such Contributor by 164 | reason of your accepting any such warranty or additional liability. 165 | 166 | END OF TERMS AND CONDITIONS 167 | 168 | LLVM EXCEPTION TO THE APACHE 2.0 LICENSE 169 | 170 | As an exception, if, as a result of your compiling your source code, portions 171 | of this Software are embedded into an Object form of such source code, you may 172 | redistribute such embedded portions in such Object form without complying with 173 | the conditions of Sections 4(a), 4(b) and 4(d) of the License. 174 | 175 | In addition, if you combine or link compiled forms of this Software with 176 | software that is licensed under the GPLv2 ("Combined Software") and if a court 177 | of competent jurisdiction determines that the patent provision (Section 3), the 178 | indemnity provision (Section 9) or other Section of the License conflicts with 179 | the conditions of the GPLv2, you may retroactively and prospectively choose to 180 | deem waived or otherwise exclude such Section(s) of the License, but only in 181 | their entirety and only with respect to the Combined Software. 182 | 183 | END OF LLVM EXCEPTION 184 | 185 | APPENDIX: How to apply the Apache License to your work. 186 | 187 | To apply the Apache License to your work, attach the following boilerplate 188 | notice, with the fields enclosed by brackets "[]" replaced with your own 189 | identifying information. (Don't include the brackets!) The text should be 190 | enclosed in the appropriate comment syntax for the file format. We also 191 | recommend that a file or class name and description of purpose be included on 192 | the same "printed page" as the copyright notice for easier identification 193 | within third-party archives. 194 | 195 | Copyright [yyyy] [name of copyright owner] 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 198 | this file except in compliance with the License. You may obtain a copy of the 199 | License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software distributed 204 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 205 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 206 | specific language governing permissions and limitations under the License. 207 | 208 | END OF APPENDIX 209 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Enzo Haussecker 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/README.md: -------------------------------------------------------------------------------- 1 | ## The Motoko CRC Package 2 | 3 | [![Build Status](https://travis-ci.org/enzoh/motoko-crc.svg?branch=master)](https://travis-ci.org/enzoh/motoko-crc?branch=master) 4 | 5 | ### Overview 6 | 7 | This package implements cyclic redundancy checks. 8 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "test": { 4 | "main": "test/Main.mo" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/src/CRC8.mo: -------------------------------------------------------------------------------- 1 | /** 2 | * Module : CRC8.mo 3 | * Description : 8-bit cyclic redundancy check. 4 | * Copyright : 2020 Enzo Haussecker 5 | * License : Apache 2.0 with LLVM Exception 6 | * Maintainer : Enzo Haussecker 7 | * Stability : Stable 8 | */ 9 | 10 | import Prim "mo:prim"; 11 | 12 | module { 13 | 14 | private let table : [Word8] = [ 15 | 000, 007, 014, 009, 028, 027, 018, 021, 16 | 056, 063, 054, 049, 036, 035, 042, 045, 17 | 112, 119, 126, 121, 108, 107, 098, 101, 18 | 072, 079, 070, 065, 084, 083, 090, 093, 19 | 224, 231, 238, 233, 252, 251, 242, 245, 20 | 216, 223, 214, 209, 196, 195, 202, 205, 21 | 144, 151, 158, 153, 140, 139, 130, 133, 22 | 168, 175, 166, 161, 180, 179, 186, 189, 23 | 199, 192, 201, 206, 219, 220, 213, 210, 24 | 255, 248, 241, 246, 227, 228, 237, 234, 25 | 183, 176, 185, 190, 171, 172, 165, 162, 26 | 143, 136, 129, 134, 147, 148, 157, 154, 27 | 039, 032, 041, 046, 059, 060, 053, 050, 28 | 031, 024, 017, 022, 003, 004, 013, 010, 29 | 087, 080, 089, 094, 075, 076, 069, 066, 30 | 111, 104, 097, 102, 115, 116, 125, 122, 31 | 137, 142, 135, 128, 149, 146, 155, 156, 32 | 177, 182, 191, 184, 173, 170, 163, 164, 33 | 249, 254, 247, 240, 229, 226, 235, 236, 34 | 193, 198, 207, 200, 221, 218, 211, 212, 35 | 105, 110, 103, 096, 117, 114, 123, 124, 36 | 081, 086, 095, 088, 077, 074, 067, 068, 37 | 025, 030, 023, 016, 005, 002, 011, 012, 38 | 033, 038, 047, 040, 061, 058, 051, 052, 39 | 078, 073, 064, 071, 082, 085, 092, 091, 40 | 118, 113, 120, 127, 106, 109, 100, 099, 41 | 062, 057, 048, 055, 034, 037, 044, 043, 42 | 006, 001, 008, 015, 026, 029, 020, 019, 43 | 174, 169, 160, 167, 178, 181, 188, 187, 44 | 150, 145, 152, 159, 138, 141, 132, 131, 45 | 222, 217, 208, 215, 194, 197, 204, 203, 46 | 230, 225, 232, 239, 250, 253, 244, 243, 47 | ]; 48 | 49 | public func crc8(data : [Word8]) : Word8 { 50 | var result : Word8 = 0; 51 | for (byte in data.vals()) { 52 | result := table[Prim.word8ToNat(result ^ byte)]; 53 | }; 54 | return result; 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/crc/test/Main.mo: -------------------------------------------------------------------------------- 1 | /** 2 | * Module : Main.mo 3 | * Description : Unit tests. 4 | * Copyright : 2020 Enzo Haussecker 5 | * License : Apache 2.0 with LLVM Exception 6 | * Maintainer : Enzo Haussecker 7 | * Stability : Stable 8 | */ 9 | 10 | import CRC8 "../src/CRC8"; 11 | 12 | actor { 13 | 14 | private let tests = [ 15 | { 16 | data = [ 17 | ] : [Word8]; 18 | expect = 000 : Word8; 19 | }, 20 | { 21 | data = [ 22 | 072, 101, 108, 108, 111, 032, 087, 111, 23 | 114, 108, 100, 24 | ] : [Word8]; 25 | expect = 037 : Word8; 26 | }, 27 | ]; 28 | 29 | public func run() { 30 | for (test in tests.vals()) { 31 | let expect = test.expect; 32 | let actual = CRC8.crc8(test.data); 33 | assert(expect == actual); 34 | }; 35 | }; 36 | }; 37 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/.gitignore: -------------------------------------------------------------------------------- 1 | .dfx/ 2 | build/ 3 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | install: 3 | - travis_retry wget https://sdk.dfinity.org/install.sh 4 | - yes Y | sh install.sh 5 | script: 6 | - dfx start & 7 | - sleep 5 8 | - dfx build 9 | - dfx canister install --all 10 | - dfx canister call test run 11 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the 13 | copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other 16 | entities that control, are controlled by, or are under common control with 17 | that entity. For the purposes of this definition, "control" means (i) the 18 | power, direct or indirect, to cause the direction or management of such 19 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 20 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of 21 | such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation source, and 28 | configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation 31 | or translation of a Source form, including but not limited to compiled 32 | object code, generated documentation, and conversions to other media types. 33 | 34 | "Work" shall mean the work of authorship, whether in Source or Object form, 35 | made available under the License, as indicated by a copyright notice that is 36 | included in or attached to the work (an example is provided in the Appendix 37 | below). 38 | 39 | "Derivative Works" shall mean any work, whether in Source or Object form, 40 | that is based on (or derived from) the Work and for which the editorial 41 | revisions, annotations, elaborations, or other modifications represent, as a 42 | whole, an original work of authorship. For the purposes of this License, 43 | Derivative Works shall not include works that remain separable from, or 44 | merely link (or bind by name) to the interfaces of, the Work and Derivative 45 | Works thereof. 46 | 47 | "Contribution" shall mean any work of authorship, including the original 48 | version of the Work and any modifications or additions to that Work or 49 | Derivative Works thereof, that is intentionally submitted to Licensor for 50 | inclusion in the Work by the copyright owner or by an individual or Legal 51 | Entity authorized to submit on behalf of the copyright owner. For the 52 | purposes of this definition, "submitted" means any form of electronic, 53 | verbal, or written communication sent to the Licensor or its 54 | representatives, including but not limited to communication on electronic 55 | mailing lists, source code control systems, and issue tracking systems that 56 | are managed by, or on behalf of, the Licensor for the purpose of discussing 57 | and improving the Work, but excluding communication that is conspicuously 58 | marked or otherwise designated in writing by the copyright owner as "Not a 59 | Contribution." 60 | 61 | "Contributor" shall mean Licensor and any individual or Legal Entity on 62 | behalf of whom a Contribution has been received by Licensor and subsequently 63 | incorporated within the Work. 64 | 65 | 2. Grant of Copyright License. Subject to the terms and conditions of this 66 | License, each Contributor hereby grants to You a perpetual, worldwide, 67 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 68 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 69 | sublicense, and distribute the Work and such Derivative Works in Source or 70 | Object form. 71 | 72 | 3. Grant of Patent License. Subject to the terms and conditions of this 73 | License, each Contributor hereby grants to You a perpetual, worldwide, 74 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 75 | this section) patent license to make, have made, use, offer to sell, sell, 76 | import, and otherwise transfer the Work, where such license applies only to 77 | those patent claims licensable by such Contributor that are necessarily 78 | infringed by their Contribution(s) alone or by combination of their 79 | Contribution(s) with the Work to which such Contribution(s) was submitted. 80 | If You institute patent litigation against any entity (including a 81 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 82 | Contribution incorporated within the Work constitutes direct or contributory 83 | patent infringement, then any patent licenses granted to You under this 84 | License for that Work shall terminate as of the date such litigation is 85 | filed. 86 | 87 | 4. Redistribution. You may reproduce and distribute copies of the Work or 88 | Derivative Works thereof in any medium, with or without modifications, and 89 | in Source or Object form, provided that You meet the following conditions: 90 | 91 | a. You must give any other recipients of the Work or Derivative Works a 92 | copy of this License; and 93 | 94 | b. You must cause any modified files to carry prominent notices stating 95 | that You changed the files; and 96 | 97 | c. You must retain, in the Source form of any Derivative Works that You 98 | distribute, all copyright, patent, trademark, and attribution notices 99 | from the Source form of the Work, excluding those notices that do not 100 | pertain to any part of the Derivative Works; and 101 | 102 | d. If the Work includes a "NOTICE" text file as part of its distribution, 103 | then any Derivative Works that You distribute must include a readable 104 | copy of the attribution notices contained within such NOTICE file, 105 | excluding those notices that do not pertain to any part of the Derivative 106 | Works, in at least one of the following places: within a NOTICE text file 107 | distributed as part of the Derivative Works; within the Source form or 108 | documentation, if provided along with the Derivative Works; or, within a 109 | display generated by the Derivative Works, if and wherever such 110 | third-party notices normally appear. The contents of the NOTICE file are 111 | for informational purposes only and do not modify the License. You may 112 | add Your own attribution notices within Derivative Works that You 113 | distribute, alongside or as an addendum to the NOTICE text from the Work, 114 | provided that such additional attribution notices cannot be construed as 115 | modifying the License. 116 | 117 | You may add Your own copyright statement to Your modifications and may 118 | provide additional or different license terms and conditions for use, 119 | reproduction, or distribution of Your modifications, or for any such 120 | Derivative Works as a whole, provided Your use, reproduction, and 121 | distribution of the Work otherwise complies with the conditions stated in 122 | this License. 123 | 124 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 125 | Contribution intentionally submitted for inclusion in the Work by You to the 126 | Licensor shall be under the terms and conditions of this License, without 127 | any additional terms or conditions. Notwithstanding the above, nothing 128 | herein shall supersede or modify the terms of any separate license agreement 129 | you may have executed with Licensor regarding such Contributions. 130 | 131 | 6. Trademarks. This License does not grant permission to use the trade names, 132 | trademarks, service marks, or product names of the Licensor, except as 133 | required for reasonable and customary use in describing the origin of the 134 | Work and reproducing the content of the NOTICE file. 135 | 136 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 137 | writing, Licensor provides the Work (and each Contributor provides its 138 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 139 | KIND, either express or implied, including, without limitation, any 140 | warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or 141 | FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining 142 | the appropriateness of using or redistributing the Work and assume any risks 143 | associated with Your exercise of permissions under this License. 144 | 145 | 8. Limitation of Liability. In no event and under no legal theory, whether in 146 | tort (including negligence), contract, or otherwise, unless required by 147 | applicable law (such as deliberate and grossly negligent acts) or agreed to 148 | in writing, shall any Contributor be liable to You for damages, including 149 | any direct, indirect, special, incidental, or consequential damages of any 150 | character arising as a result of this License or out of the use or inability 151 | to use the Work (including but not limited to damages for loss of goodwill, 152 | work stoppage, computer failure or malfunction, or any and all other 153 | commercial damages or losses), even if such Contributor has been advised of 154 | the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 157 | Derivative Works thereof, You may choose to offer, and charge a fee for, 158 | acceptance of support, warranty, indemnity, or other liability obligations 159 | and/or rights consistent with this License. However, in accepting such 160 | obligations, You may act only on Your own behalf and on Your sole 161 | responsibility, not on behalf of any other Contributor, and only if You 162 | agree to indemnify, defend, and hold each Contributor harmless for any 163 | liability incurred by, or claims asserted against, such Contributor by 164 | reason of your accepting any such warranty or additional liability. 165 | 166 | END OF TERMS AND CONDITIONS 167 | 168 | LLVM EXCEPTION TO THE APACHE 2.0 LICENSE 169 | 170 | As an exception, if, as a result of your compiling your source code, portions 171 | of this Software are embedded into an Object form of such source code, you may 172 | redistribute such embedded portions in such Object form without complying with 173 | the conditions of Sections 4(a), 4(b) and 4(d) of the License. 174 | 175 | In addition, if you combine or link compiled forms of this Software with 176 | software that is licensed under the GPLv2 ("Combined Software") and if a court 177 | of competent jurisdiction determines that the patent provision (Section 3), the 178 | indemnity provision (Section 9) or other Section of the License conflicts with 179 | the conditions of the GPLv2, you may retroactively and prospectively choose to 180 | deem waived or otherwise exclude such Section(s) of the License, but only in 181 | their entirety and only with respect to the Combined Software. 182 | 183 | END OF LLVM EXCEPTION 184 | 185 | APPENDIX: How to apply the Apache License to your work. 186 | 187 | To apply the Apache License to your work, attach the following boilerplate 188 | notice, with the fields enclosed by brackets "[]" replaced with your own 189 | identifying information. (Don't include the brackets!) The text should be 190 | enclosed in the appropriate comment syntax for the file format. We also 191 | recommend that a file or class name and description of purpose be included on 192 | the same "printed page" as the copyright notice for easier identification 193 | within third-party archives. 194 | 195 | Copyright [yyyy] [name of copyright owner] 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 198 | this file except in compliance with the License. You may obtain a copy of the 199 | License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software distributed 204 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 205 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 206 | specific language governing permissions and limitations under the License. 207 | 208 | END OF APPENDIX 209 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Enzo Haussecker 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/README.md: -------------------------------------------------------------------------------- 1 | ## The Hex Package 2 | 3 | [![Build Status](https://travis-ci.org/enzoh/motoko-hex.svg?branch=master)](https://travis-ci.org/enzoh/motoko-hex?branch=master) 4 | 5 | ### Overview 6 | 7 | This package implements hexadecimal encoding and decoding routines for the 8 | Motoko programming language. 9 | 10 | ### Usage 11 | 12 | Encode an array of unsigned 8-bit integers in hexadecimal format. 13 | ```motoko 14 | public func encode(array : [Word8]) : Text 15 | ``` 16 | 17 | Decode an array of unsigned 8-bit integers in hexadecimal format. 18 | ```motoko 19 | public func decode(text : Text) : Result<[Word8], DecodeError> 20 | ``` 21 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "test": { 4 | "main": "test/Main.mo" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/src/Hex.mo: -------------------------------------------------------------------------------- 1 | /** 2 | * Module : Hex.mo 3 | * Description : Hexadecimal encoding and decoding routines. 4 | * Copyright : 2020 Enzo Haussecker 5 | * License : Apache 2.0 with LLVM Exception 6 | * Maintainer : Enzo Haussecker 7 | * Stability : Stable 8 | */ 9 | 10 | import Array "mo:base/Array"; 11 | import Iter "mo:base/Iter"; 12 | import Option "mo:base/Option"; 13 | import Prim "mo:prim"; 14 | import Result "mo:base/Result"; 15 | 16 | module { 17 | 18 | private type Result = Result.Result; 19 | 20 | private let base : Word8 = 0x10; 21 | 22 | private let symbols = [ 23 | '0', '1', '2', '3', '4', '5', '6', '7', 24 | '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 25 | ]; 26 | 27 | /** 28 | * Define a type to indicate that the decoder has failed. 29 | */ 30 | public type DecodeError = { 31 | #msg : Text; 32 | }; 33 | 34 | /** 35 | * Encode an array of unsigned 8-bit integers in hexadecimal format. 36 | */ 37 | public func encode(array : [Word8]) : Text { 38 | Array.foldLeft(array, "", func (accum, w8) { 39 | accum # encodeW8(w8); 40 | }); 41 | }; 42 | 43 | /** 44 | * Encode an unsigned 8-bit integer in hexadecimal format. 45 | */ 46 | private func encodeW8(w8 : Word8) : Text { 47 | let c1 = symbols[Prim.word8ToNat(w8 / base)]; 48 | let c2 = symbols[Prim.word8ToNat(w8 % base)]; 49 | Prim.charToText(c1) # Prim.charToText(c2); 50 | }; 51 | 52 | /** 53 | * Decode an array of unsigned 8-bit integers in hexadecimal format. 54 | */ 55 | public func decode(text : Text) : Result<[Word8], DecodeError> { 56 | let next = text.chars().next; 57 | func parse() : Result { 58 | Option.get>( 59 | Option.chain>(next(), func (c1) { 60 | Option.chain>(next(), func (c2) {? 61 | Result.chain(decodeW4(c1), func (x1) { 62 | Result.chain(decodeW4(c2), func (x2) { 63 | #ok (x1 * base + x2); 64 | }); 65 | }); 66 | }); 67 | }), 68 | #err (#msg "Not enough input!"), 69 | ); 70 | }; 71 | var i = 0; 72 | let n = text.size() / 2 + text.size() % 2; 73 | let array = Array.init(n, 0); 74 | while (i != n) { 75 | switch (parse()) { 76 | case (#ok w8) { 77 | array[i] := w8; 78 | i += 1; 79 | }; 80 | case (#err err) { 81 | return #err err; 82 | }; 83 | }; 84 | }; 85 | #ok (Array.freeze(array)); 86 | }; 87 | 88 | /** 89 | * Decode an unsigned 4-bit integer in hexadecimal format. 90 | */ 91 | private func decodeW4(char : Char) : Result { 92 | for (i in Iter.range(0, 15)) { 93 | if (symbols[i] == char) { 94 | return #ok (Prim.natToWord8(i)); 95 | }; 96 | }; 97 | let str = "Unexpected character: " # Prim.charToText(char); 98 | #err (#msg str); 99 | }; 100 | }; -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/hex/test/Main.mo: -------------------------------------------------------------------------------- 1 | /** 2 | * Module : Main.mo 3 | * Description : Unit tests. 4 | * Copyright : 2020 DFINITY Stiftung 5 | * License : Apache 2.0 with LLVM Exception 6 | * Maintainer : Enzo Haussecker 7 | * Stability : Stable 8 | */ 9 | 10 | import Array "mo:base/Array"; 11 | import Hex "../src/Hex"; 12 | import Result "mo:base/Result"; 13 | 14 | actor { 15 | 16 | private type Result = Result.Result; 17 | 18 | private func eq(a : Word8, b : Word8) : Bool { 19 | a == b; 20 | }; 21 | 22 | private func unwrap(result : Result<[Word8], Hex.DecodeError>) : [Word8] { 23 | Result.unwrapOk<[Word8], Hex.DecodeError>(result); 24 | }; 25 | 26 | public func run() { 27 | let data : [Word8] = [ 28 | 072, 101, 108, 108, 111, 032, 087, 111, 29 | 114, 108, 100, 30 | ]; 31 | let expect = #ok data; 32 | let actual = Hex.decode(Hex.encode(data)); 33 | assert(Array.equal(unwrap(expect), unwrap(actual), eq)); 34 | }; 35 | }; -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/.gitignore: -------------------------------------------------------------------------------- 1 | .dfx/ 2 | build/ 3 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/.travis.yml: -------------------------------------------------------------------------------- 1 | dist: bionic 2 | install: 3 | - travis_retry wget https://sdk.dfinity.org/install.sh 4 | - yes Y | sh install.sh 5 | script: 6 | - dfx start & 7 | - sleep 5 8 | - dfx build 9 | - dfx canister install --all 10 | - dfx canister call test run 11 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the 13 | copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other 16 | entities that control, are controlled by, or are under common control with 17 | that entity. For the purposes of this definition, "control" means (i) the 18 | power, direct or indirect, to cause the direction or management of such 19 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 20 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of 21 | such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity exercising 24 | permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation source, and 28 | configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical transformation 31 | or translation of a Source form, including but not limited to compiled 32 | object code, generated documentation, and conversions to other media types. 33 | 34 | "Work" shall mean the work of authorship, whether in Source or Object form, 35 | made available under the License, as indicated by a copyright notice that is 36 | included in or attached to the work (an example is provided in the Appendix 37 | below). 38 | 39 | "Derivative Works" shall mean any work, whether in Source or Object form, 40 | that is based on (or derived from) the Work and for which the editorial 41 | revisions, annotations, elaborations, or other modifications represent, as a 42 | whole, an original work of authorship. For the purposes of this License, 43 | Derivative Works shall not include works that remain separable from, or 44 | merely link (or bind by name) to the interfaces of, the Work and Derivative 45 | Works thereof. 46 | 47 | "Contribution" shall mean any work of authorship, including the original 48 | version of the Work and any modifications or additions to that Work or 49 | Derivative Works thereof, that is intentionally submitted to Licensor for 50 | inclusion in the Work by the copyright owner or by an individual or Legal 51 | Entity authorized to submit on behalf of the copyright owner. For the 52 | purposes of this definition, "submitted" means any form of electronic, 53 | verbal, or written communication sent to the Licensor or its 54 | representatives, including but not limited to communication on electronic 55 | mailing lists, source code control systems, and issue tracking systems that 56 | are managed by, or on behalf of, the Licensor for the purpose of discussing 57 | and improving the Work, but excluding communication that is conspicuously 58 | marked or otherwise designated in writing by the copyright owner as "Not a 59 | Contribution." 60 | 61 | "Contributor" shall mean Licensor and any individual or Legal Entity on 62 | behalf of whom a Contribution has been received by Licensor and subsequently 63 | incorporated within the Work. 64 | 65 | 2. Grant of Copyright License. Subject to the terms and conditions of this 66 | License, each Contributor hereby grants to You a perpetual, worldwide, 67 | non-exclusive, no-charge, royalty-free, irrevocable copyright license to 68 | reproduce, prepare Derivative Works of, publicly display, publicly perform, 69 | sublicense, and distribute the Work and such Derivative Works in Source or 70 | Object form. 71 | 72 | 3. Grant of Patent License. Subject to the terms and conditions of this 73 | License, each Contributor hereby grants to You a perpetual, worldwide, 74 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in 75 | this section) patent license to make, have made, use, offer to sell, sell, 76 | import, and otherwise transfer the Work, where such license applies only to 77 | those patent claims licensable by such Contributor that are necessarily 78 | infringed by their Contribution(s) alone or by combination of their 79 | Contribution(s) with the Work to which such Contribution(s) was submitted. 80 | If You institute patent litigation against any entity (including a 81 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 82 | Contribution incorporated within the Work constitutes direct or contributory 83 | patent infringement, then any patent licenses granted to You under this 84 | License for that Work shall terminate as of the date such litigation is 85 | filed. 86 | 87 | 4. Redistribution. You may reproduce and distribute copies of the Work or 88 | Derivative Works thereof in any medium, with or without modifications, and 89 | in Source or Object form, provided that You meet the following conditions: 90 | 91 | a. You must give any other recipients of the Work or Derivative Works a 92 | copy of this License; and 93 | 94 | b. You must cause any modified files to carry prominent notices stating 95 | that You changed the files; and 96 | 97 | c. You must retain, in the Source form of any Derivative Works that You 98 | distribute, all copyright, patent, trademark, and attribution notices 99 | from the Source form of the Work, excluding those notices that do not 100 | pertain to any part of the Derivative Works; and 101 | 102 | d. If the Work includes a "NOTICE" text file as part of its distribution, 103 | then any Derivative Works that You distribute must include a readable 104 | copy of the attribution notices contained within such NOTICE file, 105 | excluding those notices that do not pertain to any part of the Derivative 106 | Works, in at least one of the following places: within a NOTICE text file 107 | distributed as part of the Derivative Works; within the Source form or 108 | documentation, if provided along with the Derivative Works; or, within a 109 | display generated by the Derivative Works, if and wherever such 110 | third-party notices normally appear. The contents of the NOTICE file are 111 | for informational purposes only and do not modify the License. You may 112 | add Your own attribution notices within Derivative Works that You 113 | distribute, alongside or as an addendum to the NOTICE text from the Work, 114 | provided that such additional attribution notices cannot be construed as 115 | modifying the License. 116 | 117 | You may add Your own copyright statement to Your modifications and may 118 | provide additional or different license terms and conditions for use, 119 | reproduction, or distribution of Your modifications, or for any such 120 | Derivative Works as a whole, provided Your use, reproduction, and 121 | distribution of the Work otherwise complies with the conditions stated in 122 | this License. 123 | 124 | 5. Submission of Contributions. Unless You explicitly state otherwise, any 125 | Contribution intentionally submitted for inclusion in the Work by You to the 126 | Licensor shall be under the terms and conditions of this License, without 127 | any additional terms or conditions. Notwithstanding the above, nothing 128 | herein shall supersede or modify the terms of any separate license agreement 129 | you may have executed with Licensor regarding such Contributions. 130 | 131 | 6. Trademarks. This License does not grant permission to use the trade names, 132 | trademarks, service marks, or product names of the Licensor, except as 133 | required for reasonable and customary use in describing the origin of the 134 | Work and reproducing the content of the NOTICE file. 135 | 136 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in 137 | writing, Licensor provides the Work (and each Contributor provides its 138 | Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 139 | KIND, either express or implied, including, without limitation, any 140 | warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or 141 | FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining 142 | the appropriateness of using or redistributing the Work and assume any risks 143 | associated with Your exercise of permissions under this License. 144 | 145 | 8. Limitation of Liability. In no event and under no legal theory, whether in 146 | tort (including negligence), contract, or otherwise, unless required by 147 | applicable law (such as deliberate and grossly negligent acts) or agreed to 148 | in writing, shall any Contributor be liable to You for damages, including 149 | any direct, indirect, special, incidental, or consequential damages of any 150 | character arising as a result of this License or out of the use or inability 151 | to use the Work (including but not limited to damages for loss of goodwill, 152 | work stoppage, computer failure or malfunction, or any and all other 153 | commercial damages or losses), even if such Contributor has been advised of 154 | the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or 157 | Derivative Works thereof, You may choose to offer, and charge a fee for, 158 | acceptance of support, warranty, indemnity, or other liability obligations 159 | and/or rights consistent with this License. However, in accepting such 160 | obligations, You may act only on Your own behalf and on Your sole 161 | responsibility, not on behalf of any other Contributor, and only if You 162 | agree to indemnify, defend, and hold each Contributor harmless for any 163 | liability incurred by, or claims asserted against, such Contributor by 164 | reason of your accepting any such warranty or additional liability. 165 | 166 | END OF TERMS AND CONDITIONS 167 | 168 | LLVM EXCEPTION TO THE APACHE 2.0 LICENSE 169 | 170 | As an exception, if, as a result of your compiling your source code, portions 171 | of this Software are embedded into an Object form of such source code, you may 172 | redistribute such embedded portions in such Object form without complying with 173 | the conditions of Sections 4(a), 4(b) and 4(d) of the License. 174 | 175 | In addition, if you combine or link compiled forms of this Software with 176 | software that is licensed under the GPLv2 ("Combined Software") and if a court 177 | of competent jurisdiction determines that the patent provision (Section 3), the 178 | indemnity provision (Section 9) or other Section of the License conflicts with 179 | the conditions of the GPLv2, you may retroactively and prospectively choose to 180 | deem waived or otherwise exclude such Section(s) of the License, but only in 181 | their entirety and only with respect to the Combined Software. 182 | 183 | END OF LLVM EXCEPTION 184 | 185 | APPENDIX: How to apply the Apache License to your work. 186 | 187 | To apply the Apache License to your work, attach the following boilerplate 188 | notice, with the fields enclosed by brackets "[]" replaced with your own 189 | identifying information. (Don't include the brackets!) The text should be 190 | enclosed in the appropriate comment syntax for the file format. We also 191 | recommend that a file or class name and description of purpose be included on 192 | the same "printed page" as the copyright notice for easier identification 193 | within third-party archives. 194 | 195 | Copyright [yyyy] [name of copyright owner] 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 198 | this file except in compliance with the License. You may obtain a copy of the 199 | License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software distributed 204 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 205 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 206 | specific language governing permissions and limitations under the License. 207 | 208 | END OF APPENDIX 209 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Enzo Haussecker 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 4 | this file except in compliance with the License. You may obtain a copy of the 5 | License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software distributed 10 | under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 11 | CONDITIONS OF ANY KIND, either express or implied. See the License for the 12 | specific language governing permissions and limitations under the License. 13 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/README.md: -------------------------------------------------------------------------------- 1 | ## The SHA Package 2 | 3 | [![Build Status](https://travis-ci.org/enzoh/motoko-sha.svg?branch=master)](https://travis-ci.org/enzoh/motoko-sha?branch=master) 4 | 5 | ### Overview 6 | 7 | This package implements secure hash algorithms for the Motoko programming 8 | language. 9 | 10 | ### Usage 11 | 12 | Calculate the SHA256 checksum of the data. 13 | ```motoko 14 | public func sha256(data : [Word8]) : [Word8] 15 | ``` 16 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "test": { 4 | "main": "test/Main.mo" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/nnsexplorer/vendor/sha/src/SHA256.mo: -------------------------------------------------------------------------------- 1 | /** 2 | * Module : SHA256.mo 3 | * Description : Cryptographic hash function. 4 | * Copyright : 2020 DFINITY Stiftung 5 | * License : Apache 2.0 with LLVM Exception 6 | * Maintainer : Enzo Haussecker 7 | * Stability : Stable 8 | */ 9 | 10 | import Array "mo:base/Array"; 11 | import Iter "mo:base/Iter"; 12 | import Prim "mo:prim"; 13 | 14 | module { 15 | 16 | private let K : [Word32] = [ 17 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 18 | 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 19 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 20 | 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 21 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 22 | 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 23 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 24 | 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 25 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 26 | 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 27 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 28 | 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 29 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 30 | 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 31 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 32 | 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 33 | ]; 34 | 35 | private let S : [Word32] = [ 36 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 37 | 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 38 | ]; 39 | 40 | // Calculate a SHA256 hash. 41 | public func sha256(data : [Word8]) : [Word8] { 42 | let digest = Digest(); 43 | digest.write(data); 44 | return digest.sum(); 45 | }; 46 | 47 | public class Digest() { 48 | 49 | private let s = Array.thaw(S); 50 | 51 | private let x = Array.init(64, 0); 52 | 53 | private var nx = 0; 54 | 55 | private var len : Word64 = 0; 56 | 57 | public func reset() { 58 | for (i in Iter.range(0, 7)) { 59 | s[i] := S[i]; 60 | }; 61 | nx := 0; 62 | len := 0; 63 | }; 64 | 65 | public func write(data : [Word8]) { 66 | var p = data; 67 | len += Prim.natToWord64(p.size()); 68 | if (nx > 0) { 69 | let n = min(p.size(), 64 - nx); 70 | for (i in Iter.range(0, n - 1)) { 71 | x[nx + i] := p[i]; 72 | }; 73 | nx += n; 74 | if (nx == 64) { 75 | let buf = Array.freeze(x); 76 | block(buf); 77 | nx := 0; 78 | }; 79 | p := Array.tabulate(p.size() - n, func (i) { 80 | return p[n + i]; 81 | }); 82 | }; 83 | if (p.size() >= 64) { 84 | let n = Prim.word64ToNat(Prim.natToWord64(p.size()) & (^ 63)); 85 | let buf = Array.tabulate(n, func (i) { 86 | return p[i]; 87 | }); 88 | block(buf); 89 | p := Array.tabulate(p.size() - n, func (i) { 90 | return p[n + i]; 91 | }); 92 | }; 93 | if (p.size() > 0) { 94 | for (i in Iter.range(0, p.size() - 1)) { 95 | x[i] := p[i]; 96 | }; 97 | nx := p.size(); 98 | }; 99 | }; 100 | 101 | public func sum() : [Word8] { 102 | var m = 0; 103 | var n = len; 104 | var t = Prim.word64ToNat(n) % 64; 105 | var buf : [var Word8] = [var]; 106 | if (56 > t) { 107 | m := 56 - t; 108 | } else { 109 | m := 120 - t; 110 | }; 111 | n := n << 3; 112 | buf := Array.init(m, 0); 113 | if (m > 0) { 114 | buf[0] := 0x80; 115 | }; 116 | write(Array.freeze(buf)); 117 | buf := Array.init(8, 0); 118 | for (i in Iter.range(0, 7)) { 119 | let j : Word64 = 56 - 8 * Prim.natToWord64(i); 120 | buf[i] := Prim.natToWord8(Prim.word64ToNat(n >> j)); 121 | }; 122 | write(Array.freeze(buf)); 123 | let hash = Array.init(32, 0); 124 | for (i in Iter.range(0, 7)) { 125 | for (j in Iter.range(0, 3)) { 126 | let k : Word32 = 24 - 8 * Prim.natToWord32(j); 127 | hash[4 * i + j] := Prim.natToWord8(Prim.word32ToNat(s[i] >> k)); 128 | }; 129 | }; 130 | return Array.freeze(hash); 131 | }; 132 | 133 | private func block(data : [Word8]) { 134 | var p = data; 135 | var w = Array.init(64, 0); 136 | while (p.size() >= 64) { 137 | var j = 0; 138 | for (i in Iter.range(0, 15)) { 139 | j := i * 4; 140 | w[i] := 141 | Prim.natToWord32(Prim.word8ToNat(p[j + 0])) << 24 | 142 | Prim.natToWord32(Prim.word8ToNat(p[j + 1])) << 16 | 143 | Prim.natToWord32(Prim.word8ToNat(p[j + 2])) << 08 | 144 | Prim.natToWord32(Prim.word8ToNat(p[j + 3])) << 00; 145 | }; 146 | var v1 : Word32 = 0; 147 | var v2 : Word32 = 0; 148 | var t1 : Word32 = 0; 149 | var t2 : Word32 = 0; 150 | for (i in Iter.range(16, 63)) { 151 | v1 := w[i - 02]; 152 | v2 := w[i - 15]; 153 | t1 := rot(v1, 17) ^ rot(v1, 19) ^ (v1 >> 10); 154 | t2 := rot(v2, 07) ^ rot(v2, 18) ^ (v2 >> 03); 155 | w[i] := 156 | t1 + w[i - 07] + 157 | t2 + w[i - 16]; 158 | }; 159 | var a = s[0]; 160 | var b = s[1]; 161 | var c = s[2]; 162 | var d = s[3]; 163 | var e = s[4]; 164 | var f = s[5]; 165 | var g = s[6]; 166 | var h = s[7]; 167 | for (i in Iter.range(0, 63)) { 168 | t1 := rot(e, 06) ^ rot(e, 11) ^ rot(e, 25); 169 | t1 += (e & f) ^ (^ e & g) + h + K[i] + w[i]; 170 | t2 := rot(a, 02) ^ rot(a, 13) ^ rot(a, 22); 171 | t2 += (a & b) ^ (a & c) ^ (b & c); 172 | h := g; 173 | g := f; 174 | f := e; 175 | e := d + t1; 176 | d := c; 177 | c := b; 178 | b := a; 179 | a := t1 + t2; 180 | }; 181 | s[0] += a; 182 | s[1] += b; 183 | s[2] += c; 184 | s[3] += d; 185 | s[4] += e; 186 | s[5] += f; 187 | s[6] += g; 188 | s[7] += h; 189 | p := Array.tabulate(p.size() - 64, func (i) { 190 | return p[i + 64]; 191 | }); 192 | }; 193 | }; 194 | }; 195 | 196 | private func min(a : Nat, b : Nat) : Nat { 197 | if (a < b) { 198 | return a; 199 | } else { 200 | return b; 201 | }; 202 | }; 203 | 204 | private func rot(n : Word32, i : Word32) : Word32 { 205 | let j : Word32 = i % 32; 206 | let k : Word32 = 32 - j; 207 | return n >> j | n << k; 208 | }; 209 | }; -------------------------------------------------------------------------------- /src/nnsexplorer_assets/App.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/color-dark.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #242f42; 3 | } 4 | .login-wrap{ 5 | background: #324157; 6 | } 7 | .plugins-tips{ 8 | background: #eef1f6; 9 | } 10 | .plugins-tips a{ 11 | color: #20a0ff; 12 | } 13 | .el-upload--text em { 14 | color: #20a0ff; 15 | } 16 | .pure-button{ 17 | background: #20a0ff; 18 | } 19 | .tags-li.active { 20 | border: 1px solid #409EFF; 21 | background-color: #409EFF; 22 | } 23 | .message-title{ 24 | color: #20a0ff; 25 | } 26 | .collapse-btn:hover{ 27 | background: rgb(40,52,70); 28 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/icon.css: -------------------------------------------------------------------------------- 1 | 2 | [class*=" el-icon-lx"], [class^=el-icon-lx] { 3 | font-family: lx-iconfont!important; 4 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | html, 7 | body, 8 | #app, 9 | .wrapper { 10 | width: 100%; 11 | height: 100%; 12 | overflow: hidden; 13 | } 14 | 15 | body { 16 | font-family: 'PingFang SC', "Helvetica Neue", Helvetica, "microsoft yahei", arial, STHeiTi, sans-serif; 17 | } 18 | 19 | a { 20 | text-decoration: none 21 | } 22 | 23 | 24 | .content-box { 25 | position: absolute; 26 | left: 250px; 27 | right: 0; 28 | top: 70px; 29 | bottom: 0; 30 | padding-bottom: 30px; 31 | -webkit-transition: left .3s ease-in-out; 32 | transition: left .3s ease-in-out; 33 | background: #f0f0f0; 34 | } 35 | 36 | .content { 37 | width: auto; 38 | height: 100%; 39 | padding: 10px; 40 | overflow-y: scroll; 41 | box-sizing: border-box; 42 | } 43 | 44 | .content-collapse { 45 | left: 65px; 46 | } 47 | 48 | .container { 49 | padding: 30px; 50 | background: #fff; 51 | border: 1px solid #ddd; 52 | border-radius: 5px; 53 | } 54 | 55 | .crumbs { 56 | margin: 10px 0; 57 | } 58 | 59 | .el-table th { 60 | background-color: #f5f7fa !important; 61 | } 62 | 63 | .pagination { 64 | margin: 20px 0; 65 | text-align: right; 66 | } 67 | 68 | .plugins-tips { 69 | padding: 20px 10px; 70 | margin-bottom: 20px; 71 | } 72 | 73 | .el-button+.el-tooltip { 74 | margin-left: 10px; 75 | } 76 | 77 | .el-table tr:hover { 78 | background: #f6faff; 79 | } 80 | 81 | .mgb20 { 82 | margin-bottom: 20px; 83 | } 84 | 85 | .move-enter-active, 86 | .move-leave-active { 87 | transition: opacity .5s; 88 | } 89 | 90 | .move-enter, 91 | .move-leave { 92 | opacity: 0; 93 | } 94 | 95 | /*BaseForm*/ 96 | 97 | .form-box { 98 | width: 600px; 99 | } 100 | 101 | .form-box .line { 102 | text-align: center; 103 | } 104 | 105 | .el-time-panel__content::after, 106 | .el-time-panel__content::before { 107 | margin-top: -7px; 108 | } 109 | 110 | .el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default) { 111 | padding-bottom: 0; 112 | } 113 | 114 | /*Upload*/ 115 | 116 | .pure-button { 117 | width: 150px; 118 | height: 40px; 119 | line-height: 40px; 120 | text-align: center; 121 | color: #fff; 122 | border-radius: 3px; 123 | } 124 | 125 | .g-core-image-corp-container .info-aside { 126 | height: 45px; 127 | } 128 | 129 | .el-upload--text { 130 | background-color: #fff; 131 | border: 1px dashed #d9d9d9; 132 | border-radius: 6px; 133 | box-sizing: border-box; 134 | width: 360px; 135 | height: 180px; 136 | text-align: center; 137 | cursor: pointer; 138 | position: relative; 139 | overflow: hidden; 140 | } 141 | 142 | .el-upload--text .el-icon-upload { 143 | font-size: 67px; 144 | color: #97a8be; 145 | margin: 40px 0 16px; 146 | line-height: 50px; 147 | } 148 | 149 | .el-upload--text { 150 | color: #97a8be; 151 | font-size: 14px; 152 | text-align: center; 153 | } 154 | 155 | .el-upload--text em { 156 | font-style: normal; 157 | } 158 | 159 | /*VueEditor*/ 160 | 161 | .ql-container { 162 | min-height: 400px; 163 | } 164 | 165 | .ql-snow .ql-tooltip { 166 | transform: translateX(117.5px) translateY(10px) !important; 167 | } 168 | 169 | .editor-btn { 170 | margin-top: 20px; 171 | } 172 | 173 | /*markdown*/ 174 | 175 | .v-note-wrapper .v-note-panel { 176 | min-height: 500px; 177 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/theme-green/color-green.css: -------------------------------------------------------------------------------- 1 | .header{ 2 | background-color: #07c4a8; 3 | } 4 | .login-wrap{ 5 | background: rgba(56, 157, 170, 0.82);; 6 | } 7 | .plugins-tips{ 8 | background: #f2f2f2; 9 | } 10 | .plugins-tips a{ 11 | color: #00d1b2; 12 | } 13 | .el-upload--text em { 14 | color: #00d1b2; 15 | } 16 | .pure-button{ 17 | background: #00d1b2; 18 | } 19 | .pagination > .active > a, .pagination > .active > a:hover, .pagination > .active > a:focus, .pagination > .active > span, .pagination > .active > span:hover, .pagination > .active > span:focus { 20 | background-color: #00d1b2 !important; 21 | border-color: #00d1b2 !important; 22 | } 23 | .tags-li.active { 24 | border: 1px solid #00d1b2; 25 | background-color: #00d1b2; 26 | } 27 | .collapse-btn:hover{ 28 | background: #00d1b2; 29 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/theme-green/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/assets/css/theme-green/fonts/element-icons.ttf -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/css/theme-green/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/assets/css/theme-green/fonts/element-icons.woff -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/img/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/assets/img/img.jpg -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/img/login-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/assets/img/login-bg.jpg -------------------------------------------------------------------------------- /src/nnsexplorer_assets/assets/img/visitor.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/assets/img/visitor.jpg -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/chart/dailyDelegate.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 208 | 209 | 251 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/chart/dailyRewards.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 219 | 220 | 262 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/chart/delegateChart.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 141 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/chart/resize.js: -------------------------------------------------------------------------------- 1 | import { debounce } from '../common/utils' 2 | 3 | export default { 4 | data() { 5 | return { 6 | $_sidebarElm: null, 7 | $_resizeHandler: null, 8 | } 9 | }, 10 | mounted() { 11 | this.$_resizeHandler = debounce(() => { 12 | if (this.chart) { 13 | this.chart.resize() 14 | } 15 | }, 100) 16 | this.$_initResizeEvent() 17 | this.$_initSidebarResizeEvent() 18 | }, 19 | beforeDestroy() { 20 | this.$_destroyResizeEvent() 21 | this.$_destroySidebarResizeEvent() 22 | }, 23 | // to fixed bug when cached by keep-alive 24 | // https://github.com/PanJiaChen/vue-element-admin/issues/2116 25 | activated() { 26 | this.$_initResizeEvent() 27 | this.$_initSidebarResizeEvent() 28 | }, 29 | deactivated() { 30 | this.$_destroyResizeEvent() 31 | this.$_destroySidebarResizeEvent() 32 | }, 33 | methods: { 34 | // use $_ for mixins properties 35 | // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential 36 | $_initResizeEvent() { 37 | window.addEventListener('resize', this.$_resizeHandler) 38 | }, 39 | $_destroyResizeEvent() { 40 | window.removeEventListener('resize', this.$_resizeHandler) 41 | }, 42 | $_sidebarResizeHandler(e) { 43 | if (e.propertyName === 'width') { 44 | this.$_resizeHandler() 45 | } 46 | }, 47 | $_initSidebarResizeEvent() { 48 | this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0] 49 | this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler) 50 | }, 51 | $_destroySidebarResizeEvent() { 52 | this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler) 53 | }, 54 | }, 55 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/common/Header.vue: -------------------------------------------------------------------------------- 1 | 129 | 330 | 427 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/common/Home.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 41 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/common/Sidebar.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 92 | 93 | 112 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/common/bus.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | // 使用 Event Bus 4 | const bus = new Vue(); 5 | 6 | export default bus; -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/common/i18n.js: -------------------------------------------------------------------------------- 1 | import enLocale from 'element-ui/lib/locale/lang/en' 2 | import zhLocale from 'element-ui/lib/locale/lang/zh-CN' 3 | 4 | export const messages = { 5 | 'zh': { 6 | // i18n: { 7 | // breadcrumb: '国际化产品', 8 | // tips: '通过切换语言按钮,来改变当前内容的语言。', 9 | // btn: '切换英文', 10 | // title1: '常用用法', 11 | // p1: '要是你把你的秘密告诉了风,那就别怪风把它带给树。', 12 | // p2: '没有什么比信念更能支撑我们度过艰难的时光了。', 13 | // p3: '只要能把自己的事做好,并让自己快乐,你就领先于大多数人了。', 14 | // title2: '组件插值', 15 | // info: 'Element组件需要国际化,请参考 {action}。', 16 | // value: '文档' 17 | // }, 18 | ...zhLocale 19 | }, 20 | 'en': { 21 | // i18n: { 22 | // breadcrumb: 'International Products', 23 | // tips: 'Click on the button to change the current language. ', 24 | // btn: 'Switch Chinese', 25 | // title1: 'Common usage', 26 | // p1: "If you reveal your secrets to the wind you should not blame the wind for revealing them to the trees.", 27 | // p2: "Nothing can help us endure dark times better than our faith. ", 28 | // p3: "If you can do what you do best and be happy, you're further along in life than most people.", 29 | // title2: 'Component interpolation', 30 | // info: 'The default language of Element is Chinese. If you wish to use another language, please refer to the {action}.', 31 | // value: 'documentation' 32 | // }, 33 | ...enLocale 34 | } 35 | } -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/dialog/BeDelegator.vue: -------------------------------------------------------------------------------- 1 | 87 | 194 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/dialog/BeNeuron.vue: -------------------------------------------------------------------------------- 1 | 59 | 150 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/dialog/ProposalInfo.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hashquark-io/nnsExplorer/5b76801de9b93de4e6f8d02be6a7746664e03b6b/src/nnsexplorer_assets/components/dialog/ProposalInfo.vue -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/page/404.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | 28 | 60 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/page/I18n.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 43 | 44 | 55 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/page/NeuronInfo.vue: -------------------------------------------------------------------------------- 1 | 62 | 191 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/components/page/Proposals.vue: -------------------------------------------------------------------------------- 1 | 119 | 120 | 264 | 265 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import ElementUI from 'element-ui'; 5 | import VueI18n from 'vue-i18n'; 6 | import { messages } from './components/common/i18n'; 7 | import 'element-ui/lib/theme-chalk/index.css'; 8 | // import './assets/css/theme-green/index.css'; 9 | import ElementLocale from 'element-ui/lib/locale' 10 | import './assets/css/icon.css'; 11 | import 'babel-polyfill'; 12 | 13 | //Vue.config.productionTip = false; 14 | Vue.use(VueI18n); 15 | Vue.use(ElementUI, { 16 | size: 'small' 17 | }); 18 | const i18n = new VueI18n({ 19 | locale: 'en', 20 | messages 21 | }); 22 | ElementLocale.i18n((key, value) => i18n.t(key, value)) 23 | 24 | router.beforeEach((to, from, next) => { 25 | document.title = `${to.meta.title} | DFINITY NNS Explorer`; 26 | // const role = localStorage.getItem('nns_useraccount'); 27 | // if (!role && to.path !== '/login') { 28 | // next('/login'); 29 | // } else if (to.meta.permission) { 30 | // // TODO 31 | // role === 'admin' ? next() : next('/403'); 32 | // } else { 33 | // if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') { 34 | // Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', { 35 | // confirmButtonText: '确定' 36 | // }); 37 | // } else { 38 | // next(); 39 | // } 40 | // } 41 | if (navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor') { 42 | Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏览器查看', '浏览器不兼容通知', { 43 | confirmButtonText: '确定' 44 | }); 45 | } else { 46 | next(); 47 | } 48 | }); 49 | 50 | new Vue({ 51 | router, 52 | i18n, 53 | render: h => h(App) 54 | }).$mount('#app'); -------------------------------------------------------------------------------- /src/nnsexplorer_assets/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | DFINITY NNS Explorer 9 | 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/nnsexplorer_assets/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Home from '../components/common/Home.vue'; 4 | import Overview from '../components/page/Overview.vue'; 5 | import NeuronInfo from '../components/page/NeuronInfo.vue'; 6 | import Proposals from '../components/page/Proposals.vue'; 7 | import Profile from '../components/page/Profile.vue'; 8 | import I18n from '../components/page/I18n.vue'; 9 | import P404 from '../components/page/404.vue'; 10 | 11 | Vue.use(Router); 12 | 13 | export default new Router({ 14 | routes: [{ 15 | path: '/', 16 | redirect: '/overview' 17 | }, 18 | { 19 | path: '/', 20 | component: Home, 21 | meta: { title: '自述文件' }, 22 | children: [{ 23 | path: '/overview', 24 | name: 'overview', 25 | component: Overview, 26 | meta: { title: 'Overview' } 27 | }, 28 | { 29 | path: '/neuronInfo', 30 | name: 'neuronInfo', 31 | component: NeuronInfo, 32 | meta: { title: 'Neuron Details' } 33 | }, 34 | { 35 | path: '/profile', 36 | name: 'profile', 37 | component: Profile, 38 | meta: { title: 'profile' } 39 | }, 40 | { 41 | path: '/proposals', 42 | name: 'proposals', 43 | component: Proposals, 44 | meta: { title: 'proposals' } 45 | }, 46 | // { 47 | // // 中英文切换组件 48 | // path: '/i18n', 49 | // component: I18n, 50 | // meta: { title: '中英文切换' } 51 | // }, 52 | { 53 | path: '/404', 54 | component: P404, 55 | meta: { title: '404' } 56 | }, 57 | ] 58 | }, 59 | { 60 | path: '*', 61 | redirect: '/404' 62 | } 63 | ] 64 | }); -------------------------------------------------------------------------------- /src/nnsexplorer_sim/main.mo: -------------------------------------------------------------------------------- 1 | import Prim "mo:prim"; 2 | import Nat64 "mo:base/Nat64"; 3 | import Array "mo:base/Array"; 4 | import Text "mo:base/Text"; 5 | import List "mo:base/List"; 6 | import Assoc "mo:base/AssocList"; 7 | import Types "../nnsexplorer/types"; 8 | import NNSExplorer "canister:nnsexplorer"; 9 | import Debug "mo:base/Debug"; 10 | 11 | actor nnsexplorer_sim { 12 | // table of mock accounts 13 | let accounts = 14 | [ 15 | { 16 | accountAddr = "A5AEC167AC201B67C6EF6B267361B3D2595C2EC798EB8D7DD52489BC02DC"; 17 | signature = "Dominic Williams"; 18 | balance = 10000: Nat64; 19 | rewards = 0: Nat64; 20 | isDelegator = false; 21 | }, 22 | { 23 | accountAddr = "A19BA9C73839E92644491D0901071267D115D1FE1A1A4870C3DB5CA50228"; 24 | signature = "Diego Prats"; 25 | balance = 10000: Nat64; 26 | rewards = 0: Nat64; 27 | isDelegator = false; 28 | }, 29 | { 30 | accountAddr = "CE1D6EDC4B7383D84187BB9056659DC6135EDF239F0E8DD0FB518A510257"; 31 | signature = "Jan Camenisch"; 32 | balance = 10000: Nat64; 33 | rewards = 0: Nat64; 34 | isDelegator = false; 35 | }, 36 | { 37 | accountAddr = "CEDDBCA8FA100E5E177F1E3934E98A366CEDFB3968D8915E6E1933970224"; 38 | signature = "Donald Trump"; 39 | balance = 10000: Nat64; 40 | rewards = 0: Nat64; 41 | isDelegator = false; 42 | }, 43 | { 44 | accountAddr = "B5B5E0924288954CE5427AC456366E7DD50837723DA10D04998AD7CE0273"; 45 | signature = "Sanam Saaber"; 46 | balance = 10000: Nat64; 47 | rewards = 0: Nat64; 48 | isDelegator = false; 49 | }, 50 | { 51 | accountAddr = "3BA830E39688DE354E40084C21FCB0C86E190DBDB322021C2A4843C002D5"; 52 | signature = "Barack Obama"; 53 | balance = 10000: Nat64; 54 | rewards = 0: Nat64; 55 | isDelegator = false; 56 | } 57 | ]; 58 | 59 | // table of mock neurons 60 | let neurons = 61 | [ 62 | { 63 | accountAddr = "A5AEC167AC201B67C6EF6B267361B3D2595C2EC798EB8D7DD52489BC02DC"; 64 | description = "Dominic Williams - Founder & Chief Scientist"; 65 | commissionRate = 5; 66 | selfStaking = 300000: Nat64; 67 | }, 68 | { 69 | accountAddr = "A19BA9C73839E92644491D0901071267D115D1FE1A1A4870C3DB5CA50228"; 70 | description = "Diego Prats - Director of Product"; 71 | commissionRate = 10; 72 | selfStaking = 200000: Nat64; 73 | }, 74 | { 75 | accountAddr = "CE1D6EDC4B7383D84187BB9056659DC6135EDF239F0E8DD0FB518A510257"; 76 | description = "Jan Camenisch - VP of Research"; 77 | commissionRate = 10; 78 | selfStaking = 50000: Nat64; 79 | }, 80 | { 81 | accountAddr = "CEDDBCA8FA100E5E177F1E3934E98A366CEDFB3968D8915E6E1933970224"; 82 | description = "Donald Trump - President"; 83 | commissionRate = 5; 84 | selfStaking = 900000: Nat64; 85 | }, 86 | { 87 | accountAddr = "B5B5E0924288954CE5427AC456366E7DD50837723DA10D04998AD7CE0273"; 88 | description = "Sanam Saaber - General Counsel"; 89 | commissionRate = 10; 90 | selfStaking = 100000: Nat64; 91 | }, 92 | { 93 | accountAddr = "3BA830E39688DE354E40084C21FCB0C86E190DBDB322021C2A4843C002D5"; 94 | description = "Barack Obama - President (Retired)"; 95 | commissionRate = 20; 96 | selfStaking = 600000: Nat64; 97 | } 98 | ]; 99 | 100 | // table of mock proposals 101 | let proposals = 102 | [ 103 | { 104 | title = "Adjust new mining identity security deposit to 2,135 ICP"; 105 | details = "content of \"Adjust new mining identity security deposit to 2,135 ICP\""; 106 | createdBy = "A19BA9C73839E92644491D0901071267D115D1FE1A1A4870C3DB5CA50228"; 107 | excutionTime = 0: Int; 108 | }, 109 | { 110 | title = "Reduce ICP emmissions by 10%"; 111 | details = "content of \"Reduce ICP emmissions by 10%\""; 112 | createdBy = "A5AEC167AC201B67C6EF6B267361B3D2595C2EC798EB8D7DD52489BC02DC"; 113 | excutionTime = 0: Int; 114 | }, 115 | { 116 | title = "Add USDT support"; 117 | details = "content of \"Add USDT support\""; 118 | createdBy = "CE1D6EDC4B7383D84187BB9056659DC6135EDF239F0E8DD0FB518A510257"; 119 | excutionTime = 0: Int; 120 | }, 121 | ]; 122 | 123 | type DFNAccount = Types.DFNAccount; 124 | type Neuron = Types.Neuron; 125 | 126 | var inited = false; 127 | var started = false; 128 | var rewardAmount: Nat64 = 256: Nat64; 129 | 130 | var netTotalVotes: Nat64 = 0: Nat64; 131 | var netTotalRewardsDist: Nat64 = 0: Nat64; 132 | var netTotalDelegated: Nat64 = 0: Nat64; 133 | 134 | public query func healthcheck(): async Bool { true }; 135 | 136 | public query func status(): async Bool { started }; 137 | 138 | public query func totalRewardsDist(addr: Text): async Text { 139 | Nat64.toText(netTotalRewardsDist) 140 | }; 141 | 142 | public query func totalDelegated(addr: Text): async Text { 143 | Nat64.toText(netTotalDelegated) 144 | }; 145 | 146 | 147 | // dfx canister call nnsexplorer_sim init 148 | public func init() : async () { 149 | if inited assert(false); 150 | inited := true; 151 | 152 | await NNSExplorer.signupTests(accounts); 153 | await NNSExplorer.createTestNeurons(neurons); 154 | 155 | let p: async () = NNSExplorer.createProposalsTest(proposals); 156 | }; 157 | 158 | public func createTestProposal() : async Bool { 159 | let now = Prim.nat64ToNat(Prim.time()/1000000000); 160 | await NNSExplorer.createProposalTest(proposals[now%3]); 161 | true 162 | }; 163 | 164 | // dfx canister call nnsexplorer_sim start 165 | public func start(): async Text { 166 | if (not inited) { await init() }; 167 | inited := true; 168 | if started { return "Already started!" }; 169 | started := true; 170 | 171 | let l: async () = startLoop(); 172 | 173 | "Started successfully!" 174 | }; 175 | 176 | // dfx canister call nnsexplorer_sim stop 177 | public func stop(): async Text { 178 | started := false; 179 | "Stopped successfully!" 180 | }; 181 | 182 | func startLoop() : async () { 183 | while(started) { 184 | let existings = await NNSExplorer.getNeuronListTest(); 185 | var accounts: [DFNAccount] = []; 186 | var netTotalVotesTemp: Nat64 = 0: Nat64; 187 | var delegatorsTemp: Assoc.AssocList = List.nil<(Text, Nat64)>(); 188 | var delegatorsAddr: [Text] = []; 189 | netTotalDelegated := 0; 190 | for (existing in existings.vals()) { 191 | netTotalDelegated += existing.totalDelegations; 192 | netTotalVotesTemp += existing.totalDelegations + existing.selfStaking; 193 | let account = await NNSExplorer.getAccount(existing.accountAddr); 194 | switch (account) { 195 | case (null) { assert(false) }; 196 | case (?account) { 197 | let newAccount = { 198 | accountAddr = account.accountAddr; 199 | signature = account.signature; 200 | balance = account.balance; 201 | rewards = account.rewards + calcNeuronRewards(existing.selfStaking, existing.totalDelegations, existing.commissionRate); 202 | isDelegator = account.isDelegator; 203 | }; 204 | accounts := Array.append(accounts, [newAccount]); 205 | }; 206 | }; 207 | 208 | func addDelegationRewards((addr, amount): (Text, Nat64)) { 209 | var rewardsAdd = calcDelegatorRewards(amount, existing.commissionRate); 210 | let rewardsOld = Assoc.find(delegatorsTemp, addr, Text.equal); 211 | switch (rewardsOld) { 212 | case (null) { delegatorsAddr := Array.append(delegatorsAddr, [addr]); }; 213 | case (?rewardsOld) { 214 | rewardsAdd += rewardsOld; 215 | }; 216 | }; 217 | let (delegatorsTempNew, _) = 218 | Assoc.replace(delegatorsTemp, addr, Text.equal, ?rewardsAdd); 219 | delegatorsTemp := delegatorsTempNew; 220 | }; 221 | List.iterate<(Text, Nat64)>(existing.delegations, addDelegationRewards); 222 | }; 223 | 224 | for (addr in delegatorsAddr.vals()) { 225 | let account = await NNSExplorer.getAccount(addr); 226 | switch (account) { 227 | case (null) { assert(false) }; 228 | case (?account) { 229 | let rewardsAddTotal = Assoc.find(delegatorsTemp, addr, Text.equal); 230 | switch (rewardsAddTotal) { 231 | case (null) { assert(false) }; 232 | case (?rewardsAddTotal) { 233 | let newAccount = { 234 | accountAddr = account.accountAddr; 235 | signature = account.signature; 236 | balance = account.balance; 237 | rewards = account.rewards + rewardsAddTotal; 238 | isDelegator = account.isDelegator; 239 | }; 240 | accounts := Array.append(accounts, [newAccount]); 241 | }; 242 | }; 243 | }; 244 | }; 245 | }; 246 | await NNSExplorer.updateAccounts(accounts); 247 | 248 | netTotalVotes := netTotalVotesTemp; 249 | }; 250 | }; 251 | 252 | func calcNeuronRewards(selfVotes: Nat64, delegations: Nat64, commissionRate: Nat): Nat64 { 253 | if (netTotalVotes == Nat64.fromNat(0)) { 254 | return Nat64.fromNat(0); 255 | }; 256 | let selfRewards: Nat64 = selfVotes * rewardAmount / netTotalVotes; 257 | let commission: Nat64 = delegations * rewardAmount / netTotalVotes * Nat64.fromNat(commissionRate) / Nat64.fromNat(100); 258 | 259 | let rewards = selfRewards + commission; 260 | netTotalRewardsDist += rewards; 261 | return rewards; 262 | }; 263 | 264 | func calcDelegatorRewards(delegation: Nat64, commissionRate: Nat): Nat64 { 265 | if (netTotalVotes == Nat64.fromNat(0)) { 266 | return Nat64.fromNat(0); 267 | }; 268 | let selfRewards: Nat64 = delegation * rewardAmount / netTotalVotes; 269 | let commission: Nat64 = selfRewards * Nat64.fromNat(commissionRate) / Nat64.fromNat(100); 270 | 271 | let rewards = selfRewards - commission; 272 | netTotalRewardsDist += rewards; 273 | return rewards; 274 | }; 275 | 276 | }; -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const utils = require('./webpack/utils') 3 | const configs = require('./webpack/configs') 4 | const webpack = require('webpack') 5 | const merge = require('webpack-merge') 6 | const vueLoaderConfig = require('./webpack/vue-loader.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 9 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 10 | const env = require('./webpack/prod.env') 11 | const TerserPlugin = require("terser-webpack-plugin"); 12 | const dfxJson = require("./dfx.json"); 13 | 14 | function resolve(dir) { 15 | return path.join(__dirname, dir) 16 | } 17 | 18 | // List of all aliases for canisters. This creates the module alias for 19 | // the `import ... from "ic:canisters/xyz"` where xyz is the name of a 20 | // canister. 21 | const aliases = Object.entries(dfxJson.canisters) 22 | .reduce((acc, [name, value]) => { 23 | // Get the network name, or `local` by default. 24 | const networkName = process.env["DFX_NETWORK"] || "local"; 25 | const outputRoot = path.join( 26 | __dirname, 27 | ".dfx", 28 | networkName, 29 | "canisters", 30 | name 31 | ); 32 | return { 33 | ...acc, 34 | ["ic:canisters/" + name]: path.join(outputRoot, name + ".js"), 35 | ["ic:idl/" + name]: path.join(outputRoot, name + ".did.js"), 36 | "vue$": "vue/dist/vue.esm.js", 37 | "@": resolve("src"), 38 | }; 39 | }, { 40 | // This will later point to the userlib from npm, when we publish the userlib. 41 | "ic:userlib": path.join( 42 | process.env["HOME"], 43 | ".cache/dfinity/versions", 44 | dfxJson.dfx || process.env["DFX_VERSION"], 45 | "js-user-library/dist/lib.prod.js", 46 | ), 47 | }); 48 | 49 | /** 50 | * Generate a webpack configuration for a canister. 51 | */ 52 | function generateWebpackConfigForCanister(name, info) { 53 | if (typeof info.frontend !== 'object') { 54 | return; 55 | } 56 | 57 | const inputRoot = __dirname; 58 | 59 | return { 60 | mode: 'production', 61 | entry: { 62 | index: path.join(inputRoot, info.frontend.entrypoint), 63 | }, 64 | devtool: configs.build.productionSourceMap ? '#source-map' : false, 65 | resolve: { 66 | extensions: ['.js', '.vue', '.json'], 67 | alias: aliases, 68 | }, 69 | output: { 70 | // filename: utils.assetsPath('js/[name].[chunkhash].js'), 71 | // chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'), 72 | filename: '[name].js', 73 | chunkFilename: '[id].js', 74 | path: path.join(__dirname, "dist", name), 75 | publicPath: './', 76 | }, 77 | module: { 78 | rules: [{ 79 | test: /\.vue$/, 80 | loader: 'vue-loader', 81 | options: vueLoaderConfig 82 | }, 83 | { 84 | test: /\.js$/, 85 | loader: 'babel-loader', 86 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')], 87 | options: { 88 | //"babelrc": false, 89 | "plugins": [ 90 | "dynamic-import-webpack", 91 | "transform-object-rest-spread" 92 | ] 93 | } 94 | }, 95 | { 96 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 97 | loader: 'url-loader', 98 | options: { 99 | limit: 100000, //10000 100 | name: 'img/[name].[ext]' 101 | //name: 'img/[name].[hash:7].[ext]' 102 | } 103 | }, 104 | { 105 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 106 | loader: 'url-loader', 107 | options: { 108 | limit: 100000, //10000 109 | name: 'media/[name].[ext]' 110 | //name: 'media/[name].[hash:7].[ext]' 111 | } 112 | }, 113 | { 114 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 115 | loader: 'url-loader', 116 | options: { 117 | //limit: 100000, //10000 118 | name: 'fonts/[name].[ext]' 119 | //name: 'fonts/[name].[hash:7].[ext]' 120 | } 121 | } 122 | ] 123 | }, 124 | plugins: [ 125 | new HtmlWebpackPlugin({ 126 | filename: path.resolve(__dirname, './dist/nnsexplorer_assets/index.html'), 127 | template: './src/nnsexplorer_assets/public/index.html', 128 | inject: true, 129 | minify: { 130 | removeComments: true, 131 | collapseWhitespace: true, 132 | removeAttributeQuotes: true 133 | }, 134 | chunksSortMode: 'none' 135 | }), 136 | new VueLoaderPlugin(), 137 | new webpack.DefinePlugin({ 138 | 'process.env': env, 139 | }), 140 | new MiniCssExtractPlugin({ 141 | // filename: utils.assetsPath('css/[name].[hash].css'), 142 | // chunkFilename: utils.assetsPath('css/[id].[hash].css'), 143 | filename: '[name].css', 144 | chunkFilename: '[id].css', 145 | }), 146 | new webpack.HashedModuleIdsPlugin(), 147 | ], 148 | optimization: { 149 | minimize: true, 150 | minimizer: [ 151 | new TerserPlugin({ 152 | warningsFilter: () => false, 153 | sourceMap: true, //configs.build.productionSourceMap, 154 | parallel: true, 155 | }), 156 | // new OptimizeCSSPlugin({ 157 | // cssProcessorOptions: { safe: true, map: { inline: false } } 158 | // }), 159 | ], 160 | // splitChunks: { 161 | // chunks: "async", 162 | // minSize: 30000, 163 | // maxSize: 0, 164 | // minChunks: 1, 165 | // maxAsyncRequests: 5, 166 | // maxInitialRequests: 3, 167 | // automaticNameDelimiter: '~', 168 | // automaticNameMaxLength: 30, 169 | // name: true, 170 | // cacheGroups: { 171 | // default: { 172 | // minChunks: 2, 173 | // priority: -20, 174 | // reuseExistingChunk: true 175 | // }, 176 | // vendors: { 177 | // test: /[\\/]node_modules[\\/]/, 178 | // priority: -10 179 | // } 180 | // } 181 | // }, 182 | // runtimeChunk: { 183 | // name: "runtime" 184 | // } 185 | } 186 | }; 187 | } 188 | 189 | // If you have additional webpack configurations you want to build 190 | // as part of this configuration, add them to the section below. 191 | module.exports = [ 192 | ...Object.entries(dfxJson.canisters).map(([name, info]) => { 193 | if (typeof info.frontend !== 'object') { 194 | return generateWebpackConfigForCanister(name, info) 195 | } 196 | 197 | return merge(generateWebpackConfigForCanister(name, info), { 198 | mode: 'production', 199 | module: { 200 | rules: utils.styleLoaders({ 201 | sourceMap: configs.build.productionSourceMap, 202 | extract: true 203 | }) 204 | } 205 | }); 206 | }).filter((x) => !!x), 207 | ]; -------------------------------------------------------------------------------- /webpack/configs.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | module.exports = { 3 | build: { 4 | productionSourceMap: true, 5 | } 6 | } -------------------------------------------------------------------------------- /webpack/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | } -------------------------------------------------------------------------------- /webpack/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | //const MiniCssExtractPlugin = require('mini-css-extract-plugin') 4 | //const packageConfig = require('../package.json') 5 | 6 | exports.assetsPath = function(_path) { 7 | const assetsSubDirectory = 'static' 8 | 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function(options) { 13 | options = options || {} 14 | 15 | const cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | sourceMap: options.sourceMap 19 | } 20 | } 21 | 22 | const postcssLoader = { 23 | loader: 'postcss-loader', 24 | options: { 25 | sourceMap: options.sourceMap 26 | } 27 | } 28 | 29 | // generate loader string to be used with extract text plugin 30 | function generateLoaders(loader, loaderOptions) { 31 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 32 | 33 | if (loader) { 34 | loaders.push({ 35 | loader: loader + '-loader', 36 | options: Object.assign({}, loaderOptions, { 37 | sourceMap: options.sourceMap 38 | }) 39 | }) 40 | } 41 | 42 | return ['vue-style-loader'].concat(loaders) 43 | // Extract CSS when that option is specified 44 | // (which is the case during production build) 45 | // if (options.extract) { 46 | // return [{ 47 | // loader: MiniCssExtractPlugin.loader, 48 | // options: { 49 | // hmr: process.env.NODE_ENV != 'development', 50 | // reloadAll: true, 51 | // } 52 | // }].concat(loaders); 53 | // } else { 54 | // return ['vue-style-loader'].concat(loaders) 55 | // } 56 | } 57 | 58 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 59 | return { 60 | css: generateLoaders(), 61 | postcss: generateLoaders(), 62 | less: generateLoaders('less'), 63 | sass: generateLoaders('sass', { indentedSyntax: true }), 64 | scss: generateLoaders('sass'), 65 | stylus: generateLoaders('stylus'), 66 | styl: generateLoaders('stylus') 67 | } 68 | } 69 | 70 | // Generate loaders for standalone style files (outside of .vue) 71 | exports.styleLoaders = function(options) { 72 | const output = [] 73 | const loaders = exports.cssLoaders(options) 74 | 75 | for (const extension in loaders) { 76 | const loader = loaders[extension] 77 | output.push({ 78 | test: new RegExp('\\.' + extension + '$'), 79 | use: loader 80 | }) 81 | } 82 | 83 | return output 84 | } 85 | 86 | // exports.createNotifierCallback = () => { 87 | // const notifier = require('node-notifier') 88 | 89 | // return (severity, errors) => { 90 | // if (severity !== 'error') return 91 | 92 | // const error = errors[0] 93 | // const filename = error.file && error.file.split('!').pop() 94 | 95 | // notifier.notify({ 96 | // title: packageConfig.name, 97 | // message: severity + ': ' + error.name, 98 | // subtitle: filename || '', 99 | // icon: path.join(__dirname, 'logo.png') 100 | // }) 101 | // } 102 | // } -------------------------------------------------------------------------------- /webpack/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const configs = require('./configs') 4 | const isProduction = true 5 | const sourceMapEnabled = configs.build.productionSourceMap 6 | 7 | module.exports = { 8 | loaders: utils.cssLoaders({ 9 | sourceMap: sourceMapEnabled, 10 | extract: isProduction 11 | }), 12 | // cssSourceMap: sourceMapEnabled, 13 | // cacheBusting: true, 14 | // transformToRequire: { 15 | // video: ['src', 'poster'], 16 | // source: 'src', 17 | // img: 'src', 18 | // image: 'xlink:href' 19 | // } 20 | } --------------------------------------------------------------------------------