├── .gitignore ├── .babelrc ├── nuxt ├── vue-ethereum-plugin.template.js └── index.js ├── .eslintrc.js ├── examples └── vue-example │ ├── index.js │ └── main.vue ├── rollup.config.js ├── LICENSE ├── CONTRIBUTING.md ├── package.json ├── src ├── constants.js ├── watcher.js └── index.js └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | node_modules 3 | npm-debug.log 4 | tmp 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "development": { 4 | "presets": ["@babel/preset-env"] 5 | }, 6 | "test": { 7 | "presets": ["babel-preset-poi"] 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /nuxt/vue-ethereum-plugin.template.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import VueEthereum from 'vue-ethereum' 4 | 5 | Vue.use(VueEthereum) 6 | 7 | export default ({app}) => { 8 | // inject options from module 9 | const pluginOptions = [<%= serialize(options) %>][0] 10 | app.eth = new VueEthereum(pluginOptions) 11 | } 12 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | // parser: 'babel-eslint', 9 | sourceType: 'module' 10 | }, 11 | extends: [ 12 | 'standard', 'plugin:vue/recommended' 13 | ], 14 | plugins: [ 15 | 'html' 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /examples/vue-example/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueEthereum from '../../src/index.js' 3 | import { OrbitSpinner } from 'epic-spinners' 4 | 5 | import main from './main.vue' 6 | 7 | Vue.use(VueEthereum) 8 | 9 | Vue.component('orbit-spinner', OrbitSpinner) 10 | 11 | export default new Vue({ 12 | el: '#app', 13 | eth: new VueEthereum({ registerComponents: false }), 14 | render: function (createElement) { 15 | return createElement(main) 16 | } 17 | }) 18 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import vue from 'rollup-plugin-vue' 2 | 3 | export default [ 4 | // ESM build to be used with webpack/rollup. 5 | { 6 | input: 'src/index.js', 7 | output: { 8 | format: 'esm', 9 | file: 'dist/vue-ethereum.esm.js' 10 | }, 11 | external: [ 'web3' ], 12 | plugins: [ 13 | vue() 14 | ] 15 | }, 16 | // SSR build. 17 | { 18 | input: 'src/index.js', 19 | output: { 20 | format: 'cjs', 21 | file: 'dist/vue-ethereum.ssr.js' 22 | }, 23 | external: [ 'web3' ], 24 | plugins: [ 25 | vue({ template: { optimizeSSR: true } }) 26 | ] 27 | } 28 | ] 29 | -------------------------------------------------------------------------------- /nuxt/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Nuxt.js module for vue-ethereum 3 | 4 | Usage: 5 | - Install vue-ethereum package 6 | - Add this into your nuxt.config.js file: 7 | { 8 | modules: [ 'vue-ethereum/nuxt' ], 9 | // Optionally passing options in module top level configuration 10 | ethereum: { useVuex: true } 11 | } 12 | */ 13 | 14 | const {resolve} = require('path'); 15 | 16 | module.exports = function nuxtVueEthereumModule(moduleOptions) { 17 | const options = Object.assign({}, this.options.ethereum, moduleOptions); 18 | 19 | // Register plugin 20 | this.addPlugin({ 21 | src: resolve(__dirname, 'vue-ethereum-plugin.template.js'), 22 | fileName: 'vue-ethereum-plugin.js', 23 | options: options 24 | }) 25 | }; 26 | 27 | // required by nuxt 28 | module.exports.meta = require('../package.json'); 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Valentin D. Guillois 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to 'vue-ethereum' 2 | 3 | ## Bugs 4 | 5 | > The ideal GitHub issue (and even some feature requests) is not an issue, it's a PR with a failing test case. 6 |
[@rauchg](https://twitter.com/rauchg/status/810589655532007424) 7 | 8 | **Before filing an issue please [search the issue tracker](https://github.com/vdg/vue-ethereum/issues); your issue may have already been discussed or fixed in `master`.** 9 | 10 | **If you want your issue to get priority, submit it as a PR instead** 11 | 12 | **Fill in the template** provided by the issue tracker, try to be as **clear** and **complete** as possible, providing a **[Short, Self Contained, Correct (Compilable), Example (SSCE)](http://sscce.org/)** (**link** to a **repository**) helps a lot . 13 | 14 | ## Feature / Enhancement Requests 15 | 16 | Feature or enhancement requests should be **submitted** in the 17 | [issue tracker](https://github.com/vdg/vue-ethereum/issues), with a **description** (follow the template) of the expected behavior & use case, where they’ll remain until **approval** by the **lead maintainer(s) and/or enough interest** from the **community**. 18 | 19 | You can **request** a feature by **writing a pull request**, but this is **no guarantee** it will be **merged**. 20 | 21 | 26 | 27 | ## Pull Requests (PR) 28 | 29 | In general, the contribution workflow looks like this: 30 | 31 | 1. **Fork** the repo. 32 | 2. **Clone** the repo. `git clone https://github.com/your-username/vue-ethereum.git`. 33 | 3. Create a **new branch** based off the master branch, provide a **descriptive name**
(ex. '**feat**-add-better-logging', '**bug**-removed-double-method', '**enh**-bumped-eslint') 34 | 4. Before running the code you’ll need to **install** the **dependencies** (`yarn install` or `npm install`). 35 | 5. **Implement** your feature / bugfix (using the **watch scripts**), you should **only need to modify `/src`**. Don’t worry about regenerating the build folder `/dist`, it is **built** in the **prepublish** phase. 36 | 6. Submit a **PR**, referencing what it addresses. 37 | 7. Please try to keep your **PR focused in scope and avoid including unrelated commits**. 38 | 39 | After you have submitted your PR, we'll try to **get back to you as soon as possible**.
We will **review** your PR and might **request changes**. 40 | 41 | ## Coding Guidelines 42 | 43 | Please **follow** the **conventions** already established in the code. 44 | 45 | Guidelines are enforced using **[ESLint](http://eslint.org/)**. 46 | 47 | 48 | You can **run the linting script** by using 49 | 50 | ```console 51 | $ yarn run lint 52 | ``` 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-ethereum", 3 | "version": "0.3.7", 4 | "description": "Vue and Nuxt plugins for easy access to Ethereum (using web3.js 1.x)", 5 | "main": "dist/vue-ethereum.ssr.js", 6 | "module": "dist/vue-ethereum.esm.js", 7 | "files": [ 8 | "dist", 9 | "src", 10 | "nuxt" 11 | ], 12 | "repository": "vdg/vue-ethereum", 13 | "author": { 14 | "name": "Valentin D. Guillois", 15 | "email": "vdg@rouge.network", 16 | "url": "https://github.com/vdg" 17 | }, 18 | "license": "MIT", 19 | "keywords": [ 20 | "ethereum", 21 | "web3", 22 | "vue", 23 | "vuex", 24 | "nuxt", 25 | "plugin" 26 | ], 27 | "scripts": { 28 | "test": "exit 0;", 29 | "prepublish": "yarn run build", 30 | "release": "release-it", 31 | "precommit": "lint-staged", 32 | "lint": "eslint src/*.js examples/vue-example", 33 | "dev-vue": "NODE_ENV=test poi examples/vue-example/index.js", 34 | "build": "rollup -c --environment BUILD:production" 35 | }, 36 | "release-it": { 37 | "github": { 38 | "release": true 39 | } 40 | }, 41 | "publishConfig": { 42 | "access": "public" 43 | }, 44 | "prettier": "prettier-config-standard", 45 | "lint-staged": { 46 | "src/**/*.js": [ 47 | "eslint --fix", 48 | "git add" 49 | ], 50 | "examples/**/*.js": [ 51 | "eslint --fix", 52 | "git add" 53 | ] 54 | }, 55 | "husky": { 56 | "hooks": { 57 | "pre-commit": "yarn run lint", 58 | "pre-push": "yarn run lint" 59 | } 60 | }, 61 | "devDependencies": { 62 | "@babel/cli": "^7.7.5", 63 | "@babel/core": "^7.7.5", 64 | "@babel/node": "^7.7.4", 65 | "@babel/preset-env": "^7.7.6", 66 | "babel-eslint": "^10.0.2", 67 | "babel-loader": "^8.0.0-beta.3", 68 | "css-loader": "^0.28.11", 69 | "epic-spinners": "^1.0.3", 70 | "escape-string-regexp": "^1.0.5", 71 | "eslint": "^6.7.2", 72 | "eslint-config-prettier": "^6.7.0", 73 | "eslint-config-standard": "^14.0.1", 74 | "eslint-plugin-html": "^6.0.0", 75 | "eslint-plugin-import": "^2.19.1", 76 | "eslint-plugin-node": "^9.1.0", 77 | "eslint-plugin-promise": "^4.2.1", 78 | "eslint-plugin-standard": "^4.0.1", 79 | "eslint-plugin-vue": "^5.2.3", 80 | "husky": "^0.14.3", 81 | "lint-staged": "^7.1.3", 82 | "poi": "^10.2.3", 83 | "prettier": "^1.19.1", 84 | "prettier-config-standard": "^1.0.1", 85 | "release-it": "^12.4.3", 86 | "rollup": "^1.27.9", 87 | "rollup-plugin-vue": "^5.1.4", 88 | "vue-html-loader": "^1.2.4", 89 | "vue-loader": "^15.7.2", 90 | "vue-style-loader": "^4.1.0", 91 | "vue-template-compiler": "^2.5.16", 92 | "vuex": "^3.0.2", 93 | "web3": "1.2.x" 94 | }, 95 | "peerDependencies": { 96 | "vue": "^2.5.16", 97 | "web3": "1.2.x" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | 2 | const NETWORKS = { 3 | 1: { 4 | name: 'Eth - Main Net', 5 | unit: 'ETH', 6 | isTest: false, 7 | hasExplorer: true, 8 | defaultGasPrice: 1, 9 | explorer: { 10 | root: 'https://etherscan.io/', 11 | address: 'address/', 12 | tx: 'tx/' 13 | } 14 | }, 15 | 2: { 16 | name: 'Eth - Deprecated Morden test network', 17 | unit: 'ETH', 18 | isTest: true, 19 | hasExplorer: false 20 | }, 21 | 3: { 22 | name: 'Eth - Ropsten test network', 23 | unit: 'ETH', 24 | isTest: true, 25 | hasExplorer: true, 26 | defaultGasPrice: 1, 27 | explorer: { 28 | root: 'https://ropsten.etherscan.io/', 29 | address: 'address/', 30 | tx: 'tx/' 31 | } 32 | }, 33 | 4: { 34 | name: 'Eth - Rinkeby test network', 35 | unit: 'ETH', 36 | isTest: true, 37 | hasExplorer: false 38 | }, 39 | 5: { 40 | name: 'Eth - Görli test network', 41 | unit: 'ETH', 42 | isTest: true, 43 | hasExplorer: true, 44 | defaultGasPrice: 1, 45 | explorer: { 46 | root: 'https://goerli.etherscan.io/', 47 | address: 'address/', 48 | tx: 'tx/' 49 | } 50 | }, 51 | 42: { 52 | name: 'Eth - Kovan test network', 53 | unit: 'ETH', 54 | isTest: true, 55 | hasExplorer: false 56 | }, 57 | 66: { 58 | name: 'Aldwych network', 59 | unit: 'ETH', 60 | isTest: true, 61 | hasExplorer: true, 62 | defaultGasPrice: 1, 63 | explorer: { 64 | root: 'https://explorer.aldwych.blaquetec.org/', 65 | address: 'account/', 66 | tx: 'tx/' 67 | } 68 | }, 69 | 77: { 70 | name: 'POA - Sokol test network', 71 | unit: 'SPOA', 72 | isTest: true, 73 | hasExplorer: true, 74 | defaultGasPrice: 1, 75 | explorer: { 76 | root: 'https://sokol-explorer.poa.network/', 77 | address: 'account/', 78 | tx: 'tx/' 79 | } 80 | }, 81 | 99: { 82 | name: 'POA - Main Net', 83 | unit: 'POA', 84 | isTest: false, 85 | hasExplorer: true, 86 | defaultGasPrice: 1, 87 | explorer: { 88 | root: 'https://sokol-explorer.poa.network/', 89 | address: 'account/', 90 | tx: 'tx/' 91 | } 92 | }, 93 | 100: { 94 | name: 'xDAI', 95 | unit: 'xDAI', 96 | isTest: false, 97 | hasExplorer: true, 98 | defaultGasPrice: 1, 99 | explorer: { 100 | root: 'https://blockscout.com/poa/xdai/', 101 | address: 'account/', 102 | tx: 'tx/' 103 | } 104 | }, 105 | 4447: { 106 | name: 'Eth - Truffle Develop Network', 107 | unit: 'ETH', 108 | isTest: true, 109 | hasExplorer: false 110 | }, 111 | 5777: { 112 | name: 'Eth - Ganache Blockchain', 113 | unit: 'ETH', 114 | isTest: true, 115 | hasExplorer: false 116 | } 117 | } 118 | 119 | export const getNetwork = networkId => NETWORKS[networkId] ? NETWORKS[networkId] : {} 120 | 121 | export const explorer = networkId => (type, id) => { 122 | const explorer = getNetwork(networkId).explorer 123 | if (!explorer || !explorer[type]) return null 124 | return `${explorer.root}${explorer[type]}${id}` 125 | } 126 | -------------------------------------------------------------------------------- /examples/vue-example/main.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 67 | 68 | 127 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # vue-ethereum 3 | 4 | Vue and Nuxt plugins for easy access to Ethereum (using web3.js 1.x) (Vuex not needed) 5 | 6 | 7 | ### Installation 8 | 9 | Install via [yarn](https://github.com/yarnpkg/yarn) 10 | 11 | ```bash 12 | yarn add vue-ethereum 13 | ``` 14 | 15 | or npm 16 | 17 | ```bash 18 | npm i vue-ethereum 19 | ``` 20 | 21 | 22 | ### Vue plugin usage 23 | 24 | ```js 25 | import VueEthereum from 'vue-ethereum' 26 | 27 | Vue.use(VueEthereum) 28 | 29 | new Vue({ 30 | // your vue config 31 | eth: new VueEthereum(), 32 | }) 33 | ``` 34 | 35 | ## Nuxt plugin usage 36 | 37 | Add `vue-ethereum/nuxt` to modules section of `nuxt.config.js` 38 | 39 | ```js 40 | { 41 | modules: [ 'vue-ethereum/nuxt' ] 42 | } 43 | ``` 44 | 45 | ## Global Helpers 46 | 47 | **vue-ethereum** provides high level helpers to use in your templates. 48 | All features can be obtained from $eth property in Vue components. 49 | 50 | For example in a vue file: 51 | 52 | ```html 53 |

54 | Connected to {{ $eth.networkName }} 55 |

56 | 57 | ``` 58 | ```js 59 | export default { 60 | mounted () { 61 | this.$eth.connect(); 62 | } 63 | } 64 | ``` 65 | 66 | #### `.on('connected, )` 67 | #### `.on('networkChanged, )` 68 | #### `.on('accountsChanged', )` 69 | 70 | Define callback functions that will be executed respectively after 71 | a connection, a network change and an account change. 72 | 73 | #### `.connect()` 74 | 75 | Connect vue to the current window provider. 76 | 77 | #### `.disconnect()` 78 | 79 | Disconnect vue to the current window provider. 80 | 81 | #### `.explorer(,)` 82 | 83 | Return an Url to the current network explorer depending on the first argument: 84 | * with type='address': the address page corresponding to the address 85 | * with type='tx': the transaction page corresponding to the tx 86 | 87 | Urls created using .explorer are automatically updated when the network is changed. 88 | 89 | #### `.balance(
)` 90 | 91 | Return the balance
in Ether (automatically updated when network or account is changed). 92 | 93 | #### `.walletDetected` 94 | 95 | Return true if a wallet has been detected. 96 | 97 | #### `.walletType` 98 | 99 | Return a description string of the current wallet detected (if possible). Example: 'MetaMask (or compatible)' 100 | 101 | #### `.isConnected` 102 | 103 | Return true if a wallet has been detected. 104 | 105 | #### `.selectedAddress` 106 | 107 | Return the current address selected in the connected wallet. 108 | 109 | #### `.accounts` 110 | 111 | Return an Array of all current accounts in the connected wallet (if possible). 'selectedAddress' 112 | is always included in this array. 113 | 114 | #### `.networkId` 115 | 116 | Return the Id of the current network (automatically updated when network is changed). 117 | 118 | #### `.networkName` 119 | 120 | Return a description string of the network detected (automatically updated when network is changed). Example: 'Ropsten'. 121 | 122 | #### `.isTestNetwork` 123 | 124 | Return true if the current network is a test network (automatically updated when network is changed). 125 | 126 | #### `.web3` 127 | 128 | Get a web3.js Javascript instance with the current connected provider. Please check 129 | [web3.js (1.x)](https://web3js.readthedocs.io/en/v1.2.1/) documentation to use this handler. 130 | 131 | #### `.error` 132 | 133 | Return the last error string from RPC connection. 134 | 135 | 136 | **work in progress for beta version, please see example in `examples/vue-example`**. 137 | 138 | 139 | ## Examples 140 | 141 | Use `npm run dev-vue` to run a simple example locally. 142 | 143 | ### Other repositories using vue-ethereum 144 | 145 | * [RGE testnet faucet](https://github.com/TheRougeProject/rge-faucet) 146 | 147 | 148 | ## Licensed under MIT 149 | -------------------------------------------------------------------------------- /src/watcher.js: -------------------------------------------------------------------------------- 1 | 2 | import Web3 from 'web3' 3 | 4 | const Web3Watcher = () => { 5 | const $ = { 6 | injected: null, 7 | instance: null, 8 | accounts: [], 9 | networkId: null, 10 | walletType: null, 11 | state: { 12 | init: 0, 13 | update: 0, 14 | error: null, 15 | isConnected: false, 16 | events: false 17 | } 18 | } 19 | 20 | const eventHandler = {} 21 | 22 | let stateHook = state => { throw new Error('Web3Watcher stateHook not set') } 23 | 24 | $.setStateHook = fn => { stateHook = fn } 25 | 26 | $.on = (event, fn) => { eventHandler[event] = fn } 27 | 28 | const updateState = data => { 29 | $.state = { ...$.state, ...data, update: $.state.update + 1 } 30 | stateHook($.state) 31 | } 32 | 33 | const onAccountsChanged = accounts => { 34 | $.accounts = accounts 35 | updateState({}) 36 | typeof eventHandler.accountsChanged === 'function' && eventHandler.accountsChanged($) 37 | } 38 | 39 | const onNetworkChanged = networkId => { 40 | $.networkId = networkId 41 | updateState({}) 42 | typeof eventHandler.networkChanged === 'function' && eventHandler.networkChanged($) 43 | } 44 | 45 | $.init = async options => { 46 | if (window.ethereum) { 47 | try { 48 | $.injected = window.ethereum 49 | if ($.injected.isMetaMask) { 50 | $.state = { ...$.state, events: true } 51 | window.ethereum.autoRefreshOnNetworkChange = false 52 | window.ethereum.on('accountsChanged', onAccountsChanged) 53 | window.ethereum.on('networkChanged', onNetworkChanged) 54 | } 55 | $.accounts = await window.ethereum.enable() 56 | $.instance = new Web3(window.ethereum) 57 | $.networkId = window.ethereum.networkVersion 58 | $.state = { 59 | ...$.state, 60 | isConnected: await $.instance.eth.net.isListening() 61 | } 62 | updateState({ init: $.state.init + 1 }) 63 | } catch (error) { 64 | $.state = { ...$.state, error: error.message, isConnected: false } 65 | updateState({}) 66 | } 67 | } else { 68 | try { 69 | if (window.web3.currentProvider) { 70 | $.injected = window.web3 71 | $.instance = new Web3(window.web3.currentProvider) 72 | } 73 | updateState({ init: $.state.init + 1 }) 74 | } catch (error) { 75 | $.state = { ...$.state, error: error.message, isConnected: false } 76 | updateState({}) 77 | } 78 | } 79 | typeof eventHandler.connected === 'function' && $.state.isConnected && eventHandler.connected($) 80 | $.walletType = await $.getWalletType() 81 | if (!$.networkId) $.networkId = await $.getId() 82 | updateState({}) 83 | return Promise.resolve($.state) 84 | } 85 | 86 | $.reset = () => { 87 | } 88 | 89 | $.getId = () => 90 | new Promise((resolve, reject) => { 91 | if (!$.instance) return reject(new Error('not connected')) 92 | $.instance.eth.net.getId((err, networkId) => { 93 | if (err) { 94 | reject(err) 95 | } else { 96 | resolve(networkId) 97 | } 98 | }) 99 | }) 100 | 101 | $.getWalletType = () => new Promise((resolve, reject) => { 102 | if (!$.instance || !$.instance.currentProvider) return reject(new Error('can determine provider')) 103 | const provider = $.instance.currentProvider 104 | // TODO find new heuristics 105 | if (provider.isNiftyWallet) { 106 | return resolve('Nifty') 107 | } 108 | if (provider.isMetaMask) { 109 | /* some fork of Metamask may identify as Metamask */ 110 | return resolve('MetaMask (or compatible)') 111 | } 112 | if (provider.isTrust) { 113 | return resolve('Trust') 114 | } 115 | return resolve('unknown') 116 | }) 117 | 118 | $.getAccounts = () => new Promise((resolve, reject) => { 119 | if (!$.instance) return reject(new Error('not connected')) 120 | $.instance.eth.getAccounts((err, accounts) => { 121 | if (err) { 122 | reject(err) 123 | } else { 124 | resolve(accounts) 125 | } 126 | }) 127 | }) 128 | 129 | $.getBalance = (account) => new Promise((resolve, reject) => { 130 | if (!$.instance) return reject(new Error('not connected')) 131 | $.instance.eth.getBalance(account, (err, result) => { 132 | if (err) { 133 | reject(err) 134 | } else { 135 | const balance = $.instance.utils.fromWei(result.toString(10), 'ether') 136 | resolve(balance) 137 | } 138 | }) 139 | }) 140 | 141 | return $ 142 | } 143 | 144 | export default Web3Watcher 145 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | 2 | // import vWeb3Component from './components/eth-tx.vue' 3 | 4 | import { getNetwork, explorer } from './constants.js' 5 | 6 | import Web3Watcher from './watcher.js' 7 | 8 | const isDebug = () => process.env.NODE_ENV !== 'production' 9 | 10 | const web3Watcher = Web3Watcher() // ADD potential option 11 | 12 | export default class VueEthereum { 13 | constructor (options = {}) { 14 | const defaults = { 15 | accessorName: '$eth', 16 | // Vuex Options 17 | useVuex: false 18 | // vuexModuleName: 'eth', 19 | // Components 20 | // registerComponent: true, 21 | // Directives 22 | // registerDirective: true, 23 | } 24 | this.options = { 25 | ...defaults, 26 | ...options 27 | } 28 | this.initialized = false 29 | } 30 | 31 | init (Vue, store) { 32 | if (isDebug() && !install.installed) { 33 | console.warn( 34 | // `[vue-ethereum] not installed. Make sure to call Vue.use(VueEthereum) before init root instance.` 35 | ) 36 | } 37 | 38 | if (this.initialized) { 39 | return 40 | } 41 | 42 | if (this.options.registerComponent) { 43 | // Vue.component(this.options.componentName, vWeb3Component) 44 | } 45 | 46 | if (this.options.useVuex) { 47 | // const { vuexModuleName } = this.options 48 | // if (!store) { 49 | throw new Error('[vue-ethereum] Vuex mode not yet available.') 50 | // } 51 | } else { 52 | this.stateHandler = new Vue({ 53 | data () { 54 | return { 55 | web3State: null, 56 | accounts: [], 57 | networkId: null, 58 | walletType: null, 59 | balanceOf: {} 60 | } 61 | }, 62 | computed: { 63 | error () { 64 | return this.web3State && this.web3State.error 65 | }, 66 | isConnected () { 67 | return this.web3State && this.web3State.isConnected 68 | }, 69 | networkName () { 70 | return getNetwork(this.networkId).name 71 | }, 72 | isTestNetwork () { 73 | return getNetwork(this.networkId).isTest 74 | }, 75 | balance () { 76 | return account => this.balanceOf[account] 77 | } 78 | }, 79 | watch: { 80 | web3State: function (val, oldVal) { 81 | this.accounts = web3Watcher.accounts 82 | this.networkId = web3Watcher.networkId 83 | this.walletType = web3Watcher.walletType 84 | } 85 | }, 86 | methods: { 87 | saveWeb3State (s) { 88 | this.web3State = s 89 | }, 90 | async getBalance (account) { 91 | Vue.set(this.balanceOf, account, await web3Watcher.getBalance(account)) 92 | } 93 | } 94 | }) 95 | } 96 | 97 | this.initialized = true 98 | } 99 | 100 | async connect () { 101 | web3Watcher.setStateHook(this.stateHandler.saveWeb3State) 102 | web3Watcher.init() 103 | } 104 | 105 | disconnect () { 106 | this.stateHandler.saveWeb3State(null) 107 | this.stateHandler.accounts = [] 108 | this.stateHandler.networkId = null 109 | this.stateHandler.walletType = null 110 | } 111 | 112 | /* helpers */ 113 | 114 | get walletDetected () { 115 | return !!this.stateHandler.walletType 116 | } 117 | 118 | get walletType () { 119 | return this.stateHandler.walletType 120 | } 121 | 122 | get isConnected () { 123 | return this.stateHandler.isConnected 124 | } 125 | 126 | get error () { 127 | return this.stateHandler.error 128 | } 129 | 130 | get networkId () { 131 | return this.stateHandler.networkId 132 | } 133 | 134 | get networkName () { 135 | return this.stateHandler.networkName 136 | } 137 | 138 | get isTestNetwork () { 139 | return this.stateHandler.isTestNetwork 140 | } 141 | 142 | get accounts () { 143 | return this.stateHandler.accounts 144 | } 145 | 146 | get selectedAddress () { 147 | return this.stateHandler.accounts[0] 148 | } 149 | 150 | get web3 () { 151 | return web3Watcher.instance 152 | } 153 | 154 | on (event, fn) { 155 | web3Watcher.on(event, fn) 156 | } 157 | 158 | explorer (type, id) { 159 | return explorer(this.stateHandler.networkId)(type, id) 160 | } 161 | 162 | balance (account) { 163 | this.stateHandler.getBalance(account) 164 | return this.stateHandler.balance(account) 165 | } 166 | } 167 | 168 | export function install (Vue) { 169 | if (install.installed && Vue) { 170 | if (isDebug()) { 171 | console.warn('[vue-ethereum] already installed. Vue.use(VueEthereum) should be called only once.') 172 | } 173 | return 174 | } 175 | 176 | Vue.mixin({ 177 | /** 178 | * VueEthereum init hook, injected into each instances init hooks list. 179 | */ 180 | beforeCreate () { 181 | const { eth, store, parent } = this.$options 182 | 183 | let instance = null 184 | if (eth) { 185 | instance = typeof eth === 'function' ? new eth() : eth // eslint-disable-line new-cap 186 | // Inject store 187 | instance.init(Vue, store) 188 | } else if (parent && parent.__$ethInstance) { 189 | instance = parent.__$ethInstance 190 | instance.init(Vue, parent.$store) 191 | } 192 | 193 | if (instance) { 194 | // Store helper for internal use 195 | this.__$ethInstance = instance 196 | this[instance.options.accessorName] = instance 197 | } 198 | } 199 | }) 200 | 201 | install.installed = true 202 | } 203 | 204 | VueEthereum.install = install 205 | --------------------------------------------------------------------------------