├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── README.md ├── box-img-lg-template.png ├── box-img-lg.png ├── box-img-sm-template.png ├── box-img-sm.png ├── contracts ├── Migrations.sol └── eip20 │ ├── EIP20.sol │ ├── EIP20Factory.sol │ └── EIP20Interface.sol ├── migrations ├── 1_initial_migration.js ├── 2_deploy_tokens.js └── 3_deploy_factory.js ├── nuxt.config.js ├── package-lock.json ├── package.json ├── src ├── assets │ └── README.md ├── components │ ├── AppLogo.vue │ └── README.md ├── layouts │ ├── README.md │ └── default.vue ├── middleware │ └── README.md ├── pages │ ├── README.md │ └── index.vue ├── plugins │ ├── README.md │ └── web3.js ├── static │ ├── README.md │ └── favicon.ico └── store │ ├── README.md │ ├── eip20.js │ └── index.js ├── test ├── .placeholder ├── eip20 │ ├── eip20.js │ └── eip20Factory.js └── helpers │ └── assertRevert.js ├── truffle-box.json ├── truffle-config.js └── truffle.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true 6 | }, 7 | parserOptions: { 8 | parser: 'babel-eslint' 9 | }, 10 | extends: [ 11 | 'eslint:recommended', 12 | // https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention 13 | // consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules. 14 | 'plugin:vue/recommended', 15 | 'plugin:prettier/recommended' 16 | ], 17 | // required to lint *.vue files 18 | plugins: [ 19 | 'vue' 20 | ], 21 | // add your custom rules here 22 | rules: { 23 | 'semi': [2, 'never'], 24 | 'no-console': 'off', 25 | 'no-debugger': 'off', 26 | 'vue/max-attributes-per-line': 'off', 27 | 'prettier/prettier': ['error', {semi: false, singleQuote: true, useTabs: true}] 28 | } 29 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | 3 | .nuxt 4 | 5 | # Dependency directories 6 | node_modules/ 7 | 8 | # Truffle 9 | build 10 | !build/README.md 11 | dist -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![nuxt-box](https://storage.googleapis.com/paperchain-assets/nuxt-box-banner.png) 2 | 3 | # Nuxt-box 4 | Nuxt-box is a truffle box using the [Nuxt.js](https://nuxtjs.org) framework to create a [Vue.js](https://vuejs.org/) application that can interact with the smart contracts on [Ethereum](https://ethereum.org/). 5 | 6 | ## Setup & Installation 7 | - Install [truffle](http://truffleframework.com): `npm i -g truffle` 8 | - Download the box. This also takes care of installing the necessary dependencies: `truffle unbox Paperchain/nuxt-box` 9 | - Install [Metamask browser extension](https://metamask.io/) 10 | 11 | ## Running the Application 12 | 13 | If you have MetaMask set for your browser, configure a 14 | Custom RPC with address: http://localhost:9545 from Metamask Networks tab. 15 | 16 | 1) Open terminal and run the development server: `truffle develop` 17 | 2) Connect local-rpc account with MetaMask. Follow [this answer](https://ethereum.stackexchange.com/questions/30593/how-can-i-import-the-accounts-from-truffle-develop-into-metamask) on Ethereum StackExchange. 18 | This account will have tokens and ether for transactions. 19 | 3) Deploy the contracts to the local-rpc: `migrate --reset` 20 | 4) Copy the token address from the terminal: 21 | 22 | ``` 23 | EIP20: 0x345ca3e014aaf5dca488057592ee47305d9b3e10 24 | ``` 25 | 26 | 5) Paste the token address to **src/store/eip20.js** where it says: 27 | 28 | ``` 29 | const tokenAddress = '0x345ca3e014aaf5dca488057592ee47305d9b3e10' 30 | // insert deployed EIP20 token address here 31 | ``` 32 | 33 | 6) Open a new terminal tab and run the webapp: `npm run dev` 34 | 35 | 36 | ## Web App Commands 37 | 38 | ``` bash 39 | # install dependencies 40 | $ npm install # Or yarn install 41 | 42 | # serve with hot reload at localhost:3000 43 | $ npm run dev 44 | 45 | # build for production and launch server 46 | $ npm run build 47 | $ npm start 48 | 49 | # generate static project using 50 | $ npm run generate 51 | 52 | # lint or lintfix 53 | $ npm run lint 54 | $ npm run lintfix 55 | ``` 56 | 57 | ## Truffle Commands 58 | 59 | ``` bash 60 | # run contract tests 61 | $ truffle test 62 | 63 | # run truffle development mode (run local blockchain) 64 | $ truffle develop 65 | 66 | # deploy contracts to local blockchain 67 | $ truffle migrate --reset 68 | $ migrate --reset (when in development mode) 69 | ``` 70 | 71 | 72 | ## Credits 73 | 74 | For example purposes this boilerplate uses [EIP20 token contracts made by ConsenSys](https://github.com/ConsenSys/Tokens/tree/master/contracts/eip20). 75 | -------------------------------------------------------------------------------- /box-img-lg-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Paperchain/nuxt-box/efc8cdf270865bed5f6a8968e4240c61d28fd54f/box-img-lg-template.png -------------------------------------------------------------------------------- /box-img-lg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Paperchain/nuxt-box/efc8cdf270865bed5f6a8968e4240c61d28fd54f/box-img-lg.png -------------------------------------------------------------------------------- /box-img-sm-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Paperchain/nuxt-box/efc8cdf270865bed5f6a8968e4240c61d28fd54f/box-img-sm-template.png -------------------------------------------------------------------------------- /box-img-sm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Paperchain/nuxt-box/efc8cdf270865bed5f6a8968e4240c61d28fd54f/box-img-sm.png -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // solhint-disable 2 | pragma solidity ^0.4.4; 3 | 4 | 5 | contract Migrations { 6 | address public owner; 7 | uint public last_completed_migration; 8 | 9 | modifier restricted() { 10 | if (msg.sender == owner) _; 11 | } 12 | 13 | constructor() public { 14 | owner = msg.sender; 15 | } 16 | 17 | function setCompleted(uint completed) public restricted { 18 | last_completed_migration = completed; 19 | } 20 | 21 | function upgrade(address new_address) public restricted { 22 | Migrations upgraded = Migrations(new_address); 23 | upgraded.setCompleted(last_completed_migration); 24 | } 25 | } -------------------------------------------------------------------------------- /contracts/eip20/EIP20.sol: -------------------------------------------------------------------------------- 1 | /* 2 | Implements EIP20 token standard: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 3 | .*/ 4 | 5 | 6 | pragma solidity ^0.4.21; 7 | 8 | import "./EIP20Interface.sol"; 9 | 10 | 11 | contract EIP20 is EIP20Interface { 12 | 13 | uint256 constant private MAX_UINT256 = 2**256 - 1; 14 | mapping (address => uint256) public balances; 15 | mapping (address => mapping (address => uint256)) public allowed; 16 | /* 17 | NOTE: 18 | The following variables are OPTIONAL vanities. One does not have to include them. 19 | They allow one to customise the token contract & in no way influences the core functionality. 20 | Some wallets/interfaces might not even bother to look at this information. 21 | */ 22 | string public name; //fancy name: eg Simon Bucks 23 | uint8 public decimals; //How many decimals to show. 24 | string public symbol; //An identifier: eg SBX 25 | 26 | constructor( 27 | uint256 _initialAmount, 28 | string _tokenName, 29 | uint8 _decimalUnits, 30 | string _tokenSymbol 31 | ) public { 32 | balances[msg.sender] = _initialAmount; // Give the creator all initial tokens 33 | totalSupply = _initialAmount; // Update total supply 34 | name = _tokenName; // Set the name for display purposes 35 | decimals = _decimalUnits; // Amount of decimals for display purposes 36 | symbol = _tokenSymbol; // Set the symbol for display purposes 37 | } 38 | 39 | function transfer(address _to, uint256 _value) public returns (bool success) { 40 | require(balances[msg.sender] >= _value); 41 | balances[msg.sender] -= _value; 42 | balances[_to] += _value; 43 | emit Transfer(msg.sender, _to, _value); //solhint-disable-line indent, no-unused-vars 44 | return true; 45 | } 46 | 47 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { 48 | uint256 allowance = allowed[_from][msg.sender]; 49 | require(balances[_from] >= _value && allowance >= _value); 50 | balances[_to] += _value; 51 | balances[_from] -= _value; 52 | if (allowance < MAX_UINT256) { 53 | allowed[_from][msg.sender] -= _value; 54 | } 55 | emit Transfer(_from, _to, _value); //solhint-disable-line indent, no-unused-vars 56 | return true; 57 | } 58 | 59 | function balanceOf(address _owner) public view returns (uint256 balance) { 60 | return balances[_owner]; 61 | } 62 | 63 | function approve(address _spender, uint256 _value) public returns (bool success) { 64 | allowed[msg.sender][_spender] = _value; 65 | emit Approval(msg.sender, _spender, _value); //solhint-disable-line indent, no-unused-vars 66 | return true; 67 | } 68 | 69 | function allowance(address _owner, address _spender) public view returns (uint256 remaining) { 70 | return allowed[_owner][_spender]; 71 | } 72 | } -------------------------------------------------------------------------------- /contracts/eip20/EIP20Factory.sol: -------------------------------------------------------------------------------- 1 | import "./EIP20.sol"; 2 | 3 | pragma solidity ^0.4.21; 4 | 5 | 6 | contract EIP20Factory { 7 | 8 | mapping(address => address[]) public created; 9 | mapping(address => bool) public isEIP20; //verify without having to do a bytecode check. 10 | bytes public EIP20ByteCode; // solhint-disable-line var-name-mixedcase 11 | 12 | constructor() public { 13 | //upon creation of the factory, deploy a EIP20 (parameters are meaningless) and store the bytecode provably. 14 | address verifiedToken = createEIP20(10000, "Verify Token", 3, "VTX"); 15 | EIP20ByteCode = codeAt(verifiedToken); 16 | } 17 | 18 | //verifies if a contract that has been deployed is a Human Standard Token. 19 | //NOTE: This is a very expensive function, and should only be used in an eth_call. ~800k gas 20 | function verifyEIP20(address _tokenContract) public view returns (bool) { 21 | bytes memory fetchedTokenByteCode = codeAt(_tokenContract); 22 | 23 | if (fetchedTokenByteCode.length != EIP20ByteCode.length) { 24 | return false; //clear mismatch 25 | } 26 | 27 | //starting iterating through it if lengths match 28 | for (uint i = 0; i < fetchedTokenByteCode.length; i++) { 29 | if (fetchedTokenByteCode[i] != EIP20ByteCode[i]) { 30 | return false; 31 | } 32 | } 33 | return true; 34 | } 35 | 36 | function createEIP20(uint256 _initialAmount, string _name, uint8 _decimals, string _symbol) 37 | public 38 | returns (address) { 39 | 40 | EIP20 newToken = (new EIP20(_initialAmount, _name, _decimals, _symbol)); 41 | created[msg.sender].push(address(newToken)); 42 | isEIP20[address(newToken)] = true; 43 | //the factory will own the created tokens. You must transfer them. 44 | newToken.transfer(msg.sender, _initialAmount); 45 | return address(newToken); 46 | } 47 | 48 | //for now, keeping this internal. Ideally there should also be a live version of this that 49 | // any contract can use, lib-style. 50 | //retrieves the bytecode at a specific address. 51 | function codeAt(address _addr) internal view returns (bytes outputCode) { 52 | assembly { // solhint-disable-line no-inline-assembly 53 | // retrieve the size of the code, this needs assembly 54 | let size := extcodesize(_addr) 55 | // allocate output byte array - this could also be done without assembly 56 | // by using outputCode = new bytes(size) 57 | outputCode := mload(0x40) 58 | // new "memory end" including padding 59 | mstore(0x40, add(outputCode, and(add(add(size, 0x20), 0x1f), not(0x1f)))) 60 | // store length in memory 61 | mstore(outputCode, size) 62 | // actually retrieve the code, this needs assembly 63 | extcodecopy(_addr, add(outputCode, 0x20), 0, size) 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /contracts/eip20/EIP20Interface.sol: -------------------------------------------------------------------------------- 1 | // Abstract contract for the full ERC 20 Token standard 2 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 3 | pragma solidity ^0.4.21; 4 | 5 | 6 | contract EIP20Interface { 7 | /* This is a slight change to the ERC20 base standard. 8 | function totalSupply() constant returns (uint256 supply); 9 | is replaced with: 10 | uint256 public totalSupply; 11 | This automatically creates a getter function for the totalSupply. 12 | This is moved to the base contract since public getter functions are not 13 | currently recognised as an implementation of the matching abstract 14 | function by the compiler. 15 | */ 16 | /// total amount of tokens 17 | uint256 public totalSupply; 18 | 19 | /// @param _owner The address from which the balance will be retrieved 20 | /// @return The balance 21 | function balanceOf(address _owner) public view returns (uint256 balance); 22 | 23 | /// @notice send `_value` token to `_to` from `msg.sender` 24 | /// @param _to The address of the recipient 25 | /// @param _value The amount of token to be transferred 26 | /// @return Whether the transfer was successful or not 27 | function transfer(address _to, uint256 _value) public returns (bool success); 28 | 29 | /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from` 30 | /// @param _from The address of the sender 31 | /// @param _to The address of the recipient 32 | /// @param _value The amount of token to be transferred 33 | /// @return Whether the transfer was successful or not 34 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success); 35 | 36 | /// @notice `msg.sender` approves `_spender` to spend `_value` tokens 37 | /// @param _spender The address of the account able to transfer the tokens 38 | /// @param _value The amount of tokens to be approved for transfer 39 | /// @return Whether the approval was successful or not 40 | function approve(address _spender, uint256 _value) public returns (bool success); 41 | 42 | /// @param _owner The address of the account owning tokens 43 | /// @param _spender The address of the account able to transfer the tokens 44 | /// @return Amount of remaining tokens allowed to spent 45 | function allowance(address _owner, address _spender) public view returns (uint256 remaining); 46 | 47 | // solhint-disable-next-line no-simple-event-func-name 48 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 49 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 50 | } -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require('./Migrations.sol') 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations) 5 | } 6 | -------------------------------------------------------------------------------- /migrations/2_deploy_tokens.js: -------------------------------------------------------------------------------- 1 | const EIP20 = artifacts.require('./EIP20.sol') 2 | 3 | module.exports = deployer => { 4 | deployer.deploy(EIP20, 10000, 'Simon Bucks', 1, 'SBX') 5 | } 6 | -------------------------------------------------------------------------------- /migrations/3_deploy_factory.js: -------------------------------------------------------------------------------- 1 | const EIP20Factory = artifacts.require('./EIP20Factory.sol') 2 | 3 | module.exports = deployer => { 4 | deployer.deploy(EIP20Factory) 5 | } 6 | -------------------------------------------------------------------------------- /nuxt.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | /* 3 | ** Headers of the page 4 | */ 5 | head: { 6 | title: 'nuxt-web3-boilerplate', 7 | meta: [ 8 | { charset: 'utf-8' }, 9 | { name: 'viewport', content: 'width=device-width, initial-scale=1' }, 10 | { 11 | hid: 'description', 12 | name: 'description', 13 | content: 'Nuxt.js and web3 template project' 14 | } 15 | ], 16 | link: [{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }] 17 | }, 18 | /* 19 | ** Customize the progress bar color 20 | */ 21 | loading: { color: '#3B8070' }, 22 | /* 23 | ** Build configuration 24 | */ 25 | build: { 26 | vendor: ['web3'], 27 | /* 28 | ** Run ESLint on save 29 | */ 30 | extend(config, { isDev, isClient }) { 31 | if (isDev && isClient) { 32 | config.module.rules.push({ 33 | enforce: 'pre', 34 | test: /\.(js|vue)$/, 35 | loader: 'eslint-loader', 36 | exclude: /(node_modules)/ 37 | }) 38 | } 39 | } 40 | }, 41 | srcDir: 'src/', 42 | rootDir: './' 43 | } 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-web3-boilerplate", 3 | "version": "1.0.0", 4 | "description": "Nuxt.js and web3 template project", 5 | "author": "pyyding ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "nuxt", 9 | "build": "nuxt build", 10 | "start": "nuxt start", 11 | "generate": "nuxt generate", 12 | "lint": "eslint --ext .js,.vue --ignore-path .gitignore .", 13 | "lintfix": "eslint --fix --ext .js,.vue --ignore-path .gitignore --ignore-pattern migrations/ --ignore-pattern test/ .", 14 | "precommit": "npm run lint" 15 | }, 16 | "dependencies": { 17 | "nuxt": "^1.0.0", 18 | "web3": "^1.0.0-beta.34", 19 | "web3-eth-abi": "^1.0.0-beta.34", 20 | "websocket": "^1.0.26" 21 | }, 22 | "devDependencies": { 23 | "babel-eslint": "^8.2.3", 24 | "eslint": "^4.19.1", 25 | "eslint-config-prettier": "^2.9.0", 26 | "eslint-friendly-formatter": "^3.0.0", 27 | "eslint-loader": "^1.9.0", 28 | "eslint-plugin-prettier": "^2.6.0", 29 | "eslint-plugin-vue": "^4.5.0", 30 | "prettier": "^1.12.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/assets/README.md: -------------------------------------------------------------------------------- 1 | # ASSETS 2 | 3 | This directory contains your un-compiled assets such as LESS, SASS, or JavaScript. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/assets#webpacked 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /src/components/AppLogo.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 80 | -------------------------------------------------------------------------------- /src/components/README.md: -------------------------------------------------------------------------------- 1 | # COMPONENTS 2 | 3 | The components directory contains your Vue.js Components. 4 | Nuxt.js doesn't supercharge these components. 5 | 6 | **This directory is not required, you can delete it if you don't want to use it.** 7 | -------------------------------------------------------------------------------- /src/layouts/README.md: -------------------------------------------------------------------------------- 1 | # LAYOUTS 2 | 3 | This directory contains your Application Layouts. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/views#layouts 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /src/layouts/default.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 56 | -------------------------------------------------------------------------------- /src/middleware/README.md: -------------------------------------------------------------------------------- 1 | # MIDDLEWARE 2 | 3 | This directory contains your Application Middleware. 4 | The middleware lets you define custom function to be ran before rendering a page or a group of pages (layouts). 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing#middleware 8 | 9 | **This directory is not required, you can delete it if you don't want to use it.** 10 | -------------------------------------------------------------------------------- /src/pages/README.md: -------------------------------------------------------------------------------- 1 | # PAGES 2 | 3 | This directory contains your Application Views and Routes. 4 | The framework reads all the .vue files inside this directory and creates the router of your application. 5 | 6 | More information about the usage of this directory in the documentation: 7 | https://nuxtjs.org/guide/routing 8 | -------------------------------------------------------------------------------- /src/pages/index.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 66 | 67 | 112 | -------------------------------------------------------------------------------- /src/plugins/README.md: -------------------------------------------------------------------------------- 1 | # PLUGINS 2 | 3 | This directory contains your Javascript plugins that you want to run before instantiating the root vue.js application. 4 | 5 | More information about the usage of this directory in the documentation: 6 | https://nuxtjs.org/guide/plugins 7 | 8 | **This directory is not required, you can delete it if you don't want to use it.** 9 | -------------------------------------------------------------------------------- /src/plugins/web3.js: -------------------------------------------------------------------------------- 1 | import Web3 from 'web3' 2 | 3 | const instance = new Web3(Web3.givenProvider || 'http://localhost:9545') 4 | 5 | export default instance 6 | -------------------------------------------------------------------------------- /src/static/README.md: -------------------------------------------------------------------------------- 1 | # STATIC 2 | 3 | This directory contains your static files. 4 | Each file inside this directory is mapped to /. 5 | 6 | Example: /static/robots.txt is mapped as /robots.txt. 7 | 8 | More information about the usage of this directory in the documentation: 9 | https://nuxtjs.org/guide/assets#static 10 | 11 | **This directory is not required, you can delete it if you don't want to use it.** 12 | -------------------------------------------------------------------------------- /src/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Paperchain/nuxt-box/efc8cdf270865bed5f6a8968e4240c61d28fd54f/src/static/favicon.ico -------------------------------------------------------------------------------- /src/store/README.md: -------------------------------------------------------------------------------- 1 | # STORE 2 | 3 | This directory contains your Vuex Store files. 4 | Vuex Store option is implemented in the Nuxt.js framework. 5 | Creating a index.js file in this directory activate the option in the framework automatically. 6 | 7 | More information about the usage of this directory in the documentation: 8 | https://nuxtjs.org/guide/vuex-store 9 | 10 | **This directory is not required, you can delete it if you don't want to use it.** 11 | -------------------------------------------------------------------------------- /src/store/eip20.js: -------------------------------------------------------------------------------- 1 | import web3 from '~/plugins/web3' 2 | import EIP20 from '../../build/contracts/EIP20' 3 | import web3Abi from 'web3-eth-abi' 4 | 5 | const tokenAddress = '0x345ca3e014aaf5dca488057592ee47305d9b3e10' // insert deployed EIP20 token address here 6 | const eip20 = new web3.eth.Contract(EIP20.abi, tokenAddress) 7 | 8 | let account 9 | web3.eth.getAccounts().then(res => { 10 | account = res[0] 11 | }) 12 | 13 | export const state = () => ({}) 14 | 15 | export const mutations = {} 16 | 17 | export const actions = { 18 | getName() { 19 | return eip20.methods.name().call({ from: account }) 20 | }, 21 | async transfer(context, params) { 22 | const transferMethod = EIP20.abi.find(method => { 23 | return method.name === 'transfer' 24 | }) 25 | 26 | const transferMethodTransactionData = web3Abi.encodeFunctionCall( 27 | transferMethod, 28 | [params.to, web3.utils.toBN(params.value)] 29 | ) 30 | 31 | const estimateGas = await web3.eth.estimateGas({ 32 | from: account, 33 | to: tokenAddress, 34 | data: transferMethodTransactionData 35 | }) 36 | 37 | const receipt = await web3.eth.sendTransaction({ 38 | from: account, 39 | to: tokenAddress, 40 | data: transferMethodTransactionData, 41 | value: 0, 42 | gas: estimateGas 43 | }) 44 | 45 | return receipt 46 | } 47 | } 48 | 49 | export const getters = {} 50 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | export const state = () => ({}) 2 | 3 | export const mutations = {} 4 | 5 | export const actions = {} 6 | 7 | export const getters = {} 8 | -------------------------------------------------------------------------------- /test/.placeholder: -------------------------------------------------------------------------------- 1 | This is a placeholder file to ensure the parent directory in the git repository. Feel free to remove. 2 | -------------------------------------------------------------------------------- /test/eip20/eip20.js: -------------------------------------------------------------------------------- 1 | const { assertRevert } = require('../helpers/assertRevert'); 2 | 3 | const EIP20Abstraction = artifacts.require('EIP20'); 4 | let HST; 5 | 6 | contract('EIP20', (accounts) => { 7 | beforeEach(async () => { 8 | HST = await EIP20Abstraction.new(10000, 'Simon Bucks', 1, 'SBX', { from: accounts[0] }); 9 | }); 10 | 11 | it('creation: should create an initial balance of 10000 for the creator', async () => { 12 | const balance = await HST.balanceOf.call(accounts[0]); 13 | assert.strictEqual(balance.toNumber(), 10000); 14 | }); 15 | 16 | it('creation: test correct setting of vanity information', async () => { 17 | const name = await HST.name.call(); 18 | assert.strictEqual(name, 'Simon Bucks'); 19 | 20 | const decimals = await HST.decimals.call(); 21 | assert.strictEqual(decimals.toNumber(), 1); 22 | 23 | const symbol = await HST.symbol.call(); 24 | assert.strictEqual(symbol, 'SBX'); 25 | }); 26 | 27 | it('creation: should succeed in creating over 2^256 - 1 (max) tokens', async () => { 28 | // 2^256 - 1 29 | const HST2 = await EIP20Abstraction.new('115792089237316195423570985008687907853269984665640564039457584007913129639935', 'Simon Bucks', 1, 'SBX', { from: accounts[0] }); 30 | const totalSupply = await HST2.totalSupply(); 31 | const match = totalSupply.equals('1.15792089237316195423570985008687907853269984665640564039457584007913129639935e+77'); 32 | assert(match, 'result is not correct'); 33 | }); 34 | 35 | // TRANSERS 36 | // normal transfers without approvals 37 | it('transfers: ether transfer should be reversed.', async () => { 38 | const balanceBefore = await HST.balanceOf.call(accounts[0]); 39 | assert.strictEqual(balanceBefore.toNumber(), 10000); 40 | 41 | await assertRevert(new Promise((resolve, reject) => { 42 | web3.eth.sendTransaction({ from: accounts[0], to: HST.address, value: web3.toWei('10', 'Ether') }, (err, res) => { 43 | if (err) { reject(err); } 44 | resolve(res); 45 | }); 46 | })); 47 | 48 | const balanceAfter = await HST.balanceOf.call(accounts[0]); 49 | assert.strictEqual(balanceAfter.toNumber(), 10000); 50 | }); 51 | 52 | it('transfers: should transfer 10000 to accounts[1] with accounts[0] having 10000', async () => { 53 | await HST.transfer(accounts[1], 10000, { from: accounts[0] }); 54 | const balance = await HST.balanceOf.call(accounts[1]); 55 | assert.strictEqual(balance.toNumber(), 10000); 56 | }); 57 | 58 | it('transfers: should fail when trying to transfer 10001 to accounts[1] with accounts[0] having 10000', async () => { 59 | await assertRevert(HST.transfer.call(accounts[1], 10001, { from: accounts[0] })); 60 | }); 61 | 62 | it('transfers: should handle zero-transfers normally', async () => { 63 | assert(await HST.transfer.call(accounts[1], 0, { from: accounts[0] }), 'zero-transfer has failed'); 64 | }); 65 | 66 | // NOTE: testing uint256 wrapping is impossible since you can't supply > 2^256 -1 67 | // todo: transfer max amounts 68 | 69 | // APPROVALS 70 | it('approvals: msg.sender should approve 100 to accounts[1]', async () => { 71 | await HST.approve(accounts[1], 100, { from: accounts[0] }); 72 | const allowance = await HST.allowance.call(accounts[0], accounts[1]); 73 | assert.strictEqual(allowance.toNumber(), 100); 74 | }); 75 | 76 | // bit overkill. But is for testing a bug 77 | it('approvals: msg.sender approves accounts[1] of 100 & withdraws 20 once.', async () => { 78 | const balance0 = await HST.balanceOf.call(accounts[0]); 79 | assert.strictEqual(balance0.toNumber(), 10000); 80 | 81 | await HST.approve(accounts[1], 100, { from: accounts[0] }); // 100 82 | const balance2 = await HST.balanceOf.call(accounts[2]); 83 | assert.strictEqual(balance2.toNumber(), 0, 'balance2 not correct'); 84 | 85 | await HST.transferFrom.call(accounts[0], accounts[2], 20, { from: accounts[1] }); 86 | await HST.allowance.call(accounts[0], accounts[1]); 87 | await HST.transferFrom(accounts[0], accounts[2], 20, { from: accounts[1] }); // -20 88 | const allowance01 = await HST.allowance.call(accounts[0], accounts[1]); 89 | assert.strictEqual(allowance01.toNumber(), 80); // =80 90 | 91 | const balance22 = await HST.balanceOf.call(accounts[2]); 92 | assert.strictEqual(balance22.toNumber(), 20); 93 | 94 | const balance02 = await HST.balanceOf.call(accounts[0]); 95 | assert.strictEqual(balance02.toNumber(), 9980); 96 | }); 97 | 98 | // should approve 100 of msg.sender & withdraw 50, twice. (should succeed) 99 | it('approvals: msg.sender approves accounts[1] of 100 & withdraws 20 twice.', async () => { 100 | await HST.approve(accounts[1], 100, { from: accounts[0] }); 101 | const allowance01 = await HST.allowance.call(accounts[0], accounts[1]); 102 | assert.strictEqual(allowance01.toNumber(), 100); 103 | 104 | await HST.transferFrom(accounts[0], accounts[2], 20, { from: accounts[1] }); 105 | const allowance012 = await HST.allowance.call(accounts[0], accounts[1]); 106 | assert.strictEqual(allowance012.toNumber(), 80); 107 | 108 | const balance2 = await HST.balanceOf.call(accounts[2]); 109 | assert.strictEqual(balance2.toNumber(), 20); 110 | 111 | const balance0 = await HST.balanceOf.call(accounts[0]); 112 | assert.strictEqual(balance0.toNumber(), 9980); 113 | 114 | // FIRST tx done. 115 | // onto next. 116 | await HST.transferFrom(accounts[0], accounts[2], 20, { from: accounts[1] }); 117 | const allowance013 = await HST.allowance.call(accounts[0], accounts[1]); 118 | assert.strictEqual(allowance013.toNumber(), 60); 119 | 120 | const balance22 = await HST.balanceOf.call(accounts[2]); 121 | assert.strictEqual(balance22.toNumber(), 40); 122 | 123 | const balance02 = await HST.balanceOf.call(accounts[0]); 124 | assert.strictEqual(balance02.toNumber(), 9960); 125 | }); 126 | 127 | // should approve 100 of msg.sender & withdraw 50 & 60 (should fail). 128 | it('approvals: msg.sender approves accounts[1] of 100 & withdraws 50 & 60 (2nd tx should fail)', async () => { 129 | await HST.approve(accounts[1], 100, { from: accounts[0] }); 130 | const allowance01 = await HST.allowance.call(accounts[0], accounts[1]); 131 | assert.strictEqual(allowance01.toNumber(), 100); 132 | 133 | await HST.transferFrom(accounts[0], accounts[2], 50, { from: accounts[1] }); 134 | const allowance012 = await HST.allowance.call(accounts[0], accounts[1]); 135 | assert.strictEqual(allowance012.toNumber(), 50); 136 | 137 | const balance2 = await HST.balanceOf.call(accounts[2]); 138 | assert.strictEqual(balance2.toNumber(), 50); 139 | 140 | const balance0 = await HST.balanceOf.call(accounts[0]); 141 | assert.strictEqual(balance0.toNumber(), 9950); 142 | 143 | // FIRST tx done. 144 | // onto next. 145 | await assertRevert(HST.transferFrom.call(accounts[0], accounts[2], 60, { from: accounts[1] })); 146 | }); 147 | 148 | it('approvals: attempt withdrawal from account with no allowance (should fail)', async () => { 149 | await assertRevert(HST.transferFrom.call(accounts[0], accounts[2], 60, { from: accounts[1] })); 150 | }); 151 | 152 | it('approvals: allow accounts[1] 100 to withdraw from accounts[0]. Withdraw 60 and then approve 0 & attempt transfer.', async () => { 153 | await HST.approve(accounts[1], 100, { from: accounts[0] }); 154 | await HST.transferFrom(accounts[0], accounts[2], 60, { from: accounts[1] }); 155 | await HST.approve(accounts[1], 0, { from: accounts[0] }); 156 | await assertRevert(HST.transferFrom.call(accounts[0], accounts[2], 10, { from: accounts[1] })); 157 | }); 158 | 159 | it('approvals: approve max (2^256 - 1)', async () => { 160 | await HST.approve(accounts[1], '115792089237316195423570985008687907853269984665640564039457584007913129639935', { from: accounts[0] }); 161 | const allowance = await HST.allowance(accounts[0], accounts[1]); 162 | assert(allowance.equals('1.15792089237316195423570985008687907853269984665640564039457584007913129639935e+77')); 163 | }); 164 | 165 | // should approve max of msg.sender & withdraw 20 without changing allowance (should succeed). 166 | it('approvals: msg.sender approves accounts[1] of max (2^256 - 1) & withdraws 20', async () => { 167 | const balance0 = await HST.balanceOf.call(accounts[0]); 168 | assert.strictEqual(balance0.toNumber(), 10000); 169 | 170 | const max = '1.15792089237316195423570985008687907853269984665640564039457584007913129639935e+77'; 171 | await HST.approve(accounts[1], max, { from: accounts[0] }); 172 | const balance2 = await HST.balanceOf.call(accounts[2]); 173 | assert.strictEqual(balance2.toNumber(), 0, 'balance2 not correct'); 174 | 175 | await HST.transferFrom(accounts[0], accounts[2], 20, { from: accounts[1] }); 176 | const allowance01 = await HST.allowance.call(accounts[0], accounts[1]); 177 | assert(allowance01.equals(max)); 178 | 179 | const balance22 = await HST.balanceOf.call(accounts[2]); 180 | assert.strictEqual(balance22.toNumber(), 20); 181 | 182 | const balance02 = await HST.balanceOf.call(accounts[0]); 183 | assert.strictEqual(balance02.toNumber(), 9980); 184 | }); 185 | 186 | /* eslint-disable no-underscore-dangle */ 187 | it('events: should fire Transfer event properly', async () => { 188 | const res = await HST.transfer(accounts[1], '2666', { from: accounts[0] }); 189 | const transferLog = res.logs.find(element => element.event.match('Transfer')); 190 | assert.strictEqual(transferLog.args._from, accounts[0]); 191 | assert.strictEqual(transferLog.args._to, accounts[1]); 192 | assert.strictEqual(transferLog.args._value.toString(), '2666'); 193 | }); 194 | 195 | it('events: should fire Transfer event normally on a zero transfer', async () => { 196 | const res = await HST.transfer(accounts[1], '0', { from: accounts[0] }); 197 | const transferLog = res.logs.find(element => element.event.match('Transfer')); 198 | assert.strictEqual(transferLog.args._from, accounts[0]); 199 | assert.strictEqual(transferLog.args._to, accounts[1]); 200 | assert.strictEqual(transferLog.args._value.toString(), '0'); 201 | }); 202 | 203 | it('events: should fire Approval event properly', async () => { 204 | const res = await HST.approve(accounts[1], '2666', { from: accounts[0] }); 205 | const approvalLog = res.logs.find(element => element.event.match('Approval')); 206 | assert.strictEqual(approvalLog.args._owner, accounts[0]); 207 | assert.strictEqual(approvalLog.args._spender, accounts[1]); 208 | assert.strictEqual(approvalLog.args._value.toString(), '2666'); 209 | }); 210 | }); -------------------------------------------------------------------------------- /test/eip20/eip20Factory.js: -------------------------------------------------------------------------------- 1 | const EIP20Factory = artifacts.require('EIP20Factory'); 2 | 3 | contract('EIP20Factory', (accounts) => { 4 | it('Verify a Human Standard Token once deployed using both verification functions.', async () => { 5 | const factory = await EIP20Factory.new(); 6 | const newTokenAddr = await factory.createEIP20.call(100000, 'Simon Bucks', 2, 'SBX', { from: accounts[0] }); 7 | await factory.createEIP20(100000, 'Simon Bucks', 2, 'SBX', { from: accounts[0] }); 8 | const res = await factory.verifyEIP20.call(newTokenAddr, { from: accounts[0] }); 9 | assert(res, 'Could not verify the token.'); 10 | }); 11 | }); -------------------------------------------------------------------------------- /test/helpers/assertRevert.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | assertRevert: async (promise) => { 3 | try { 4 | await promise; 5 | } catch (error) { 6 | const revertFound = error.message.search('revert') >= 0; 7 | assert(revertFound, `Expected "revert", got ${error} instead`); 8 | return; 9 | } 10 | assert.fail('Expected revert not received'); 11 | }, 12 | }; -------------------------------------------------------------------------------- /truffle-box.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": [ 3 | "README.md", 4 | ".gitignore" 5 | ], 6 | "commands": { 7 | "Compile contracts": "truffle compile", 8 | "Migrate contracts": "truffle migrate", 9 | "Test contracts": "truffle test" 10 | }, 11 | "hooks": { 12 | "post-unpack": "npm install" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | } 5 | -------------------------------------------------------------------------------- /truffle.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // See 3 | // to customize your Truffle configuration! 4 | } 5 | --------------------------------------------------------------------------------