├── .eslintignore ├── babel.config.js ├── public ├── favicon.ico ├── simple.sol ├── index.html ├── network.json ├── contracts.json └── ERC20.sol ├── src ├── assets │ ├── logo.png │ ├── icon │ │ ├── block.png │ │ ├── peer.png │ │ ├── compile@3x.png │ │ ├── contract.png │ │ ├── peer_small.png │ │ ├── run_small.png │ │ ├── block_small.png │ │ ├── trans_small.png │ │ └── transaction.png │ └── status_bar_prograss.png ├── router │ ├── index.js │ └── routes.js ├── language │ ├── index.js │ └── lib │ │ ├── sc.json │ │ └── en.json ├── api-config │ └── index.js ├── main.js ├── components │ ├── common │ │ ├── gui │ │ │ ├── InputString.vue │ │ │ ├── InterfaceInput.js │ │ │ ├── InputAny.vue │ │ │ ├── Loading.vue │ │ │ ├── InputBool.vue │ │ │ ├── InputAddress.vue │ │ │ ├── InputByte.vue │ │ │ └── InputUint.vue │ │ ├── svg │ │ │ ├── copy.vue │ │ │ └── compile.vue │ │ ├── function │ │ │ ├── Help.vue │ │ │ ├── Notice.vue │ │ │ ├── Selector.vue │ │ │ ├── SigninAccount.vue │ │ │ ├── SetTxConfig.vue │ │ │ └── CreateAccount.vue │ │ └── logs │ │ │ ├── TxLog.vue │ │ │ └── CreationLog.vue │ ├── Log.vue │ ├── Hello.vue │ ├── Chain.vue │ ├── Transfer.vue │ ├── Interact.vue │ └── Deploy.vue ├── store │ ├── modules │ │ ├── eth.js │ │ ├── accounts.js │ │ ├── log.js │ │ └── indexdb.js │ └── index.js ├── style.styl └── App.vue ├── .gitignore ├── vue.config.js ├── README.md ├── package.json └── server └── index.js /.eslintignore: -------------------------------------------------------------------------------- 1 | public/**/*.js 2 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/icon/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/block.png -------------------------------------------------------------------------------- /src/assets/icon/peer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/peer.png -------------------------------------------------------------------------------- /src/assets/icon/compile@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/compile@3x.png -------------------------------------------------------------------------------- /src/assets/icon/contract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/contract.png -------------------------------------------------------------------------------- /src/assets/icon/peer_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/peer_small.png -------------------------------------------------------------------------------- /src/assets/icon/run_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/run_small.png -------------------------------------------------------------------------------- /src/assets/icon/block_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/block_small.png -------------------------------------------------------------------------------- /src/assets/icon/trans_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/trans_small.png -------------------------------------------------------------------------------- /src/assets/icon/transaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/icon/transaction.png -------------------------------------------------------------------------------- /src/assets/status_bar_prograss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/truechain/truechain-stellar/HEAD/src/assets/status_bar_prograss.png -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | import routes from './routes.js' 5 | 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes 10 | }) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | eth/ 4 | dist/ 5 | npm-debug.log* 6 | yarn-debug.log* 7 | yarn-error.log* 8 | # package-lock.json* 9 | 10 | # Editor directories and files 11 | .idea 12 | .vscode 13 | *.suo 14 | *.ntvs* 15 | *.njsproj 16 | *.sln 17 | 18 | nohup.out* 19 | -------------------------------------------------------------------------------- /src/language/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueI18n from 'vue-i18n' 3 | 4 | import en from './lib/en.json' 5 | import sc from './lib/sc.json' 6 | 7 | Vue.use(VueI18n) 8 | 9 | const i18n = new VueI18n({ 10 | locale: 'sc', 11 | messages: { 12 | en, 13 | sc 14 | } 15 | }) 16 | 17 | export default i18n 18 | -------------------------------------------------------------------------------- /src/api-config/index.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | const URL = process.env.NODE_ENV === 'production' 4 | ? 'https://stellar.truechain.pro/ethserver' 5 | : 'http://localhost:3000' 6 | 7 | export default { 8 | compile (source, version) { 9 | const data = { 10 | source, 11 | version 12 | } 13 | return axios.post(`${URL}/compile`, data) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /public/simple.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | contract SimpleStorage { 4 | uint storedData; 5 | 6 | constructor (uint x) public { 7 | storedData = x; 8 | } 9 | 10 | function set(uint x) public { 11 | require(x < 100, "Not enough Ether provided."); 12 | storedData = x; 13 | } 14 | 15 | function get() public view returns (uint) { 16 | return storedData; 17 | } 18 | } -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | function resolve (dir) { 3 | return path.join(__dirname, dir) 4 | } 5 | 6 | module.exports = { 7 | publicPath: './', 8 | lintOnSave: false, 9 | chainWebpack: (config)=>{ 10 | config.resolve.alias 11 | .set('svg-icon', resolve('src/components/common/svg')) 12 | .set('common', resolve('src/components/common')) 13 | .set('static', resolve('public')) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { mapMutations } from 'vuex' 3 | import App from './App' 4 | import router from './router' 5 | import store from './store' 6 | import i18n from './language' 7 | import './style.styl' 8 | 9 | Vue.config.productionTip = false 10 | 11 | new Vue({ 12 | router, 13 | store, 14 | i18n, 15 | methods: { 16 | ...mapMutations([ 17 | 'initI18n' 18 | ]) 19 | }, 20 | created () { 21 | this.initI18n(i18n) 22 | this.$store.dispatch('initDB') 23 | }, 24 | render: h => h(App) 25 | }).$mount('#app') 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Stellar - TrueChain Contract Management Tool 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/components/common/gui/InputString.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | // import Home from '@/components/Home' 2 | import Deploy from '@/components/Deploy' 3 | import Interact from '@/components/Interact' 4 | import Transfer from '@/components/Transfer' 5 | // import Chain from '@/components/Chain' 6 | import Log from '@/components/Log' 7 | 8 | export default [ 9 | // { 10 | // path: '/', 11 | // name: 'Home', 12 | // component: Home 13 | // }, 14 | { 15 | path: '/transfer', 16 | name: 'Transfer', 17 | component: Transfer 18 | }, 19 | { 20 | path: '/interact', 21 | name: 'Interact', 22 | component: Interact 23 | }, 24 | { 25 | path: '/deploy', 26 | name: 'Deploy', 27 | component: Deploy 28 | }, 29 | // { 30 | // path: '/chain', 31 | // name: 'Chain', 32 | // component: Chain 33 | // }, 34 | { 35 | path: '/log', 36 | name: 'Log', 37 | component: Log 38 | } 39 | ] 40 | -------------------------------------------------------------------------------- /public/network.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "True", 4 | "tag": "main", 5 | "provider": "https://rpc.truechain.network/", 6 | "type": "etrue" 7 | }, 8 | { 9 | "name": "True test", 10 | "tag": "test", 11 | "provider": "https://rpc.truescan.network/testnet/", 12 | "type": "etrue" 13 | }, 14 | { 15 | "name": "Local Net", 16 | "tag": "localnet", 17 | "provider": "http://127.0.0.1:8545", 18 | "type": "etrue" 19 | }, 20 | { 21 | "name": "ETH", 22 | "tag": "mainnet", 23 | "provider": "https://ethrpc.truescan.network/", 24 | "type": "eth" 25 | }, 26 | { 27 | "name": "Local ETH", 28 | "tag": "ethlocalnet", 29 | "provider": "http://127.0.0.1:8545", 30 | "type": "eth" 31 | }, 32 | { 33 | "name": "Ropsten ETH", 34 | "tag": "ropsten", 35 | "provider": "https://ropsten.infura.io/", 36 | "type": "eth" 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /src/store/modules/eth.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | gasPrice: '20000000000', 3 | blockNumber: 0, 4 | MAX_GAS_PRICE_GWEI: 100, 5 | MIN_GAS_PRICE_GWEI: 1 6 | } 7 | 8 | // getters 9 | // const getters = { 10 | // asd: state => state.addresses 11 | // } 12 | 13 | // actions 14 | const actions = { 15 | updateEthereumInfo ({ commit, rootState }) { 16 | const web3 = rootState.web3 17 | return Promise.all([ 18 | web3.eth.getGasPrice().then(res => { commit('setGasPrice', res) }), 19 | web3.eth.getBlockNumber().then(res => { commit('setBlockNumber', res) }) 20 | ]) 21 | } 22 | } 23 | 24 | // mutations 25 | const mutations = { 26 | setGasPrice (state, price) { 27 | state.gasPrice = price 28 | }, 29 | setBlockNumber (state, number) { 30 | state.blockNumber = number 31 | } 32 | } 33 | 34 | export default { 35 | state, 36 | // getters, 37 | actions, 38 | mutations 39 | } 40 | -------------------------------------------------------------------------------- /src/components/common/gui/InterfaceInput.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | import InputAddress from 'common/gui/InputAddress' 4 | import InputUint from 'common/gui/InputUint' 5 | import InputString from 'common/gui/InputString' 6 | import InputBool from 'common/gui/InputBool' 7 | import InputByte from 'common/gui/InputByte' 8 | import InputAny from 'common/gui/InputAny' 9 | 10 | export default Vue.component('interface-input', { 11 | functional: true, 12 | render (createElement, context) { 13 | function getComponent (type) { 14 | switch (true) { 15 | case /address/.test(type): 16 | return InputAddress 17 | case /int/.test(type): 18 | return InputUint 19 | case /string/.test(type): 20 | return InputString 21 | case /bool/.test(type): 22 | return InputBool 23 | case /byte/.test(type): 24 | return InputByte 25 | default: 26 | return InputAny 27 | } 28 | } 29 | const component = getComponent(context.props.type) 30 | return createElement(component, context.data) 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /src/components/common/gui/InputAny.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 42 | -------------------------------------------------------------------------------- /src/components/common/gui/Loading.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 43 | 44 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stellar 2 | 3 | > TrueChain Dashboard 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | ## Compile Server 22 | 23 | ``` bash 24 | # Start a simple solidity compilation service on port 3000 25 | node server/index.js 26 | ``` 27 | 28 | ``` 29 | ├── server => 合约编译服务 30 | ├── src 31 | │   ├── App.vue => 入口组件 32 | │   ├── api-config 33 | │   │   └── index.js => 合约编译服务配置 34 | │   ├── components 35 | │   │   ├── Deploy.vue => 合约部署页面 36 | │   │   ├── Hello.vue => 欢迎页面 37 | │   │   ├── Interact.vue => 合约调用页面 38 | │   │   ├── Log.vue => 交易日志页面 39 | │   │   ├── Transfer.vue => 转账页面 40 | │   │   └── common => 通用组件 41 | │   ├── language => 全球化配置 42 | │   ├── main.js => 入口文件 43 | │   ├── router => 路由配置 44 | │   ├── store => vuex 45 | │   └── style.styl => 样式初始化 46 | └── static 47 | ├── contracts.json => 默认合约配置 48 | └── network.json => 默认网络配置 49 | ``` 50 | -------------------------------------------------------------------------------- /src/components/common/svg/copy.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | -------------------------------------------------------------------------------- /src/components/common/gui/InputBool.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 50 | -------------------------------------------------------------------------------- /src/components/common/gui/InputAddress.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 56 | -------------------------------------------------------------------------------- /src/components/Log.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 60 | 61 | 67 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "steller", 3 | "version": "1.0.0", 4 | "description": "TrueChain Dashboard", 5 | "author": "Tari", 6 | "private": true, 7 | "scripts": { 8 | "serve": "vue-cli-service serve", 9 | "build": "vue-cli-service build", 10 | "lint": "vue-cli-service lint" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.18.0", 14 | "bn.js": "^4.11.8", 15 | "body-parser": "^1.18.3", 16 | "cookie-storage": "^3.1.0", 17 | "core-js": "^2.6.5", 18 | "cors": "^2.8.5", 19 | "ethereumjs-tx": "^1.3.4", 20 | "express": "^4.16.4", 21 | "iclipboard": "^1.0.1", 22 | "owasp-password-strength-test": "^1.3.0", 23 | "solc": "^0.5.7", 24 | "vue": "^2.6.10", 25 | "vue-i18n": "^8.10.0", 26 | "vue-router": "^3.0.3", 27 | "vuex": "^3.0.1", 28 | "web3true": "^1.1.3" 29 | }, 30 | "devDependencies": { 31 | "@vue/cli-plugin-babel": "^3.6.0", 32 | "@vue/cli-plugin-eslint": "^3.6.0", 33 | "@vue/cli-service": "^3.6.0", 34 | "babel-eslint": "^10.0.1", 35 | "eslint": "^5.16.0", 36 | "eslint-plugin-vue": "^5.0.0", 37 | "stylus": "^0.54.5", 38 | "stylus-loader": "^3.0.2", 39 | "vue-template-compiler": "^2.5.21" 40 | }, 41 | "eslintConfig": { 42 | "root": true, 43 | "env": { 44 | "node": true 45 | }, 46 | "extends": [ 47 | "plugin:vue/essential", 48 | "eslint:recommended" 49 | ], 50 | "rules": { 51 | "no-console": 0 52 | }, 53 | "parserOptions": { 54 | "parser": "babel-eslint" 55 | } 56 | }, 57 | "postcss": { 58 | "plugins": { 59 | "autoprefixer": {} 60 | } 61 | }, 62 | "engines": { 63 | "node": ">= 6.0.0", 64 | "npm": ">= 3.0.0" 65 | }, 66 | "browserslist": [ 67 | "> 1%", 68 | "last 2 versions", 69 | "not ie <= 8" 70 | ] 71 | } 72 | -------------------------------------------------------------------------------- /src/components/common/function/Help.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | 34 | 81 | -------------------------------------------------------------------------------- /src/components/common/function/Notice.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 33 | 34 | 81 | -------------------------------------------------------------------------------- /src/components/common/gui/InputByte.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 72 | -------------------------------------------------------------------------------- /public/contracts.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "ERC20", 4 | "address": "", 5 | "abi": [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}] 6 | } 7 | ] -------------------------------------------------------------------------------- /src/components/common/logs/TxLog.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 53 | 54 | 84 | -------------------------------------------------------------------------------- /src/components/common/logs/CreationLog.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 52 | 53 | 83 | -------------------------------------------------------------------------------- /src/store/modules/accounts.js: -------------------------------------------------------------------------------- 1 | const state = { 2 | accounts: new Map(), 3 | addresses: [], 4 | accountsDialogIsOpen: false, 5 | latestAccounts: '' 6 | } 7 | 8 | // getters 9 | const getters = { 10 | allAccounts: state => state.addresses, 11 | accountsCount: state => state.addresses.length, 12 | signedTransaction: state => (address, rawTx) => { 13 | const account = state.accounts[address.toLocaleLowerCase()] 14 | if (!account) { 15 | throw new Error(`Address: ${address} is not authorized`) 16 | } else { 17 | return account.signTransaction(rawTx) 18 | } 19 | } 20 | } 21 | 22 | // actions 23 | const actions = { 24 | pushAccountToWallet ({ state, rootState }, address) { 25 | const web3 = rootState.web3 26 | const account = state.accounts.get(address.toLowerCase()) 27 | if (account) { 28 | web3.eth.accounts.wallet.add(account) 29 | setTimeout(() => { 30 | web3.eth.accounts.wallet.clear() 31 | }, 10000) 32 | } else { 33 | return false 34 | } 35 | return true 36 | }, 37 | async signTx ({ state, rootState }, txConfig) { 38 | const web3 = rootState.web3 39 | const from = txConfig.from.toLowerCase() 40 | const account = state.accounts.get(from.toLowerCase()) 41 | if (!rootState.useGreenBelt && !account) { 42 | return false 43 | } 44 | if (!rootState.chainId) { 45 | rootState.chainId = await web3.eth.net.getId() 46 | } 47 | const tx = Object.assign({ 48 | chainId: rootState.chainId 49 | }, txConfig) 50 | const { rawTransaction } = rootState.useGreenBelt ? 51 | await web3.eth.accounts.signTransaction(tx, web3.currentProvider) : 52 | await account.signTransaction(tx) 53 | return rawTransaction 54 | } 55 | } 56 | 57 | // mutations 58 | const mutations = { 59 | saveAccounts (state, accounts) { 60 | const tempAccounts = {} 61 | for (let i = 0; i < accounts.length; i++) { 62 | const account = accounts[i] 63 | const address = account.address.toLocaleLowerCase() 64 | tempAccounts[address] = account 65 | if (state.addresses.indexOf(address) === -1) { 66 | state.addresses.push(address) 67 | } 68 | state.accounts.set(address, account) 69 | } 70 | state.latestAccounts = state.addresses[state.addresses.length - 1] 71 | }, 72 | toAddAccounts (state) { 73 | state.accountsDialogIsOpen = true 74 | }, 75 | endAddAccounts (state) { 76 | state.accountsDialogIsOpen = false 77 | } 78 | } 79 | 80 | export default { 81 | state, 82 | getters, 83 | actions, 84 | mutations 85 | } 86 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const bodyParser = require('body-parser') 3 | const solc = require('solc') 4 | 5 | const lowVersion = require('../public/soljson-v0.4.25+commit.59dbf8f1.js') 6 | 7 | const app = express() 8 | app.use(bodyParser.json({ limit: '1mb' })) 9 | app.use(bodyParser.urlencoded({ extended: true })) 10 | 11 | app.all('*', (_, res, next) => { 12 | res.header('Access-Control-Allow-Origin', '*') 13 | res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept') 14 | res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS') 15 | res.header('X-Powered-By', ' 3.2.1') 16 | next() 17 | }) 18 | 19 | app.get('/', (_, res) => { 20 | res.send('hello world') 21 | }) 22 | 23 | app.post('/compile', (req, res) => { 24 | console.log('\n-----------compile require-----------') 25 | const data = req.body 26 | for (const key in data) { 27 | console.log(`${key}: ${data[key]}`) 28 | } 29 | console.log() 30 | if (data.source === undefined) { 31 | console.warn('No source code input') 32 | return res.json({ 33 | error: true, 34 | from: '[POST /compile]', 35 | msg: 'No source code input' 36 | }) 37 | } 38 | const matched = data.source.match(/pragma[\s]+solidity[\s]+\^?0\.([\d]+)\.[\d]+/) 39 | if (!matched || !matched[1]) { 40 | console.warn('Unknow solidity version') 41 | return res.json({ 42 | error: true, 43 | from: '[POST /compile]', 44 | msg: 'Unknow solidity version' 45 | }) 46 | } 47 | const input = { 48 | 'language': 'Solidity', 49 | 'settings': { 50 | 'outputSelection': { 51 | '*': { 52 | '*': [ 'evm.bytecode.object', 'abi' ] 53 | } 54 | } 55 | }, 56 | 'sources': { 57 | 'main.sol': { 58 | 'content': data.source 59 | } 60 | } 61 | } 62 | let output = null 63 | if (matched[1] < 5) { 64 | const useSolc = solc.setupMethods(lowVersion) 65 | output = JSON.parse(useSolc.lowlevel.compileStandard(JSON.stringify(input))) 66 | } else { 67 | output = JSON.parse(solc.compileStandardWrapper(JSON.stringify(input))) 68 | } 69 | if (output.errors) { 70 | console.warn('Compile error\n') 71 | for (let i = 0; i < output.errors.length; i++) { 72 | const err = output.errors[i] 73 | console.warn(err) 74 | } 75 | return res.json({ 76 | error: true, 77 | from: '[POST /compile]', 78 | msg: 'Compile error', 79 | details: output.errors 80 | }) 81 | } 82 | const main = output.contracts['main.sol'] 83 | for (var contractName in main) { 84 | console.log(`Contract ${contractName}: ${main[contractName].evm.bytecode.object}`) 85 | } 86 | return res.json(output) 87 | }) 88 | 89 | console.log('server listen on port 3000') 90 | app.listen(3000) 91 | -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import Web3 from 'web3true' 4 | 5 | import accounts from './modules/accounts' 6 | import eth from './modules/eth' 7 | import log from './modules/log' 8 | import indexdb from './modules/indexdb' 9 | import networkSet from 'static/network.json' 10 | 11 | Vue.use(Vuex) 12 | 13 | // const debug = process.env.NODE_ENV !== 'production' 14 | const debug = false 15 | const web3 = new Web3(networkSet[0].provider, networkSet[0].type) 16 | window.web3 = web3 17 | 18 | const state = { 19 | i18n: null, 20 | languageTag: 'sc', 21 | web3, 22 | chainId: '19330', 23 | provider: networkSet[0], 24 | 25 | useGreenBelt: false, 26 | greenbeltAddr: '', 27 | 28 | noticeBoxTimer: 0, 29 | noticeBox: null, 30 | noticeTextBox: null, 31 | hold: false 32 | } 33 | 34 | const mutations = { 35 | setWeb3Provider (state, config) { 36 | state.web3.setProvider(config.provider, config.type) 37 | state.chainId = '' 38 | state.provider = config 39 | }, 40 | initI18n (state, i18n) { 41 | state.i18n = i18n 42 | }, 43 | setLanguage (state, tag) { 44 | state.i18n.locale = tag 45 | state.languageTag = tag 46 | }, 47 | bindNoticeBox (state, el) { 48 | state.noticeBox = el 49 | state.noticeTextBox = el.querySelector('p') 50 | }, 51 | holdNoticeBox (state, hold) { 52 | state.hold = hold 53 | if (!state.noticeBoxTimer && !hold) { 54 | state.noticeBox.style.transform = 'translateY(110%)' 55 | } 56 | }, 57 | closeNoticeBox (state) { 58 | state.noticeBox.style.transform = 'translateY(110%)' 59 | state.noticeBoxTimer = 0 60 | } 61 | } 62 | 63 | const actions = { 64 | async useGreenBelt ({ state }, provider) { 65 | const error = await provider.enable().then(addrs => { 66 | state.greenbeltAddr = addrs[0] 67 | return false 68 | }).catch(() => true) 69 | if (error) { 70 | return 71 | } 72 | provider.on('accountsChanged' ,addrs => { 73 | state.greenbeltAddr = addrs[0] 74 | }) 75 | state.web3.setProvider(provider) 76 | state.chainId = provider.networkVersion 77 | state.useGreenBelt = true 78 | }, 79 | notice ({ state }, [color, text, time]) { 80 | const el = state.noticeBox 81 | const tel = state.noticeTextBox 82 | if (!el) { 83 | return 84 | } 85 | let delay = 0 86 | if (state.noticeBoxTimer) { 87 | clearTimeout(state.noticeBoxTimer) 88 | delay = 300 89 | } 90 | switch (color) { 91 | case 'info': 92 | color = '#0fa9a2' 93 | break 94 | case 'log': 95 | color = '#2fa4d9' 96 | break 97 | case 'warn': 98 | color = '#ed951f' 99 | break 100 | case 'error': 101 | color = '#d80315' 102 | break 103 | } 104 | el.style.transform = 'translateY(110%)' 105 | el.style.backgroundColor = color 106 | tel.innerText = text 107 | setTimeout(() => { 108 | el.style.transform = 'translateY(0%)' 109 | }, delay) 110 | state.noticeBoxTimer = setTimeout(() => { 111 | if (!state.hold) { 112 | el.style.transform = 'translateY(110%)' 113 | } 114 | state.noticeBoxTimer = 0 115 | }, delay + time) 116 | } 117 | } 118 | 119 | export default new Vuex.Store({ 120 | state, 121 | mutations, 122 | actions, 123 | modules: { 124 | accounts, 125 | eth, 126 | log, 127 | indexdb 128 | }, 129 | strict: debug 130 | }) 131 | -------------------------------------------------------------------------------- /src/components/common/gui/InputUint.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 106 | 107 | 126 | -------------------------------------------------------------------------------- /src/store/modules/log.js: -------------------------------------------------------------------------------- 1 | class BaseTxObj { 2 | constructor (time, txData) { 3 | this.id = txData.hash 4 | this.from = txData.from 5 | this.sendTime = time 6 | this.height = -1 7 | 8 | this.finished = false 9 | this.receiptTime = 0 10 | this.error = null 11 | } 12 | onFail (time, error) { 13 | this.finished = true 14 | this.receiptTime = time 15 | this.error = error 16 | } 17 | onSuccess (time, txRecept) { 18 | this.finished = true 19 | this.receiptTime = time 20 | this.height = txRecept.blockNumber 21 | } 22 | } 23 | 24 | class TransferTxObj extends BaseTxObj { 25 | constructor (time, txData) { 26 | super(time, txData) 27 | this.to = txData.to 28 | this.value = txData.value 29 | } 30 | } 31 | 32 | class ContractTxObj extends BaseTxObj { 33 | constructor (time, txData) { 34 | super(time, txData) 35 | this.input = txData.input 36 | this.contract = '' 37 | } 38 | onSuccess (time, txRecept) { 39 | this.finished = true 40 | this.receiptTime = time 41 | this.contract = txRecept.contractAddress 42 | this.height = txRecept.blockNumber 43 | } 44 | } 45 | 46 | const state = { 47 | logs: [], 48 | monitoring: 0, 49 | pendingTxs: new Map() 50 | } 51 | 52 | const mutations = { 53 | afterTxSend (state, txData) { 54 | const time = new Date() 55 | if (txData.to) { 56 | const transferTxObj = new TransferTxObj(time, txData) 57 | state.logs.unshift(transferTxObj) 58 | } else { 59 | const contractTxObj = new ContractTxObj(time, txData) 60 | state.logs.unshift(contractTxObj) 61 | } 62 | }, 63 | afterTxReceipt (state, txRecept) { 64 | const time = new Date() 65 | const tx = state.logs.find(item => item.id === txRecept.transactionHash) 66 | if (!tx) { 67 | return 68 | } 69 | if (txRecept.status) { 70 | tx.onSuccess(time, txRecept) 71 | } else { 72 | tx.onFail(time, 'Unknow Error') 73 | } 74 | }, 75 | afterTxError (state, { txHash, errMsg }) { 76 | const time = new Date() 77 | const tx = state.logs.find(item => item.id === txHash) 78 | if (!tx) { 79 | return 80 | } 81 | tx.onFail(time, errMsg) 82 | } 83 | } 84 | 85 | const actions = { 86 | addPendingTx ({ state, dispatch }, [txHash, cb]) { 87 | state.pendingTxs.set(txHash, cb) 88 | if (!state.monitoring) { 89 | dispatch('startMonitoring') 90 | } 91 | }, 92 | startMonitoring ({ state, dispatch }) { 93 | if (state.monitoring) { 94 | return false 95 | } 96 | state.monitoring = setInterval(() => { 97 | dispatch('processPendingTxs') 98 | }, 2000) 99 | return true 100 | }, 101 | stopMonitoring ({ state }) { 102 | if (!state.monitoring) { 103 | return false 104 | } 105 | clearInterval(state.monitoring) 106 | state.monitoring = 0 107 | return true 108 | }, 109 | processPendingTxs ({ state, rootState, commit }) { 110 | const web3 = rootState.web3 111 | state.pendingTxs.forEach((cb, txHash) => { 112 | web3.eth.getTransactionReceipt(txHash).then(receipt => { 113 | if (!receipt) { 114 | return 115 | } 116 | state.pendingTxs.delete(txHash) 117 | if (receipt.status) { 118 | commit('afterTxReceipt', receipt) 119 | } else { 120 | commit('afterTxError', { 121 | txHash: receipt.transactionHash, 122 | errMsg: 'Transactions fail when executed in EVM' 123 | }) 124 | } 125 | if (typeof cb === 'function') { 126 | cb(receipt) 127 | } 128 | }) 129 | }) 130 | } 131 | } 132 | 133 | export default { 134 | namespaced: true, 135 | state, 136 | // getters, 137 | actions, 138 | mutations 139 | } 140 | -------------------------------------------------------------------------------- /src/language/lib/sc.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Stellar", 3 | "Hello": { 4 | "title": "你好!", 5 | "welcome": "欢迎使用Stellar" 6 | }, 7 | "App": { 8 | "back": "退出", 9 | "close": "关闭", 10 | "custom": "自定义Provider", 11 | "account": "没有激活账户 | 已激活{count}个账户 | 已激活{count}个账户", 12 | "providerNotice": "仅支持HttpProvider,格式为IP+Port。例如", 13 | "router": { 14 | "Transfer": "转账", 15 | "Interact": "合约调用", 16 | "Deploy": "合约部署", 17 | "Chain": "主网状态", 18 | "Log": "日志" 19 | }, 20 | "network": { 21 | "beta": "True β主网", 22 | "main": "True 主网", 23 | "test": "True 测试网", 24 | "mainnet": "ETH主网", 25 | "ropsten": "Ropsten", 26 | "privatenet": "私有网络", 27 | "localnet": "本地True网络", 28 | "ethlocalnet": "本地ETH网络", 29 | "unknow": "测试网络" 30 | } 31 | }, 32 | "Transfer": { 33 | "title": "转账" 34 | }, 35 | "Interact": { 36 | "title": "合约调用", 37 | "contract": "选择标准合约", 38 | "api": "接口JSON", 39 | "address": "合约地址", 40 | "interface": "接口", 41 | "custom": "自定义", 42 | "saveContract": "储存合约信息", 43 | "name": "名称", 44 | "save": "储存", 45 | "delete": "删除", 46 | "notice": { 47 | "save": "请确保合约地址或接口输入正确,并且输入合约名称", 48 | "saveSuccess": "合约储存成功", 49 | "saveFail": "合约储存失败", 50 | "delete": "请输入将要删除的合约名称", 51 | "deleteSuccess": "合约删除成功", 52 | "deleteFail": "合约删除失败" 53 | } 54 | }, 55 | "Deploy": { 56 | "title": "部署合约", 57 | "deployBy": "部署方式: ", 58 | "solSource": "Sol 源代码", 59 | "codeAndApi": "二进制代码 / 接口", 60 | "solSourceCode": "Solidity源代码", 61 | "compiled": "二进制代码", 62 | "interface": "接口JSON", 63 | "compile": "编译", 64 | "constructor": "构造函数" 65 | }, 66 | "CreateAccount": { 67 | "title": "创建新账户", 68 | "submit": "生成", 69 | "noKeystore": "未生成KeyStore", 70 | "canDownload": "下载你的KeyStore", 71 | "passwordHelp": "请牢记你的密码!", 72 | "keystoreNotice": "**务必妥善保管** 一旦丢失没有任何办法帮助你找回!" 73 | }, 74 | "SigninAccount": { 75 | "title": "添加账户", 76 | "privateKey": "从私钥导入", 77 | "select": "或者 选择KeyStore文件" 78 | }, 79 | "Selector": { 80 | "noOptions": "无可用选项" 81 | }, 82 | "SetTxConfig": { 83 | "newAccount": "+ 添加新账户", 84 | "noSugs": "无建议值", 85 | "expected": "预计" 86 | }, 87 | "Notice": { 88 | "gasTooLow": "燃气费设置过低", 89 | "gasTooHigh": "燃气费设置过高" 90 | }, 91 | "Common": { 92 | "transaction": "交易", 93 | "password": "密码", 94 | "repeat": "重复密码", 95 | "decrypt": "解码", 96 | "next": "下一步", 97 | "send": "发送交易", 98 | "skip": "跳过", 99 | "deploy": "部署合约", 100 | "txInfo": { 101 | "base": "交易信息" 102 | }, 103 | "waiting": "等待中", 104 | "resize": "还原窗口大小", 105 | "notice": { 106 | "error": "错误 ", 107 | "warn": "注意 ", 108 | "response": "查询结果:", 109 | "ksTooLarge": "所选文件过大", 110 | "ksParseErr": "KeyStore文件格式错误", 111 | "ksPkErr": "私钥使用失败:", 112 | "ksPwErr": "KeyStore解析失败:", 113 | "afterSend": "交易已发出 ID:", 114 | "txError": "交易失败 ", 115 | "txEVMError": "交易执行时失败", 116 | "txSuccess": "交易成功 交易ID:", 117 | "compileError": "编译失败 ", 118 | "compileSuccess": "编译成功" 119 | }, 120 | "logs": { 121 | "txError": "交易失败", 122 | "txSuccess": "交易成功", 123 | "blockHeight": "区块高度", 124 | "contractCreation": "合约创建", 125 | "contractAddress": "合约地址" 126 | } 127 | }, 128 | "Copy": { 129 | "success": "已复制:", 130 | "fail": "复制失败" 131 | }, 132 | "GreenBelt": { 133 | "title": "使用GreenBelt", 134 | "start": "使用GreenBelt管理账户", 135 | "download": "从Chrome商店下载插件", 136 | "versionNotice": "请使用7.1.4版本以上的GreenBelt", 137 | "linked": "连接至GreenBelt", 138 | "account": "使用GreenBelt账户", 139 | "notfound": "未能连接至GreenBelt,请确保安装并已经启动" 140 | } 141 | } -------------------------------------------------------------------------------- /src/components/common/svg/compile.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 30 | -------------------------------------------------------------------------------- /src/store/modules/indexdb.js: -------------------------------------------------------------------------------- 1 | import staticContracts from 'static/contracts.json' 2 | 3 | const DB_NAME = 'stellar' 4 | const DB_VERSION = 1 5 | 6 | // state 7 | const state = { 8 | dbversion: DB_VERSION, 9 | db: null, 10 | contracts: [], 11 | state: false 12 | } 13 | 14 | // actions 15 | const actions = { 16 | async initDB ({ state, dispatch }) { 17 | let upgradeneeded = false 18 | state.db = await new Promise(resolve => { 19 | const openRequest = indexedDB.open(DB_NAME, DB_VERSION) 20 | openRequest.onupgradeneeded = event => { 21 | const db = event.target.result 22 | db.createObjectStore('contract', { keyPath: 'name' }) 23 | upgradeneeded = true 24 | } 25 | openRequest.onsuccess = () => { 26 | console.log('Use IndexDB:', openRequest.result.name, 'version:', openRequest.result.version) 27 | state.state = true 28 | resolve(openRequest.result) 29 | } 30 | openRequest.onerror = () => { 31 | console.warn('IndexDB could not be initialized') 32 | resolve(null) 33 | } 34 | }) 35 | if (upgradeneeded) { 36 | await staticContracts.map(contract => { 37 | return dispatch('saveContract', contract) 38 | }) 39 | } 40 | await dispatch('updateAllContracts') 41 | }, 42 | async saveContract ({ state, dispatch }, { name, address, abi }) { 43 | const db = state.db 44 | if (!db || !(db instanceof IDBDatabase)) { 45 | return false 46 | } 47 | const res = new Promise(resolve => { 48 | const saveRequest = db.transaction(['contract'], 'readwrite') 49 | .objectStore('contract') 50 | .add({ name, address, abi }) 51 | saveRequest.onsuccess = () => { 52 | resolve(true) 53 | } 54 | saveRequest.onerror = () => { 55 | resolve(false) 56 | } 57 | }) 58 | if (res) { 59 | await dispatch('updateAllContracts') 60 | } 61 | return res 62 | }, 63 | async updateContract ({ state, dispatch }, { name, address, abi }) { 64 | const db = state.db 65 | if (!db || !(db instanceof IDBDatabase)) { 66 | return false 67 | } 68 | const res = new Promise(resolve => { 69 | const delRequest = db.transaction(['contract'], 'readwrite') 70 | .objectStore('contract') 71 | .put({ name, address, abi }) 72 | delRequest.onsuccess = () => { 73 | resolve(true) 74 | } 75 | delRequest.onerror = () => { 76 | resolve(false) 77 | } 78 | }) 79 | if (res) { 80 | await dispatch('updateAllContracts') 81 | } 82 | return res 83 | }, 84 | async removeContract ({ state, dispatch }, name) { 85 | const db = state.db 86 | if (!db || !(db instanceof IDBDatabase)) { 87 | return false 88 | } 89 | const res = new Promise(resolve => { 90 | const delRequest = db.transaction(['contract'], 'readwrite') 91 | .objectStore('contract') 92 | .delete(name) 93 | delRequest.onsuccess = () => { 94 | resolve(true) 95 | } 96 | delRequest.onerror = () => { 97 | resolve(false) 98 | } 99 | }) 100 | if (res) { 101 | await dispatch('updateAllContracts') 102 | } 103 | return res 104 | }, 105 | async updateAllContracts ({ state }) { 106 | const db = state.db 107 | if (!db || !(db instanceof IDBDatabase)) { 108 | return false 109 | } 110 | return new Promise(resolve => { 111 | const getRequest = db.transaction(['contract']) 112 | .objectStore('contract') 113 | .getAll() 114 | getRequest.onsuccess = event => { 115 | state.contracts = event.target.result 116 | resolve(event.target.result) 117 | } 118 | getRequest.onerror = () => { 119 | resolve(false) 120 | } 121 | }) 122 | } 123 | } 124 | 125 | export default { 126 | state, 127 | actions 128 | } 129 | -------------------------------------------------------------------------------- /src/style.styl: -------------------------------------------------------------------------------- 1 | body 2 | margin 0 3 | overflow hidden 4 | font-size 16px 5 | p, ul 6 | margin 0 7 | padding 0 8 | li 9 | list-style none 10 | input 11 | font-family 'Avenir', Helvetica, Arial, sans-serif 12 | -webkit-font-smoothing antialiased 13 | -moz-osx-font-smoothing grayscale 14 | font-size inherit 15 | box-sizing border-box 16 | height 40px 17 | border-radius 3px 18 | border solid 1px #ddd 19 | padding 0 9px 20 | font-size 16px 21 | outline none 22 | textarea 23 | font-family 'Avenir', Helvetica, Arial, sans-serif 24 | -webkit-font-smoothing antialiased 25 | -moz-osx-font-smoothing grayscale 26 | font-size inherit 27 | box-sizing border-box 28 | border-radius 3px 29 | border solid 1px #ddd 30 | padding 4px 9px 31 | font-size 16px 32 | outline none 33 | resize none 34 | .tc-card 35 | border-radius 5px 36 | background-color #fff 37 | padding 20px 38 | box-shadow 0 2px 4px #0001 39 | min-width 320px 40 | .tc-title 41 | font-weight bold 42 | font-size 1.6em 43 | line-height 40px 44 | margin 0 45 | .tc-form-line 46 | position relative 47 | margin 20px 0 48 | line-height 40px 49 | width 320px 50 | height 40px 51 | input 52 | float right 53 | transition border-left .4s 54 | .no-data 55 | font-size 14px 56 | color #bbb 57 | text-align center 58 | background-color #f9f9f9 59 | line-height 40px 60 | .clear 61 | clear both 62 | .code 63 | font-family "Consolas","Andale Mono WT","Andale Mono","Lucida Console","Lucida Sans Typewriter","DejaVu Sans Mono","Bitstream Vera Sans Mono","Liberation Mono","Nimbus Mono L",Monaco,"Courier New",Courier,monospace 64 | hr 65 | margin 30px 0 66 | border none 67 | height 2px 68 | background: #eee 69 | .mask 70 | top 0 71 | left 0 72 | position fixed 73 | width 100% 74 | height 100% 75 | z-index 50 76 | background-color #0004 77 | .input-active 78 | border-color #0d85da 79 | // box-shadow 0 0 6px #0d85da66 80 | .input-error 81 | border-color #e00b27 82 | .button-blue 83 | background-color #0072c1 84 | cursor default 85 | line-height 40px 86 | border-radius 3px 87 | color #fff 88 | text-align center 89 | div 90 | border-radius 3px 91 | transition background-color .4s, transform .4s 92 | background-color #bbb 93 | .button-active 94 | cursor pointer 95 | div 96 | background-color #0d85da 97 | transform translateY(-10px) 98 | &:hover 99 | transform translateY(-6px) 100 | .input-data-box 101 | background-color #fff 102 | position relative 103 | input 104 | width 100% 105 | font-size inherit 106 | height calc(5em - 40px) 107 | line-height calc(5em - 40px) 108 | transition 0.4s 109 | background-color transparent 110 | position relative 111 | z-index 4 112 | .input-default 113 | position absolute 114 | line-height calc(5em - 40px) 115 | top 0 116 | left 0 117 | padding-left 10px 118 | color #ddd 119 | 120 | .position-r 121 | position relative 122 | 123 | .margin-right-1em 124 | margin-right 1em 125 | 126 | // main-color 127 | .normal 128 | color #2fa4d9 129 | .warning 130 | color #ed951f 131 | .error 132 | color #d80315 133 | .b-default 134 | background-color #999999 135 | .b-info 136 | background-color #0fa9a2 137 | .b-normal 138 | background-color #2fa4d9 139 | .b-warning 140 | background-color #ed951f 141 | .b-error 142 | background-color #d80315 143 | 144 | .new:after 145 | content 'New!' 146 | position absolute 147 | color #0fa9a2 148 | display inline-block 149 | animation charJump 1.4s linear infinite 150 | 151 | 152 | @keyframes charJump 153 | 0% 154 | transform translateY(0) scale(.6) 155 | 60% 156 | transform translateY(0) scale(.6) 157 | 70% 158 | transform translateY(-8%) scale(.6) 159 | 80% 160 | transform translateY(0) scale(.6) 161 | 90% 162 | transform translateY(-8%) scale(.6) 163 | 100% 164 | transform translateY(0) scale(.6) 165 | -------------------------------------------------------------------------------- /public/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | library SafeMath { 4 | // function mul(uint256 a, uint256 b) internal pure returns (uint256) { 5 | // if (a == 0) { 6 | // return 0; 7 | // } 8 | // uint256 c = a * b; 9 | // assert(c / a == b); 10 | // return c; 11 | // } 12 | 13 | // function div(uint256 a, uint256 b) internal pure returns (uint256) { 14 | // uint256 c = a / b; 15 | // return c; 16 | // } 17 | 18 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 19 | assert(b <= a); 20 | return a - b; 21 | } 22 | 23 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 24 | uint256 c = a + b; 25 | assert(c >= a); 26 | return c; 27 | } 28 | } 29 | 30 | contract TestERC20Token { 31 | using SafeMath for uint256; 32 | string public constant name = "Test ERC20 Token"; 33 | string public constant symbol = "TET"; 34 | uint256 public constant decimals = 18; 35 | uint256 _totalSupply = 100000000 * 10 ** decimals; 36 | address payable public founder = address(0); 37 | uint256 public distributed = 0; 38 | 39 | mapping (address => uint256) balances; 40 | mapping (address => mapping (address => uint256)) allowed; 41 | 42 | event Transfer(address indexed _from, address indexed _to, uint256 _value); 43 | event Approval(address indexed _owner, address indexed _spender, uint256 _value); 44 | 45 | constructor() public { 46 | founder = msg.sender; 47 | } 48 | 49 | function totalSupply() public view returns (uint256 supply) { 50 | return _totalSupply; 51 | } 52 | 53 | function balanceOf(address _owner) public view returns (uint256 balance) { 54 | return balances[_owner]; 55 | } 56 | 57 | function transfer(address _to, uint256 _value) public returns (bool success) { 58 | require (_to != address(0), ""); 59 | require((balances[msg.sender] >= _value), ""); 60 | balances[msg.sender] = balances[msg.sender].sub(_value); 61 | balances[_to] = balances[_to].add(_value); 62 | emit Transfer(msg.sender, _to, _value); 63 | return true; 64 | } 65 | 66 | function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) { 67 | require (_to != address(0), ""); 68 | require(balances[_from] >= _value && allowed[_from][msg.sender] >= _value, ""); 69 | balances[_from] = balances[_from].sub(_value); 70 | balances[_to] = balances[_to].add(_value); 71 | emit Transfer(_from, _to, _value); 72 | return true; 73 | } 74 | 75 | function approve(address _spender, uint256 _value) public returns (bool success) { 76 | allowed[msg.sender][_spender] = _value; 77 | emit Approval(msg.sender, _spender, _value); 78 | return true; 79 | } 80 | 81 | function allowance(address _owner, address _spender) public view returns (uint256 remaining) { 82 | return allowed[_owner][_spender]; 83 | } 84 | 85 | function distribute(address _to, uint256 _amount) public returns (bool success) { 86 | require(msg.sender == founder, ""); 87 | require(distributed.add(_amount) <= _totalSupply, ""); 88 | 89 | distributed = distributed.add(_amount); 90 | balances[_to] = balances[_to].add(_amount); 91 | emit Transfer(address(this), _to, _amount); 92 | return true; 93 | } 94 | 95 | function distributeMultiple(address[] memory _tos, uint256[] memory _values) public returns (bool success) { 96 | require(msg.sender == founder, ""); 97 | 98 | uint256 total = 0; 99 | uint256 i = 0; 100 | for (i = 0; i < _tos.length; i++) { 101 | total = total.add(_values[i]); 102 | } 103 | 104 | require(distributed.add(total) < _totalSupply, ""); 105 | 106 | for (i = 0; i < _tos.length; i++) { 107 | distributed = distributed.add(_values[i]); 108 | balances[_tos[i]] = balances[_tos[i]].add(_values[i]); 109 | emit Transfer(address(this), _tos[i], _values[i]); 110 | } 111 | 112 | return true; 113 | } 114 | 115 | function changeFounder(address payable newFounder) public { 116 | require(msg.sender == founder, ""); 117 | 118 | founder = newFounder; 119 | } 120 | 121 | function kill() public { 122 | require(msg.sender == founder, ""); 123 | 124 | selfdestruct(founder); 125 | } 126 | } -------------------------------------------------------------------------------- /src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 110 | 111 | 153 | -------------------------------------------------------------------------------- /src/components/common/function/Selector.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 109 | 110 | 177 | -------------------------------------------------------------------------------- /src/components/common/function/SigninAccount.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 103 | 104 | 158 | -------------------------------------------------------------------------------- /src/language/lib/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Stellar", 3 | "Hello": { 4 | "title": "Hello!", 5 | "welcome": "Welcome to Stellar" 6 | }, 7 | "App": { 8 | "back": "Exit", 9 | "close": "Close", 10 | "custom": "Custom Provider", 11 | "account": "no Accounts in Session | {count} Account in Session | {count} Accounts in Session", 12 | "providerNotice": "Only HttpProvider is supported, and the format is IP+ port. E.g", 13 | "router": { 14 | "Transfer": "Transfer", 15 | "Interact": "Interact", 16 | "Deploy": "Deploy", 17 | "Chain": "Chain", 18 | "Log": "Log" 19 | }, 20 | "network": { 21 | "beta": "True β Main Net", 22 | "main": "True Main Net", 23 | "test": "True Test Net", 24 | "mainnet": "ETH Main Net", 25 | "ropsten": "Ropsten", 26 | "privatenet": "Private Net", 27 | "localnet": "Local True Net", 28 | "ethlocalnet": "Local ETH Net", 29 | "unknow": "Test Net" 30 | } 31 | }, 32 | "Transfer": { 33 | "title": "Transfer" 34 | }, 35 | "Interact": { 36 | "title": "Interact Contract", 37 | "contract": "Standard Contract", 38 | "api": "Iterface JSON", 39 | "address": "Address", 40 | "interface": "Interface", 41 | "custom": "Custom", 42 | "saveContract": "Save Contract Info", 43 | "name": "Name", 44 | "save": "save", 45 | "delete": "delete", 46 | "notice": { 47 | "save": "Please make sure the contract address or interface is entered correctly and enter the contract name", 48 | "saveSuccess": "Contract storage successful", 49 | "saveFail": "Contract storage failed", 50 | "delete": "Please enter the name of the contract that will be deleted", 51 | "deleteSuccess": "Contract deletion successful", 52 | "deleteFail": "Contract deletion failed" 53 | } 54 | }, 55 | "Deploy": { 56 | "title": "Deploy Contract", 57 | "deployBy": "Deploy Contract By: ", 58 | "solSource": "Sol Source", 59 | "codeAndApi": "Code / Interface", 60 | "solSourceCode": "Solidity Source Code", 61 | "compiled": "Compiled Code", 62 | "interface": "Interface JSON", 63 | "compile": "Compile", 64 | "constructor": "Constructor" 65 | }, 66 | "CreateAccount": { 67 | "title": "Create new Account", 68 | "submit": "Submit", 69 | "noKeystore": "No KeyStore", 70 | "canDownload": "Download your KeyStore", 71 | "passwordHelp": "Do NOT forget to save this", 72 | "keystoreNotice": "**Do not lose it!** It cannot be recovered if you lose it." 73 | }, 74 | "SigninAccount": { 75 | "title": "Add Account", 76 | "privateKey": "Private Key", 77 | "select": "or Select KeyStore flie" 78 | }, 79 | "Selector": { 80 | "noOptions": "No options" 81 | }, 82 | "SetTxConfig": { 83 | "newAccount": "+ add new Account", 84 | "noSugs": "No suggestions", 85 | "expected": "Expected" 86 | }, 87 | "Notice": { 88 | "gasTooLow": "Gas price set too low", 89 | "gasTooHigh": "Gas price set too high" 90 | }, 91 | "Common": { 92 | "transaction": "Transaction", 93 | "password": "Password", 94 | "repeat": "Repeat", 95 | "decrypt": "Decrypt", 96 | "next": "Next", 97 | "send": "Send", 98 | "skip": "Skip", 99 | "deploy": "Deploy", 100 | "txInfo": { 101 | "base": "Tx Info" 102 | }, 103 | "waiting": "waiting", 104 | "resize": "resize", 105 | "notice": { 106 | "error": "Error ", 107 | "warn": "Warn ", 108 | "response": "Response: ", 109 | "ksTooLarge": "The selected file is too large", 110 | "ksParseErr": "KeyStore file format wrong", 111 | "ksPkErr": "Private key usage failed: ", 112 | "ksPwErr": "KeyStore decrypt failed: ", 113 | "afterSend": "Transaction has been send, ID:", 114 | "txError": "Transaction failed, ", 115 | "txEVMError": "Transaction execution failed", 116 | "txSuccess": "Transaction succeed, ID: ", 117 | "compileError": "Compile failed ", 118 | "compileSuccess": "Compile succeed" 119 | }, 120 | "logs": { 121 | "txError": "Transaction failed", 122 | "txSuccess": "Transaction succeed", 123 | "blockHeight": "Block Height", 124 | "contractCreation": "Contract Creation", 125 | "contractAddress": "Contract Address" 126 | } 127 | }, 128 | "Copy": { 129 | "success": "Copied: ", 130 | "fail": "Copy failed" 131 | }, 132 | "GreenBelt": { 133 | "title": "Use GreenBelt", 134 | "start": "Use GreenBelt to manage accounts", 135 | "download": "Download plugins from Chrome Store", 136 | "versionNotice": "Please use GreenBelt above v7.1.4", 137 | "linked": "Connect by GreenBelt", 138 | "account": "Use the GreenBelt account", 139 | "notfound": "Failed to connect to GreenBelt, please ensure installation and start-up" 140 | } 141 | } -------------------------------------------------------------------------------- /src/components/common/function/SetTxConfig.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 132 | 133 | 199 | -------------------------------------------------------------------------------- /src/components/Chain.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 109 | 110 | 199 | -------------------------------------------------------------------------------- /src/components/common/function/CreateAccount.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 119 | 120 | 187 | -------------------------------------------------------------------------------- /src/components/Transfer.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 198 | 199 | 256 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 80 | 81 | 259 | 260 | 485 | -------------------------------------------------------------------------------- /src/components/Interact.vue: -------------------------------------------------------------------------------- 1 | 92 | 93 | 425 | 426 | 506 | -------------------------------------------------------------------------------- /src/components/Deploy.vue: -------------------------------------------------------------------------------- 1 | 93 | 94 | 389 | 390 | 537 | --------------------------------------------------------------------------------