diff --git a/.browserslistrc b/.browserslistrc
new file mode 100644
index 0000000..214388f
--- /dev/null
+++ b/.browserslistrc
@@ -0,0 +1,3 @@
+> 1%
+last 2 versions
+not dead
diff --git a/.env b/.env
new file mode 100644
index 0000000..7c35c84
--- /dev/null
+++ b/.env
@@ -0,0 +1,4 @@
+VUE_APP_WS_URL=wss://rinkeby.infura.io/ws/v3/6c266c0719d144369f24093fbed4c6d8
+VUE_APP_HUB_URL=https://makiswap-dev.thinkincoin.com
+VUE_APP_IPFS_NODE=gateway.pinata.cloud
+VUE_DEFAULT_NETWORK=4
diff --git a/.env.dev b/.env.dev
new file mode 100644
index 0000000..95ceed5
--- /dev/null
+++ b/.env.dev
@@ -0,0 +1,4 @@
+HOST=makiswap-dev.thinkincoin.com
+VUE_APP_HTTP_URL=https://polygon-mainnet.infura.io/v3/6c266c0719d144369f24093fbed4c6d8
+VUE_APP_HUB_URL=https://makiswap-dev.thinkincoin.com
+VUE_APP_IPFS_NODE=gateway.pinata.cloud
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 0000000..ea2969f
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,24 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true
+ },
+ extends: [
+ 'plugin:vue/essential',
+ 'eslint:recommended',
+ '@vue/typescript/recommended',
+ '@vue/prettier',
+ '@vue/prettier/@typescript-eslint'
+ ],
+ parserOptions: {
+ ecmaVersion: 2020
+ },
+ rules: {
+ 'no-console': 'off',
+ 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/ban-ts-ignore': 'off',
+ '@typescript-eslint/camelcase': 'off',
+ '@typescript-eslint/no-undef': 'off'
+ }
+};
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..11f5d71
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,22 @@
+.DS_Store
+node_modules
+/dist
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000..7d93e18
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ singleQuote: true
+};
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7c9b370
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) Balancer Labs
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5de5f69
--- /dev/null
+++ b/README.md
@@ -0,0 +1,25 @@
+# Snapshot
+
+## Project setup
+```
+npm install
+```
+
+### Compiles and hot-reloads for development
+```
+npm run serve
+```
+
+### Compiles and minifies for production
+```
+npm run build
+```
+
+### Lints and fixes files
+```
+npm run lint
+```
+
+## License
+
+[MIT](LICENSE).
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 0000000..916db64
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+ presets: ['@vue/cli-plugin-babel/preset']
+};
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..b7cc453
--- /dev/null
+++ b/package.json
@@ -0,0 +1,72 @@
+{
+ "name": "snapshot",
+ "version": "0.1.1",
+ "repository": "balancer-labs/snapshot",
+ "license": "MIT",
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "@bonustrack/lock": "github:bonustrack/lock#e66d69d728e4003c4fcf5b124387bb16c37cbfe1",
+ "@ethersproject/abi": "^5.0.1",
+ "@ethersproject/address": "^5.0.1",
+ "@ethersproject/constants": "^5.0.1",
+ "@ethersproject/contracts": "^5.0.1",
+ "@ethersproject/providers": "^5.0.4",
+ "@ethersproject/units": "^5.0.1",
+ "@ethersproject/wallet": "^5.0.1",
+ "@pinata/sdk": "^1.1.10",
+ "@portis/web3": "2.0.0-beta.49",
+ "@primer/css": "^14.4.0",
+ "@vue/cli-plugin-babel": "^4.4.0",
+ "@vue/cli-plugin-eslint": "^4.4.0",
+ "@vue/cli-plugin-typescript": "^4.4.0",
+ "@vue/cli-service": "^4.4.0",
+ "@walletconnect/web3-provider": "^1.0.13",
+ "bluebird": "^3.7.2",
+ "body-parser": "^1.19.0",
+ "core-js": "^3.6.5",
+ "cors": "^2.8.5",
+ "eslint": "^6.7.2",
+ "fortmatic": "^2.0.6",
+ "frameguard": "^3.1.0",
+ "json-to-graphql-query": "^2.0.0",
+ "jsonexport": "^3.0.1",
+ "lodash": "^4.17.15",
+ "numeral": "^2.0.4",
+ "primer-support": "^5.0.0",
+ "redis": "^3.0.2",
+ "remarkable": "^2.0.1",
+ "sanitize-html": "^1.27.1",
+ "serve-static": "^1.14.1",
+ "stylus": "^0.54.8",
+ "stylus-loader": "^3.0.2",
+ "typescript": "~3.9.3",
+ "vue": "^2.6.11",
+ "vue-autofocus-directive": "^1.0.4",
+ "vue-cli-plugin-webpack-bundle-analyzer": "^2.0.0",
+ "vue-i18n": "^8.18.1",
+ "vue-infinite-scroll": "^2.0.2",
+ "vue-jazzicon": "^0.1.3",
+ "vue-router": "^3.2.0",
+ "vue-textarea-autosize": "^1.1.1",
+ "vuex": "^3.4.0"
+ },
+ "devDependencies": {
+ "@types/node": "^14.0.13",
+ "@typescript-eslint/eslint-plugin": "^2.33.0",
+ "@typescript-eslint/parser": "^2.33.0",
+ "@vue/cli-plugin-router": "^4.4.0",
+ "@vue/cli-plugin-vuex": "^4.4.0",
+ "@vue/eslint-config-prettier": "^6.0.0",
+ "@vue/eslint-config-typescript": "^5.0.2",
+ "eslint-plugin-prettier": "^3.1.3",
+ "eslint-plugin-vue": "^6.2.2",
+ "node-sass": "^4.12.0",
+ "prettier": "^1.19.1",
+ "sass-loader": "^8.0.2",
+ "vue-template-compiler": "^2.6.11"
+ }
+}
diff --git a/public/favicon.ico b/public/favicon.ico
new file mode 100644
index 0000000..f103ead
Binary files /dev/null and b/public/favicon.ico differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 0000000..9e5a626
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ Snapshot
+
+
+
+
+
+
+
diff --git a/src/App.vue b/src/App.vue
new file mode 100644
index 0000000..1e36f62
--- /dev/null
+++ b/src/App.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/src/assets/fonts/Calibre-Medium.eot b/src/assets/fonts/Calibre-Medium.eot
new file mode 100644
index 0000000..bf85d1d
Binary files /dev/null and b/src/assets/fonts/Calibre-Medium.eot differ
diff --git a/src/assets/fonts/Calibre-Medium.ttf b/src/assets/fonts/Calibre-Medium.ttf
new file mode 100644
index 0000000..9932cbf
Binary files /dev/null and b/src/assets/fonts/Calibre-Medium.ttf differ
diff --git a/src/assets/fonts/Calibre-Medium.woff b/src/assets/fonts/Calibre-Medium.woff
new file mode 100644
index 0000000..bb702dc
Binary files /dev/null and b/src/assets/fonts/Calibre-Medium.woff differ
diff --git a/src/assets/fonts/Calibre-Semibold.eot b/src/assets/fonts/Calibre-Semibold.eot
new file mode 100644
index 0000000..8303c21
Binary files /dev/null and b/src/assets/fonts/Calibre-Semibold.eot differ
diff --git a/src/assets/fonts/Calibre-Semibold.ttf b/src/assets/fonts/Calibre-Semibold.ttf
new file mode 100644
index 0000000..457cf3d
Binary files /dev/null and b/src/assets/fonts/Calibre-Semibold.ttf differ
diff --git a/src/assets/fonts/Calibre-Semibold.woff b/src/assets/fonts/Calibre-Semibold.woff
new file mode 100644
index 0000000..5bea21c
Binary files /dev/null and b/src/assets/fonts/Calibre-Semibold.woff differ
diff --git a/src/assets/fonts/iconfont.css b/src/assets/fonts/iconfont.css
new file mode 100644
index 0000000..f53652c
--- /dev/null
+++ b/src/assets/fonts/iconfont.css
@@ -0,0 +1,77 @@
+@font-face {font-family: "iconfont";
+ src: url('iconfont.eot?t=1595018697091'); /* IE9 */
+ src: url('iconfont.eot?t=1595018697091#iefix') format('embedded-opentype'), /* IE6-IE8 */
+ url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAhoAAsAAAAAEKQAAAgZAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCFFAqRJI1LATYCJANACyIABCAFhG0HgUEb3g2jopRwBpP9RYJtLP2hg6GpjdjQNCwMlxaY9USehGvQ1PapDEvsQJDx8M9+/X6fKzqGmCQRiSSxap5IUEmEpCl5Mmme5rHWa8Cvf/62V8ncvke6Rpbs3GraHuE//oZ/D0jS83W6xm4hW+H6A572L8k6tM6gj8lImm47yFNy5+Z/tz5waE9u+6WDgm92+3Kbf7igj4GptVZFNOri7VOitRP932Nu8X1MJX1EKtMZquuLJ4jECwXx0KmRUt5APOslmx+VaJ5AY65NqX3ntw+kKMOqA/0u+S4jRUueLCA8VDmFx43ZIJ6Sq5K7yRvcUz4+xq0JfxJ5ir3w8JkzhxwO/R5P74xopyQ3THYYj8NIsRqRPaQPnvIr0MRPZEYzNPMAszXJX+sMDevhahvscNZVt9z3Zvhn7PTHRyMC3F97nZodu16YzbnPaShxpJBplCpdqVqrI9fTl9z/eQWq6cD7ZWufISGLYFhnUTBcjWRfuAFIA7gDSAl4FkgFeBVIF/AWkBTwPtSyha+BtIBvgHQA/yCLnLFTSE+Bp4H1TUwGIyRggBvmIxYgyWPS44QNuqQpZJIfim5WCSGRBm8eNFc7h/lqzckzMta7e9G+6tL0brcKU4PjgxzXdJUq4XysXdBe5ghKFAjCYAmuNp4IpcY9YTrLuXw2VfyM2s+Xvyh7XWy9ITaanaGIybGeNkgbvQkJxixrWSNQVu+Oe/eQAeXxCfChg0mjX0MoZWY13xNDkJxxzEjqMaVSENQlV6ZIVIO6Eg5GIMxzBdKxyyE9Dn1Sl+FinPSi+yGw7A/qmqCTu40HwuGAR9aeuBTcPcmm9pqvJMrY55GwHwrtdTIrtL0k1d0oBwieJ0WREoQZY88xz7Me2j1gceufi0Dsv3qFr2cEPUfzrNhHu/UpWk6qF1g/RvRjeQOBJsjJ2aBB1qgQJapA5IP6lE2OFNIkb7TS7hVxTOpmp+vQYRsmVJ5PM8h9TvDvkCfMSHBChOl0gsmWeMIT/CKfaD8TKghaRkw1CbkMT95gm0URznFBk/zD9dTPeOphgrYmiu9RwpebpVCGClQQDkkH++AxUctEnHLMESGxOxMVrJNxSDuvcFE+R/h61etiLMY4+mULDPQkG7oYJOxEIrC40U8YjYN0UJCBP4wwHB+zhVLyMQcTu0prso8P36BgoxGCB+hgRQzuza4nxu0hWoU527tC5JTZNnY8iAgyGCBoeftfruW4pUq9KRSx5jGxUfEqHw1TxaHV8rHrEbZjkZSTTSatR8IsV5crTlwLtx4OIyYGQ9G2o5F2V/un0FVfXeQ51hpZDeiCBcqRNkxtXGJ7tudO/JbTxq3VK5vHdMuDt+26vL79Dn/o5W+d76yNiGloQH+Z0dIiJyX3yar5MYn9h2Z98wLIqxXRkFIZcCPAIeBU/5tK5U3/0VFRNyCFHDoarFVvxi9r3F2d2lkzVNveQeJkWztpyGS7nAsE9Fb4k93tLvwKvrnstqvuhqZMc2NBnQuvgCN5N7cCbD13xev+HPoXXId+Ha+9myo2eW90QHQIQz53exdXLJ5yBWXnXBC+wBXt55rSR3XL4Vy0fsPU1CKIwqo8Pv/8k4mC505iklHz0eHcAg7HxUppoPTj/mC4Tw0Onub1mc4Ky81BDh8mihfXbc3V6fK27WYIOX5r3p5teZ1yt9UuLiYCDtLA6BMa6NHoIc2RrBOQPd0LhfIKSNekQ0X5j1tACtGkI+XlDped3q+AJL9nBPMx+h2fqCifd9CTz6O2/Oj/29mzlI3ZuraPpH+IL3y8a0UDBcObNBM6CbsYeyIlsm5ri39jHFbr35R+d+fdpoxaPyzOr7F/X0RdAPbkY4t0kvcqMGDb6ZiDhS4JMu7zTlQUPDpa9cILfBXkdzuHvBGQzWpQPJED8c1xW3DoOtQkAYkIuzQT8T0uqG1lN2P3xrnkslp8S9xe3IELdsXtgfy5eyVBgYExufOePvXb+wcfq5n/A9TPr4cf1N88dvD9307NfUpTu8IPgxt7whz4/RNDtfO902QUOe2FduiJ7xGO1A51LklCelet6hXDkVWrSnpWrTYuWP3e0g7F/x1C1tFxTn8OciTxe2EXLnxZ0pW/Y7z75/PvLKlbgm3+3D2+Ix9aV3ocWjkKwIjXYqlKwqkHWK/8AidW4fh3d6PfApDS6AtMhA79sDb5GKW9mCsWiaXdNLIH9UZjaI+UepY7qbNfY7d7buz+V7UXvvqvm/ZOTh39PzLn0juodj51FECd0+ScBKwg/+VYcfCnRill3gU6s6QBT7EpQcPpcDarmOivSGlKZOZEKk0xQKI0B6Qqi90z79Ug11oHCpWdoLHKxe2tSVBGZDVWemVAGHgDiZ4nIDXwQ4CA9y/ITfUPCoPAQONIdPRsLY2l5RMEZsCh4xfqcyUFX2jKav87cG3E0Mwp8U+A2q+nw97A3n4BEjCLS/TEHRkjqEAV03PGMogiRRNUAXDT84xJtvt94XVpj6uYlO2FAGOk9A5q7EXVxymSWNsoO97/DnBZEQYDpv1RfQKQ5m+dGuoZRHC/0MhI01ZlqDbhGjEEC1QYi5QYdU4wiLgWhUq8jwsAzujxEjQltvXJciKqple8FI/5DdBgH3YQaKSRRR5FlFFFHU200Ylu9KIfg9Ao3fRdyYxFaPIK4uAnZktZE/kSnBz3gIeFKUPpSzevgSH3sjFIm+OR0pB3fePZcTmJrN7SMYuiGswMoGTRVmyzw7SrsmPGw6zVgEWGqKZbNimrgiNoJSEAAA==') format('woff2'),
+ url('iconfont.woff?t=1595018697091') format('woff'),
+ url('iconfont.ttf?t=1595018697091') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
+ url('iconfont.svg?t=1595018697091#iconfont') format('svg'); /* iOS 4.1- */
+}
+
+.iconfont {
+ font-family: "iconfont" !important;
+ font-size: 16px;
+ font-style: normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+.iconsignature:before {
+ content: "\e600";
+}
+
+.iconreceipt-outlined:before {
+ content: "\e8eb";
+}
+
+.iconcheck:before {
+ content: "\e679";
+}
+
+.iconwarning:before {
+ content: "\e62c";
+}
+
+.iconsearch:before {
+ content: "\e6f2";
+}
+
+.iconmenu:before {
+ content: "\e609";
+}
+
+.iconclose:before {
+ content: "\e63e";
+}
+
+.icongithub:before {
+ content: "\e667";
+}
+
+.iconplus-small:before {
+ content: "\e69d";
+}
+
+.iconexternal-link:before {
+ content: "\e636";
+}
+
+.icongo:before {
+ content: "\e6cb";
+}
+
+.iconback:before {
+ content: "\e6cc";
+}
+
+.iconuser:before {
+ content: "\e66f";
+}
+
+.iconarrow-up:before {
+ content: "\e75c";
+}
+
+.iconarrow-down:before {
+ content: "\e75d";
+}
+
diff --git a/src/assets/fonts/iconfont.eot b/src/assets/fonts/iconfont.eot
new file mode 100644
index 0000000..13e7224
Binary files /dev/null and b/src/assets/fonts/iconfont.eot differ
diff --git a/src/assets/fonts/iconfont.json b/src/assets/fonts/iconfont.json
new file mode 100644
index 0000000..efe2c28
--- /dev/null
+++ b/src/assets/fonts/iconfont.json
@@ -0,0 +1,114 @@
+{
+ "id": "1946815",
+ "name": "gang",
+ "font_family": "iconfont",
+ "css_prefix_text": "icon",
+ "description": "",
+ "glyphs": [
+ {
+ "icon_id": "11399282",
+ "name": "signature",
+ "font_class": "signature",
+ "unicode": "e600",
+ "unicode_decimal": 58880
+ },
+ {
+ "icon_id": "15617545",
+ "name": "receipt-outlined",
+ "font_class": "receipt-outlined",
+ "unicode": "e8eb",
+ "unicode_decimal": 59627
+ },
+ {
+ "icon_id": "10561798",
+ "name": "Check, label",
+ "font_class": "check",
+ "unicode": "e679",
+ "unicode_decimal": 59001
+ },
+ {
+ "icon_id": "59347",
+ "name": "warning",
+ "font_class": "warning",
+ "unicode": "e62c",
+ "unicode_decimal": 58924
+ },
+ {
+ "icon_id": "1262104",
+ "name": "search",
+ "font_class": "search",
+ "unicode": "e6f2",
+ "unicode_decimal": 59122
+ },
+ {
+ "icon_id": "1336076",
+ "name": "Menu",
+ "font_class": "menu",
+ "unicode": "e609",
+ "unicode_decimal": 58889
+ },
+ {
+ "icon_id": "2518398",
+ "name": "close",
+ "font_class": "close",
+ "unicode": "e63e",
+ "unicode_decimal": 58942
+ },
+ {
+ "icon_id": "5679219",
+ "name": "mark-github",
+ "font_class": "github",
+ "unicode": "e667",
+ "unicode_decimal": 58983
+ },
+ {
+ "icon_id": "5679273",
+ "name": "plus-small",
+ "font_class": "plus-small",
+ "unicode": "e69d",
+ "unicode_decimal": 59037
+ },
+ {
+ "icon_id": "7141712",
+ "name": "external-link",
+ "font_class": "external-link",
+ "unicode": "e636",
+ "unicode_decimal": 58934
+ },
+ {
+ "icon_id": "11262646",
+ "name": "go",
+ "font_class": "go",
+ "unicode": "e6cb",
+ "unicode_decimal": 59083
+ },
+ {
+ "icon_id": "11262647",
+ "name": "back",
+ "font_class": "back",
+ "unicode": "e6cc",
+ "unicode_decimal": 59084
+ },
+ {
+ "icon_id": "13519508",
+ "name": "user-solid",
+ "font_class": "user",
+ "unicode": "e66f",
+ "unicode_decimal": 58991
+ },
+ {
+ "icon_id": "13895880",
+ "name": "arrow-up",
+ "font_class": "arrow-up",
+ "unicode": "e75c",
+ "unicode_decimal": 59228
+ },
+ {
+ "icon_id": "14232782",
+ "name": "arrow-up",
+ "font_class": "arrow-down",
+ "unicode": "e75d",
+ "unicode_decimal": 59229
+ }
+ ]
+}
diff --git a/src/assets/fonts/iconfont.svg b/src/assets/fonts/iconfont.svg
new file mode 100644
index 0000000..1e5ae12
--- /dev/null
+++ b/src/assets/fonts/iconfont.svg
@@ -0,0 +1,71 @@
+
+
+
+
diff --git a/src/assets/fonts/iconfont.ttf b/src/assets/fonts/iconfont.ttf
new file mode 100644
index 0000000..28ba4cb
Binary files /dev/null and b/src/assets/fonts/iconfont.ttf differ
diff --git a/src/assets/fonts/iconfont.woff b/src/assets/fonts/iconfont.woff
new file mode 100644
index 0000000..7873a6e
Binary files /dev/null and b/src/assets/fonts/iconfont.woff differ
diff --git a/src/assets/fonts/iconfont.woff2 b/src/assets/fonts/iconfont.woff2
new file mode 100644
index 0000000..2fa4c90
Binary files /dev/null and b/src/assets/fonts/iconfont.woff2 differ
diff --git a/src/assets/logo.svg b/src/assets/logo.svg
new file mode 100644
index 0000000..ee8d35e
--- /dev/null
+++ b/src/assets/logo.svg
@@ -0,0 +1,19 @@
+
+
\ No newline at end of file
diff --git a/src/components/Avatar.vue b/src/components/Avatar.vue
new file mode 100644
index 0000000..5b414b2
--- /dev/null
+++ b/src/components/Avatar.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/components/Block.vue b/src/components/Block.vue
new file mode 100644
index 0000000..3de78c9
--- /dev/null
+++ b/src/components/Block.vue
@@ -0,0 +1,19 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Block/Results.vue b/src/components/Block/Results.vue
new file mode 100644
index 0000000..4335806
--- /dev/null
+++ b/src/components/Block/Results.vue
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+ {{ _numeral(results.totalBalances[i]) }}
+ {{ namespace.symbol || _shorten(namespace.token) }}
+
+
+
+
+
+
+ Download report
+
+
+
+
+
diff --git a/src/components/Block/Votes.vue b/src/components/Block/Votes.vue
new file mode 100644
index 0000000..8adc19e
--- /dev/null
+++ b/src/components/Block/Votes.vue
@@ -0,0 +1,79 @@
+
+
+
+
+ See more
+
+
+
+
+
+
diff --git a/src/components/Container.vue b/src/components/Container.vue
new file mode 100644
index 0000000..ecf77f6
--- /dev/null
+++ b/src/components/Container.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/src/components/Icon.vue b/src/components/Icon.vue
new file mode 100644
index 0000000..6bf4016
--- /dev/null
+++ b/src/components/Icon.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
diff --git a/src/components/Modal/About.vue b/src/components/Modal/About.vue
new file mode 100644
index 0000000..51dc03b
--- /dev/null
+++ b/src/components/Modal/About.vue
@@ -0,0 +1,77 @@
+
+
+ About
+
+
+
+
+
+ {{ pkg.version }}
+
+
+
+ {{ pkg.license }}
+
+
+
+ {{ config.network === 'homestead' ? 'mainnet' : config.network }}
+
+
+
+
+ {{ ipfsNode }}
+
+
+
+ {{ config.hubUrl }}
+
+
+
+
+
+
+
diff --git a/src/components/Modal/Account.vue b/src/components/Modal/Account.vue
new file mode 100644
index 0000000..33eb244
--- /dev/null
+++ b/src/components/Modal/Account.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
diff --git a/src/components/Modal/Confirm.vue b/src/components/Modal/Confirm.vue
new file mode 100644
index 0000000..f0e2c91
--- /dev/null
+++ b/src/components/Modal/Confirm.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
diff --git a/src/components/Modal/Receipt.vue b/src/components/Modal/Receipt.vue
new file mode 100644
index 0000000..3ed54b6
--- /dev/null
+++ b/src/components/Modal/Receipt.vue
@@ -0,0 +1,39 @@
+
+
+ Receipt
+
+
+
+
+
+
diff --git a/src/components/Modal/SelectDate.vue b/src/components/Modal/SelectDate.vue
new file mode 100644
index 0000000..0450b02
--- /dev/null
+++ b/src/components/Modal/SelectDate.vue
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
diff --git a/src/components/Modal/User.vue b/src/components/Modal/User.vue
new file mode 100644
index 0000000..867812c
--- /dev/null
+++ b/src/components/Modal/User.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
diff --git a/src/components/Notifications.vue b/src/components/Notifications.vue
new file mode 100644
index 0000000..03e8a47
--- /dev/null
+++ b/src/components/Notifications.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+ {{ item.message }}
+
+
+
+
+
+
+
diff --git a/src/components/RowLoading.vue b/src/components/RowLoading.vue
new file mode 100644
index 0000000..5ac2647
--- /dev/null
+++ b/src/components/RowLoading.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
diff --git a/src/components/RowProposal.vue b/src/components/RowProposal.vue
new file mode 100644
index 0000000..9fb6672
--- /dev/null
+++ b/src/components/RowProposal.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+ By {{ _shorten(proposal.address) }} {{ _numeral(proposal.balance) }}
+ {{ namespace.symbol }}
+
+ start
+
+ end
+
+
+
+
+
+
diff --git a/src/components/State.vue b/src/components/State.vue
new file mode 100644
index 0000000..4bc0f2d
--- /dev/null
+++ b/src/components/State.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/src/components/Sticky.vue b/src/components/Sticky.vue
new file mode 100644
index 0000000..658c60f
--- /dev/null
+++ b/src/components/Sticky.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
diff --git a/src/components/Token.vue b/src/components/Token.vue
new file mode 100644
index 0000000..5b18b5d
--- /dev/null
+++ b/src/components/Token.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/src/components/Topnav.vue b/src/components/Topnav.vue
new file mode 100644
index 0000000..2ea852b
--- /dev/null
+++ b/src/components/Topnav.vue
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Button.vue b/src/components/Ui/Button.vue
new file mode 100644
index 0000000..c3fe6a9
--- /dev/null
+++ b/src/components/Ui/Button.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Calendar.vue b/src/components/Ui/Calendar.vue
new file mode 100644
index 0000000..7421abd
--- /dev/null
+++ b/src/components/Ui/Calendar.vue
@@ -0,0 +1,143 @@
+
+
+
+
+
{{ monthName }} {{ year }}
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Counter.vue b/src/components/Ui/Counter.vue
new file mode 100644
index 0000000..f0f3ad9
--- /dev/null
+++ b/src/components/Ui/Counter.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Label.vue b/src/components/Ui/Label.vue
new file mode 100644
index 0000000..2d4517f
--- /dev/null
+++ b/src/components/Ui/Label.vue
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Loading.vue b/src/components/Ui/Loading.vue
new file mode 100644
index 0000000..91a3a39
--- /dev/null
+++ b/src/components/Ui/Loading.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Markdown.vue b/src/components/Ui/Markdown.vue
new file mode 100644
index 0000000..100f6ef
--- /dev/null
+++ b/src/components/Ui/Markdown.vue
@@ -0,0 +1,42 @@
+
+
+
+
+
+
diff --git a/src/components/Ui/Modal.vue b/src/components/Ui/Modal.vue
new file mode 100644
index 0000000..a4f89e6
--- /dev/null
+++ b/src/components/Ui/Modal.vue
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
diff --git a/src/components/Ui/Progress.vue b/src/components/Ui/Progress.vue
new file mode 100644
index 0000000..eb49c5b
--- /dev/null
+++ b/src/components/Ui/Progress.vue
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/components/User.vue b/src/components/User.vue
new file mode 100644
index 0000000..ec7ce9a
--- /dev/null
+++ b/src/components/User.vue
@@ -0,0 +1,43 @@
+
+
+
+
+ {{ name }}
+
+
+
+
+
+
+
diff --git a/src/config.json b/src/config.json
new file mode 100644
index 0000000..7df8b50
--- /dev/null
+++ b/src/config.json
@@ -0,0 +1,88 @@
+{
+ "master": {
+ "network": "homestead",
+ "chainId": 4,
+ "subgraphUrl": "https://api.thegraph.com/subgraphs/",
+ "hubUrl": "https://makiswap-dev.thinkincoin.com",
+ "multicall": "0xb5ec65821e27de5ec9d52d5826057a99bd78c875",
+ "connectors": {
+ "injected": {
+ "id": "injected",
+ "name": "MetaMask"
+ },
+ "portis": {
+ "id": "portis",
+ "name": "Portis",
+ "options": {
+ "dappId": "3f1c3cfc-7dd5-4e8a-aa03-71ff7396d9fe",
+ "network": "mainnet"
+ }
+ },
+ "fortmatic": {
+ "id": "fortmatic",
+ "name": "Fortmatic",
+ "options": {
+ "apiKey": "pk_live_9CE8FD92E54684ED"
+ }
+ }
+ }
+ },
+ "develop": {
+ "network": "heco",
+ "chainId": 4,
+ "subgraphUrl": "https://api.thegraph.com/subgraphs/",
+ "hubUrl": "https://makiswap-dev.thinkincoin.com",
+ "multicall": "0xb5ec65821e27de5ec9d52d5826057a99bd78c875",
+ "disableHostCheck": true,
+ "connectors": {
+ "injected": {
+ "id": "injected",
+ "name": "MetaMask"
+ },
+ "portis": {
+ "id": "portis",
+ "name": "Portis",
+ "options": {
+ "dappId": "3f1c3cfc-7dd5-4e8a-aa03-71ff7396d9fe",
+ "network": "mainnet"
+ }
+ },
+ "fortmatic": {
+ "id": "fortmatic",
+ "name": "Fortmatic",
+ "options": {
+ "apiKey": "pk_live_9CE8FD92E54684ED"
+ }
+ }
+ }
+ },
+ "local": {
+ "network": "homestead",
+ "chainId": 4,
+ "subgraphUrl": "https://api.thegraph.com/subgraphs/",
+ "hubUrl": "http://localhost:3001",
+ "multicall": "0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441",
+ "disableHostCheck": true,
+ "connectors": {
+ "injected": {
+ "id": "injected",
+ "name": "MetaMask"
+ },
+ "portis": {
+ "id": "portis",
+ "name": "Portis",
+ "options": {
+ "dappId": "3f1c3cfc-7dd5-4e8a-aa03-71ff7396d9fe",
+ "network": "mainnet"
+ }
+ },
+ "magic": {
+ "id": "magic",
+ "name": "Magic",
+ "options": {
+ "apiKey": "pk_live_9CE8FD92E54684ED"
+ }
+ }
+ }
+ }
+}
diff --git a/src/fonts.scss b/src/fonts.scss
new file mode 100644
index 0000000..c6aee22
--- /dev/null
+++ b/src/fonts.scss
@@ -0,0 +1,21 @@
+@import './assets/fonts/iconfont.css';
+
+@font-face {
+ font-family: 'Calibre-Medium';
+ src: url('./assets/fonts/Calibre-Medium.eot');
+ src: url('./assets/fonts/Calibre-Medium.eot?#iefix') format('embedded-opentype'),
+ url('./assets/fonts/Calibre-Medium.woff') format('woff'),
+ url('./assets/fonts/Calibre-Medium.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
+
+@font-face {
+ font-family: 'Calibre-Semibold';
+ src: url('./assets/fonts/Calibre-Semibold.eot');
+ src: url('./assets/fonts/Calibre-Semibold.eot?#iefix') format('embedded-opentype'),
+ url('./assets/fonts/Calibre-Semibold.woff') format('woff'),
+ url('./assets/fonts/Calibre-Semibold.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
+}
diff --git a/src/helpers/abi/Multicall.json b/src/helpers/abi/Multicall.json
new file mode 100644
index 0000000..801f1df
--- /dev/null
+++ b/src/helpers/abi/Multicall.json
@@ -0,0 +1,146 @@
+{
+ "contractName": "Multicall",
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "getCurrentBlockTimestamp",
+ "outputs": [
+ {
+ "name": "timestamp",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "components": [
+ {
+ "name": "target",
+ "type": "address"
+ },
+ {
+ "name": "callData",
+ "type": "bytes"
+ }
+ ],
+ "name": "calls",
+ "type": "tuple[]"
+ }
+ ],
+ "name": "aggregate",
+ "outputs": [
+ {
+ "name": "blockNumber",
+ "type": "uint256"
+ },
+ {
+ "name": "returnData",
+ "type": "bytes[]"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "getLastBlockHash",
+ "outputs": [
+ {
+ "name": "blockHash",
+ "type": "bytes32"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "addr",
+ "type": "address"
+ }
+ ],
+ "name": "getEthBalance",
+ "outputs": [
+ {
+ "name": "balance",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "getCurrentBlockDifficulty",
+ "outputs": [
+ {
+ "name": "difficulty",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "getCurrentBlockGasLimit",
+ "outputs": [
+ {
+ "name": "gaslimit",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "getCurrentBlockCoinbase",
+ "outputs": [
+ {
+ "name": "coinbase",
+ "type": "address"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "blockNumber",
+ "type": "uint256"
+ }
+ ],
+ "name": "getBlockHash",
+ "outputs": [
+ {
+ "name": "blockHash",
+ "type": "bytes32"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ }
+ ]
+}
diff --git a/src/helpers/abi/TestToken.json b/src/helpers/abi/TestToken.json
new file mode 100644
index 0000000..21d7a21
--- /dev/null
+++ b/src/helpers/abi/TestToken.json
@@ -0,0 +1,1177 @@
+{
+ "contractName": "TestToken",
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "mint",
+ "outputs": [],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "internalType": "uint8",
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "addedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "increaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "account",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "subtractedValue",
+ "type": "uint256"
+ }
+ ],
+ "name": "decreaseAllowance",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "recipient",
+ "type": "address"
+ },
+ {
+ "internalType": "uint256",
+ "name": "amount",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "name",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "symbol",
+ "type": "string"
+ },
+ {
+ "internalType": "uint8",
+ "name": "decimals",
+ "type": "uint8"
+ },
+ {
+ "internalType": "uint256",
+ "name": "initialSupply",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ }
+ ],
+ "metadata": "{\"compiler\":{\"version\":\"0.5.11+commit.c082d0b4\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[],\"name\":\"name\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"approve\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"totalSupply\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transferFrom\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"decimals\",\"outputs\":[{\"internalType\":\"uint8\",\"name\":\"\",\"type\":\"uint8\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"addedValue\",\"type\":\"uint256\"}],\"name\":\"increaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"}],\"name\":\"balanceOf\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"symbol\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"subtractedValue\",\"type\":\"uint256\"}],\"name\":\"decreaseAllowance\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"transfer\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"}],\"name\":\"allowance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"string\",\"name\":\"name\",\"type\":\"string\"},{\"internalType\":\"string\",\"name\":\"symbol\",\"type\":\"string\"},{\"internalType\":\"uint8\",\"name\":\"decimals\",\"type\":\"uint8\"},{\"internalType\":\"uint256\",\"name\":\"initialSupply\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Transfer\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"owner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"spender\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"Approval\",\"type\":\"event\"}],\"devdoc\":{\"methods\":{\"allowance(address,address)\":{\"details\":\"See `IERC20.allowance`.\"},\"approve(address,uint256)\":{\"details\":\"See `IERC20.approve`. * Requirements: * - `spender` cannot be the zero address.\"},\"balanceOf(address)\":{\"details\":\"See `IERC20.balanceOf`.\"},\"decimals()\":{\"details\":\"Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). * Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. * > Note that this information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including `IERC20.balanceOf` and `IERC20.transfer`.\"},\"decreaseAllowance(address,uint256)\":{\"details\":\"Atomically decreases the allowance granted to `spender` by the caller. * This is an alternative to `approve` that can be used as a mitigation for problems described in `IERC20.approve`. * Emits an `Approval` event indicating the updated allowance. * Requirements: * - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`.\"},\"increaseAllowance(address,uint256)\":{\"details\":\"Atomically increases the allowance granted to `spender` by the caller. * This is an alternative to `approve` that can be used as a mitigation for problems described in `IERC20.approve`. * Emits an `Approval` event indicating the updated allowance. * Requirements: * - `spender` cannot be the zero address.\"},\"name()\":{\"details\":\"Returns the name of the token.\"},\"symbol()\":{\"details\":\"Returns the symbol of the token, usually a shorter version of the name.\"},\"totalSupply()\":{\"details\":\"See `IERC20.totalSupply`.\"},\"transfer(address,uint256)\":{\"details\":\"See `IERC20.transfer`. * Requirements: * - `recipient` cannot be the zero address. - the caller must have a balance of at least `amount`.\"},\"transferFrom(address,address,uint256)\":{\"details\":\"See `IERC20.transferFrom`. * Emits an `Approval` event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of `ERC20`; * Requirements: - `sender` and `recipient` cannot be the zero address. - `sender` must have a balance of at least `value`. - the caller must have allowance for `sender`'s tokens of at least `amount`.\"}}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/Users/thomas/Code/client/balancer/external-contracts/contracts/TestToken.sol\":\"TestToken\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"/Users/thomas/Code/client/balancer/external-contracts/contracts/TestToken.sol\":{\"keccak256\":\"0x12fdb31a50e502eac30b764735cdb7d4acff7a51a564933dc79a63b9fd5d3f81\",\"urls\":[\"bzz-raw://512ea3a0db85076dedd0e75dd639e8777215f36742e7eac40fcffb30e4b5e40b\",\"dweb:/ipfs/QmZmEcpKAMkekctF5GJQgsAL4VqS62HepSDbmGbEr7evuW\"]},\"@openzeppelin/contracts/math/SafeMath.sol\":{\"keccak256\":\"0xd1804d04fb39689453f673601429a99a0c68c422a981fc338773df9a59180fe9\",\"urls\":[\"bzz-raw://1b9307920e0378d58c6677f8952ad090a9ecb30e878835e301a0d18386a870c1\",\"dweb:/ipfs/QmYYixTDVF4FXqFpYzEcufAwEY9BFBJ33Ew9ncsGvD7btC\"]},\"@openzeppelin/contracts/token/ERC20/ERC20.sol\":{\"keccak256\":\"0x852793a3c2f86d336a683b30d688ec3dcfc57451af5a2bf5975cda3b7191a901\",\"urls\":[\"bzz-raw://4f5b57664069671648fb81f55b0082faecdf1b2f159eec6b1fa6cef9b7d73bc5\",\"dweb:/ipfs/QmcyytaLs7zFdb4Uu7C5PmQRhQdB3wA3fUdkV6mkYfdDFH\"]},\"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\":{\"keccak256\":\"0xc61b3603089b09a730d8ca72e9133a496cc4405da40e9b87c12f073245d774bf\",\"urls\":[\"bzz-raw://de8bb0003d53de236913f0e0102e7a9d015e02098f2495edd000f207fe2be2f4\",\"dweb:/ipfs/QmbtwNwAJEehWWL7yGGyyMoenQvcqtz91pqLgQPpLRoLYC\"]},\"@openzeppelin/contracts/token/ERC20/IERC20.sol\":{\"keccak256\":\"0x90e8c2521653bbb1768b05889c5760031e688d9cd361f167489b89215e201b95\",\"urls\":[\"bzz-raw://d0abb99bb8bfc2bc0a89902b8ed1dc0442ad08cc78cee64c291b3df6a27bcccc\",\"dweb:/ipfs/QmP5NaEwZthQeM2ESz4WTT3osrP7jhbvu7ocbttBi2JAw6\"]}},\"version\":1}",
+ "bytecode": "0x60806040523480156200001157600080fd5b50604051620014f5380380620014f5833981810160405260808110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b838201915060208201858111156200006f57600080fd5b82518660018202830111640100000000821117156200008d57600080fd5b8083526020830192505050908051906020019080838360005b83811015620000c3578082015181840152602081019050620000a6565b50505050905090810190601f168015620000f15780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200011557600080fd5b838201915060208201858111156200012c57600080fd5b82518660018202830111640100000000821117156200014a57600080fd5b8083526020830192505050908051906020019080838360005b838110156200018057808201518184015260208101905062000163565b50505050905090810190601f168015620001ae5780820380516001836020036101000a031916815260200191505b5060405260200180519060200190929190805190602001909291905050508383838260039080519060200190620001e79291906200048e565b508160049080519060200190620002009291906200048e565b5080600560006101000a81548160ff021916908360ff1602179055505050506200023133826200023b60201b60201c565b505050506200053d565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415620002df576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b620002fb816002546200040560201b62000e5d1790919060201c565b60028190555062000359816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546200040560201b62000e5d1790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b60008082840190508381101562000484576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620004d157805160ff191683800117855562000502565b8280016001018555821562000502579182015b8281111562000501578251825591602001919060010190620004e4565b5b50905062000511919062000515565b5090565b6200053a91905b80821115620005365760008160009055506001016200051c565b5090565b90565b610fa8806200054d6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025f57806370a08231146102c557806395d89b411461031d578063a457c2d7146103a0578063a9059cbb14610406578063dd62ed3e1461046c576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b66104e4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610586565b604051808215151515815260200191505060405180910390f35b61019f61059d565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105a7565b604051808215151515815260200191505060405180910390f35b610243610658565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061066f565b604051808215151515815260200191505060405180910390f35b610307600480360360208110156102db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610714565b6040518082815260200191505060405180910390f35b61032561075c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036557808201518184015260208101905061034a565b50505050905090810190601f1680156103925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103ec600480360360408110156103b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107fe565b604051808215151515815260200191505060405180910390f35b6104526004803603604081101561041c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108a3565b604051808215151515815260200191505060405180910390f35b6104ce6004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108ba565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561057c5780601f106105515761010080835404028352916020019161057c565b820191906000526020600020905b81548152906001019060200180831161055f57829003601f168201915b5050505050905090565b6000610593338484610941565b6001905092915050565b6000600254905090565b60006105b4848484610b38565b61064d843361064885600160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b610941565b600190509392505050565b6000600560009054906101000a900460ff16905090565b600061070a338461070585600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5d90919063ffffffff16565b610941565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107f45780601f106107c9576101008083540402835291602001916107f4565b820191906000526020600020905b8154815290600101906020018083116107d757829003601f168201915b5050505050905090565b6000610899338461089485600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b610941565b6001905092915050565b60006108b0338484610b38565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156109c7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180610f506024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a4d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610f096022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610bbe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180610f2b6025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610c44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610ee66023913960400191505060405180910390fd5b610c95816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d28816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5d90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600082821115610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b600082840390508091505092915050565b600080828401905083811015610edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b809150509291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373a265627a7a723158201a68b621826f87edc888b7fee157c6fb5686e303e10dcb96b5e4698620f1204364736f6c634300050b0032",
+ "deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025f57806370a08231146102c557806395d89b411461031d578063a457c2d7146103a0578063a9059cbb14610406578063dd62ed3e1461046c576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019757806323b872dd146101b5578063313ce5671461023b575b600080fd5b6100b66104e4565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610586565b604051808215151515815260200191505060405180910390f35b61019f61059d565b6040518082815260200191505060405180910390f35b610221600480360360608110156101cb57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105a7565b604051808215151515815260200191505060405180910390f35b610243610658565b604051808260ff1660ff16815260200191505060405180910390f35b6102ab6004803603604081101561027557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061066f565b604051808215151515815260200191505060405180910390f35b610307600480360360208110156102db57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610714565b6040518082815260200191505060405180910390f35b61032561075c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561036557808201518184015260208101905061034a565b50505050905090810190601f1680156103925780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103ec600480360360408110156103b657600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506107fe565b604051808215151515815260200191505060405180910390f35b6104526004803603604081101561041c57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108a3565b604051808215151515815260200191505060405180910390f35b6104ce6004803603604081101561048257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108ba565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561057c5780601f106105515761010080835404028352916020019161057c565b820191906000526020600020905b81548152906001019060200180831161055f57829003601f168201915b5050505050905090565b6000610593338484610941565b6001905092915050565b6000600254905090565b60006105b4848484610b38565b61064d843361064885600160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b610941565b600190509392505050565b6000600560009054906101000a900460ff16905090565b600061070a338461070585600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5d90919063ffffffff16565b610941565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156107f45780601f106107c9576101008083540402835291602001916107f4565b820191906000526020600020905b8154815290600101906020018083116107d757829003601f168201915b5050505050905090565b6000610899338461089485600160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b610941565b6001905092915050565b60006108b0338484610b38565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156109c7576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526024815260200180610f506024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610a4d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610f096022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610bbe576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526025815260200180610f2b6025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610c44576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610ee66023913960400191505060405180910390fd5b610c95816000808673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610dd490919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610d28816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610e5d90919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b600082821115610e4c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601e8152602001807f536166654d6174683a207375627472616374696f6e206f766572666c6f77000081525060200191505060405180910390fd5b600082840390508091505092915050565b600080828401905083811015610edb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b809150509291505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f2061646472657373a265627a7a723158201a68b621826f87edc888b7fee157c6fb5686e303e10dcb96b5e4698620f1204364736f6c634300050b0032",
+ "sourceMap": "146:238:1:-;;;195:187;8:9:-1;5:2;;;30:1;27;20:12;5:2;195:187:1;;;;;;;;;;;;;;;13:3:-1;8;5:12;2:2;;;30:1;27;20:12;2:2;195:187:1;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;71:11;66:3;62:21;55:28;;123:4;118:3;114:14;159:9;141:16;138:31;135:2;;;182:1;179;172:12;135:2;219:3;213:10;330:9;325:1;311:12;307:20;289:16;285:43;282:58;261:11;247:12;244:29;233:115;230:2;;;361:1;358;351:12;230:2;384:12;379:3;372:25;420:4;415:3;411:14;404:21;;0:432;;195:187:1;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;195:187:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;19:11:-1;14:3;11:20;8:2;;;44:1;41;34:12;8:2;71:11;66:3;62:21;55:28;;123:4;118:3;114:14;159:9;141:16;138:31;135:2;;;182:1;179;172:12;135:2;219:3;213:10;330:9;325:1;311:12;307:20;289:16;285:43;282:58;261:11;247:12;244:29;233:115;230:2;;;361:1;358;351:12;230:2;384:12;379:3;372:25;420:4;415:3;411:14;404:21;;0:432;;195:187:1;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;195:187:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;302:4;308:6;316:8;512:4:4;504:5;:12;;;;;;;;;;;;:::i;:::-;;536:6;526:7;:16;;;;;;;;;;;;:::i;:::-;;564:8;552:9;;:20;;;;;;;;;;;;;;;;;;416:163;;;343:32:1;349:10;361:13;343:5;;;:32;;:::i;:::-;195:187;;;;146:238;;5771:302:3;5865:1;5846:21;;:7;:21;;;;5838:65;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5929:24;5946:6;5929:12;;:16;;;;;;:24;;;;:::i;:::-;5914:12;:39;;;;5984:30;6007:6;5984:9;:18;5994:7;5984:18;;;;;;;;;;;;;;;;:22;;;;;;:30;;;;:::i;:::-;5963:9;:18;5973:7;5963:18;;;;;;;;;;;;;;;:51;;;;6050:7;6029:37;;6046:1;6029:37;;;6059:6;6029:37;;;;;;;;;;;;;;;;;;5771:302;;:::o;834:176:2:-;892:7;911:9;927:1;923;:5;911:17;;951:1;946;:6;;938:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1002:1;995:8;;;834:176;;;;:::o;146:238:1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;:::-;;;;;;;",
+ "deployedSourceMap": "146:238:1:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;146:238:1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;644:81:4;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;644:81:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2453:145:3;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2453:145:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;1514:89;;;:::i;:::-;;;;;;;;;;;;;;;;;;;3055:252;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3055:252:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;1478:81:4;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;3702:203:3;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;3702:203:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;1661:108;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;1661:108:3;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;838:85:4;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;23:1:-1;8:100;33:3;30:1;27:10;8:100;;;99:1;94:3;90:11;84:18;80:1;75:3;71:11;64:39;52:2;49:1;45:10;40:15;;8:100;;;12:14;838:85:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4392:213:3;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;4392:213:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;1972:153;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;1972:153:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;2183:132;;;;;;13:2:-1;8:3;5:11;2:2;;;29:1;26;19:12;2:2;2183:132:3;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;644:81:4;681:13;713:5;706:12;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;644:81;:::o;2453:145:3:-;2518:4;2534:36;2543:10;2555:7;2564:5;2534:8;:36::i;:::-;2587:4;2580:11;;2453:145;;;;:::o;1514:89::-;1558:7;1584:12;;1577:19;;1514:89;:::o;3055:252::-;3144:4;3160:36;3170:6;3178:9;3189:6;3160:9;:36::i;:::-;3206:73;3215:6;3223:10;3235:43;3271:6;3235:11;:19;3247:6;3235:19;;;;;;;;;;;;;;;:31;3255:10;3235:31;;;;;;;;;;;;;;;;:35;;:43;;;;:::i;:::-;3206:8;:73::i;:::-;3296:4;3289:11;;3055:252;;;;;:::o;1478:81:4:-;1519:5;1543:9;;;;;;;;;;;1536:16;;1478:81;:::o;3702:203:3:-;3782:4;3798:79;3807:10;3819:7;3828:48;3865:10;3828:11;:23;3840:10;3828:23;;;;;;;;;;;;;;;:32;3852:7;3828:32;;;;;;;;;;;;;;;;:36;;:48;;;;:::i;:::-;3798:8;:79::i;:::-;3894:4;3887:11;;3702:203;;;;:::o;1661:108::-;1718:7;1744:9;:18;1754:7;1744:18;;;;;;;;;;;;;;;;1737:25;;1661:108;;;:::o;838:85:4:-;877:13;909:7;902:14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;838:85;:::o;4392:213:3:-;4477:4;4493:84;4502:10;4514:7;4523:53;4560:15;4523:11;:23;4535:10;4523:23;;;;;;;;;;;;;;;:32;4547:7;4523:32;;;;;;;;;;;;;;;;:36;;:53;;;;:::i;:::-;4493:8;:84::i;:::-;4594:4;4587:11;;4392:213;;;;:::o;1972:153::-;2041:4;2057:40;2067:10;2079:9;2090:6;2057:9;:40::i;:::-;2114:4;2107:11;;1972:153;;;;:::o;2183:132::-;2255:7;2281:11;:18;2293:5;2281:18;;;;;;;;;;;;;;;:27;2300:7;2281:27;;;;;;;;;;;;;;;;2274:34;;2183:132;;;;:::o;7117:329::-;7226:1;7209:19;;:5;:19;;;;7201:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7306:1;7287:21;;:7;:21;;;;7279:68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7388:5;7358:11;:18;7370:5;7358:18;;;;;;;;;;;;;;;:27;7377:7;7358:27;;;;;;;;;;;;;;;:35;;;;7424:7;7408:31;;7417:5;7408:31;;;7433:5;7408:31;;;;;;;;;;;;;;;;;;7117:329;;;:::o;5079:422::-;5194:1;5176:20;;:6;:20;;;;5168:70;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5277:1;5256:23;;:9;:23;;;;5248:71;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5350:29;5372:6;5350:9;:17;5360:6;5350:17;;;;;;;;;;;;;;;;:21;;:29;;;;:::i;:::-;5330:9;:17;5340:6;5330:17;;;;;;;;;;;;;;;:49;;;;5412:32;5437:6;5412:9;:20;5422:9;5412:20;;;;;;;;;;;;;;;;:24;;:32;;;;:::i;:::-;5389:9;:20;5399:9;5389:20;;;;;;;;;;;;;;;:55;;;;5476:9;5459:35;;5468:6;5459:35;;;5487:6;5459:35;;;;;;;;;;;;;;;;;;5079:422;;;:::o;1274:179:2:-;1332:7;1364:1;1359;:6;;1351:49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1410:9;1426:1;1422;:5;1410:17;;1445:1;1438:8;;;1274:179;;;;:::o;834:176::-;892:7;911:9;927:1;923;:5;911:17;;951:1;946;:6;;938:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1002:1;995:8;;;834:176;;;;:::o",
+ "source": "pragma solidity ^0.5.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/ERC20.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol\";\n\ncontract TestToken is ERC20, ERC20Detailed {\n constructor(string memory name, string memory symbol, uint8 decimals, uint256 initialSupply) ERC20Detailed(name, symbol, decimals) public {\n _mint(msg.sender, initialSupply);\n }\n}",
+ "sourcePath": "/Users/thomas/Code/client/balancer/external-contracts/contracts/TestToken.sol",
+ "ast": {
+ "absolutePath": "/Users/thomas/Code/client/balancer/external-contracts/contracts/TestToken.sol",
+ "exportedSymbols": {
+ "TestToken": [
+ 88
+ ]
+ },
+ "id": 89,
+ "nodeType": "SourceUnit",
+ "nodes": [
+ {
+ "id": 58,
+ "literals": [
+ "solidity",
+ "^",
+ "0.5",
+ ".0"
+ ],
+ "nodeType": "PragmaDirective",
+ "src": "0:23:1"
+ },
+ {
+ "absolutePath": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
+ "file": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
+ "id": 59,
+ "nodeType": "ImportDirective",
+ "scope": 89,
+ "sourceUnit": 619,
+ "src": "25:55:1",
+ "symbolAliases": [],
+ "unitAlias": ""
+ },
+ {
+ "absolutePath": "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol",
+ "file": "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol",
+ "id": 60,
+ "nodeType": "ImportDirective",
+ "scope": 89,
+ "sourceUnit": 677,
+ "src": "81:63:1",
+ "symbolAliases": [],
+ "unitAlias": ""
+ },
+ {
+ "baseContracts": [
+ {
+ "arguments": null,
+ "baseName": {
+ "contractScope": null,
+ "id": 61,
+ "name": "ERC20",
+ "nodeType": "UserDefinedTypeName",
+ "referencedDeclaration": 618,
+ "src": "168:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_contract$_ERC20_$618",
+ "typeString": "contract ERC20"
+ }
+ },
+ "id": 62,
+ "nodeType": "InheritanceSpecifier",
+ "src": "168:5:1"
+ },
+ {
+ "arguments": null,
+ "baseName": {
+ "contractScope": null,
+ "id": 63,
+ "name": "ERC20Detailed",
+ "nodeType": "UserDefinedTypeName",
+ "referencedDeclaration": 676,
+ "src": "175:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_contract$_ERC20Detailed_$676",
+ "typeString": "contract ERC20Detailed"
+ }
+ },
+ "id": 64,
+ "nodeType": "InheritanceSpecifier",
+ "src": "175:13:1"
+ }
+ ],
+ "contractDependencies": [
+ 618,
+ 676,
+ 745
+ ],
+ "contractKind": "contract",
+ "documentation": null,
+ "fullyImplemented": true,
+ "id": 88,
+ "linearizedBaseContracts": [
+ 88,
+ 676,
+ 618,
+ 745
+ ],
+ "name": "TestToken",
+ "nodeType": "ContractDefinition",
+ "nodes": [
+ {
+ "body": {
+ "id": 86,
+ "nodeType": "Block",
+ "src": "333:49:1",
+ "statements": [
+ {
+ "expression": {
+ "argumentTypes": null,
+ "arguments": [
+ {
+ "argumentTypes": null,
+ "expression": {
+ "argumentTypes": null,
+ "id": 81,
+ "name": "msg",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 760,
+ "src": "349:3:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_magic_message",
+ "typeString": "msg"
+ }
+ },
+ "id": 82,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "memberName": "sender",
+ "nodeType": "MemberAccess",
+ "referencedDeclaration": null,
+ "src": "349:10:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_address_payable",
+ "typeString": "address payable"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 83,
+ "name": "initialSupply",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 72,
+ "src": "361:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ }
+ ],
+ "expression": {
+ "argumentTypes": [
+ {
+ "typeIdentifier": "t_address_payable",
+ "typeString": "address payable"
+ },
+ {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ ],
+ "id": 80,
+ "name": "_mint",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 504,
+ "src": "343:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$__$",
+ "typeString": "function (address,uint256)"
+ }
+ },
+ "id": 84,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "kind": "functionCall",
+ "lValueRequested": false,
+ "names": [],
+ "nodeType": "FunctionCall",
+ "src": "343:32:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_tuple$__$",
+ "typeString": "tuple()"
+ }
+ },
+ "id": 85,
+ "nodeType": "ExpressionStatement",
+ "src": "343:32:1"
+ }
+ ]
+ },
+ "documentation": null,
+ "id": 87,
+ "implemented": true,
+ "kind": "constructor",
+ "modifiers": [
+ {
+ "arguments": [
+ {
+ "argumentTypes": null,
+ "id": 75,
+ "name": "name",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 66,
+ "src": "302:4:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string memory"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 76,
+ "name": "symbol",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 68,
+ "src": "308:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string memory"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 77,
+ "name": "decimals",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 70,
+ "src": "316:8:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ }
+ }
+ ],
+ "id": 78,
+ "modifierName": {
+ "argumentTypes": null,
+ "id": 74,
+ "name": "ERC20Detailed",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 676,
+ "src": "288:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_type$_t_contract$_ERC20Detailed_$676_$",
+ "typeString": "type(contract ERC20Detailed)"
+ }
+ },
+ "nodeType": "ModifierInvocation",
+ "src": "288:37:1"
+ }
+ ],
+ "name": "",
+ "nodeType": "FunctionDefinition",
+ "parameters": {
+ "id": 73,
+ "nodeType": "ParameterList",
+ "parameters": [
+ {
+ "constant": false,
+ "id": 66,
+ "name": "name",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "207:18:1",
+ "stateVariable": false,
+ "storageLocation": "memory",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string"
+ },
+ "typeName": {
+ "id": 65,
+ "name": "string",
+ "nodeType": "ElementaryTypeName",
+ "src": "207:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_storage_ptr",
+ "typeString": "string"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 68,
+ "name": "symbol",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "227:20:1",
+ "stateVariable": false,
+ "storageLocation": "memory",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string"
+ },
+ "typeName": {
+ "id": 67,
+ "name": "string",
+ "nodeType": "ElementaryTypeName",
+ "src": "227:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_storage_ptr",
+ "typeString": "string"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 70,
+ "name": "decimals",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "249:14:1",
+ "stateVariable": false,
+ "storageLocation": "default",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ },
+ "typeName": {
+ "id": 69,
+ "name": "uint8",
+ "nodeType": "ElementaryTypeName",
+ "src": "249:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 72,
+ "name": "initialSupply",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "265:21:1",
+ "stateVariable": false,
+ "storageLocation": "default",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ },
+ "typeName": {
+ "id": 71,
+ "name": "uint256",
+ "nodeType": "ElementaryTypeName",
+ "src": "265:7:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ }
+ ],
+ "src": "206:81:1"
+ },
+ "returnParameters": {
+ "id": 79,
+ "nodeType": "ParameterList",
+ "parameters": [],
+ "src": "333:0:1"
+ },
+ "scope": 88,
+ "src": "195:187:1",
+ "stateMutability": "nonpayable",
+ "superFunction": null,
+ "visibility": "public"
+ }
+ ],
+ "scope": 89,
+ "src": "146:238:1"
+ }
+ ],
+ "src": "0:384:1"
+ },
+ "legacyAST": {
+ "absolutePath": "/Users/thomas/Code/client/balancer/external-contracts/contracts/TestToken.sol",
+ "exportedSymbols": {
+ "TestToken": [
+ 88
+ ]
+ },
+ "id": 89,
+ "nodeType": "SourceUnit",
+ "nodes": [
+ {
+ "id": 58,
+ "literals": [
+ "solidity",
+ "^",
+ "0.5",
+ ".0"
+ ],
+ "nodeType": "PragmaDirective",
+ "src": "0:23:1"
+ },
+ {
+ "absolutePath": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
+ "file": "@openzeppelin/contracts/token/ERC20/ERC20.sol",
+ "id": 59,
+ "nodeType": "ImportDirective",
+ "scope": 89,
+ "sourceUnit": 619,
+ "src": "25:55:1",
+ "symbolAliases": [],
+ "unitAlias": ""
+ },
+ {
+ "absolutePath": "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol",
+ "file": "@openzeppelin/contracts/token/ERC20/ERC20Detailed.sol",
+ "id": 60,
+ "nodeType": "ImportDirective",
+ "scope": 89,
+ "sourceUnit": 677,
+ "src": "81:63:1",
+ "symbolAliases": [],
+ "unitAlias": ""
+ },
+ {
+ "baseContracts": [
+ {
+ "arguments": null,
+ "baseName": {
+ "contractScope": null,
+ "id": 61,
+ "name": "ERC20",
+ "nodeType": "UserDefinedTypeName",
+ "referencedDeclaration": 618,
+ "src": "168:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_contract$_ERC20_$618",
+ "typeString": "contract ERC20"
+ }
+ },
+ "id": 62,
+ "nodeType": "InheritanceSpecifier",
+ "src": "168:5:1"
+ },
+ {
+ "arguments": null,
+ "baseName": {
+ "contractScope": null,
+ "id": 63,
+ "name": "ERC20Detailed",
+ "nodeType": "UserDefinedTypeName",
+ "referencedDeclaration": 676,
+ "src": "175:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_contract$_ERC20Detailed_$676",
+ "typeString": "contract ERC20Detailed"
+ }
+ },
+ "id": 64,
+ "nodeType": "InheritanceSpecifier",
+ "src": "175:13:1"
+ }
+ ],
+ "contractDependencies": [
+ 618,
+ 676,
+ 745
+ ],
+ "contractKind": "contract",
+ "documentation": null,
+ "fullyImplemented": true,
+ "id": 88,
+ "linearizedBaseContracts": [
+ 88,
+ 676,
+ 618,
+ 745
+ ],
+ "name": "TestToken",
+ "nodeType": "ContractDefinition",
+ "nodes": [
+ {
+ "body": {
+ "id": 86,
+ "nodeType": "Block",
+ "src": "333:49:1",
+ "statements": [
+ {
+ "expression": {
+ "argumentTypes": null,
+ "arguments": [
+ {
+ "argumentTypes": null,
+ "expression": {
+ "argumentTypes": null,
+ "id": 81,
+ "name": "msg",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 760,
+ "src": "349:3:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_magic_message",
+ "typeString": "msg"
+ }
+ },
+ "id": 82,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "lValueRequested": false,
+ "memberName": "sender",
+ "nodeType": "MemberAccess",
+ "referencedDeclaration": null,
+ "src": "349:10:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_address_payable",
+ "typeString": "address payable"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 83,
+ "name": "initialSupply",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 72,
+ "src": "361:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ }
+ ],
+ "expression": {
+ "argumentTypes": [
+ {
+ "typeIdentifier": "t_address_payable",
+ "typeString": "address payable"
+ },
+ {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ ],
+ "id": 80,
+ "name": "_mint",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 504,
+ "src": "343:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_function_internal_nonpayable$_t_address_$_t_uint256_$returns$__$",
+ "typeString": "function (address,uint256)"
+ }
+ },
+ "id": 84,
+ "isConstant": false,
+ "isLValue": false,
+ "isPure": false,
+ "kind": "functionCall",
+ "lValueRequested": false,
+ "names": [],
+ "nodeType": "FunctionCall",
+ "src": "343:32:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_tuple$__$",
+ "typeString": "tuple()"
+ }
+ },
+ "id": 85,
+ "nodeType": "ExpressionStatement",
+ "src": "343:32:1"
+ }
+ ]
+ },
+ "documentation": null,
+ "id": 87,
+ "implemented": true,
+ "kind": "constructor",
+ "modifiers": [
+ {
+ "arguments": [
+ {
+ "argumentTypes": null,
+ "id": 75,
+ "name": "name",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 66,
+ "src": "302:4:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string memory"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 76,
+ "name": "symbol",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 68,
+ "src": "308:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string memory"
+ }
+ },
+ {
+ "argumentTypes": null,
+ "id": 77,
+ "name": "decimals",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 70,
+ "src": "316:8:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ }
+ }
+ ],
+ "id": 78,
+ "modifierName": {
+ "argumentTypes": null,
+ "id": 74,
+ "name": "ERC20Detailed",
+ "nodeType": "Identifier",
+ "overloadedDeclarations": [],
+ "referencedDeclaration": 676,
+ "src": "288:13:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_type$_t_contract$_ERC20Detailed_$676_$",
+ "typeString": "type(contract ERC20Detailed)"
+ }
+ },
+ "nodeType": "ModifierInvocation",
+ "src": "288:37:1"
+ }
+ ],
+ "name": "",
+ "nodeType": "FunctionDefinition",
+ "parameters": {
+ "id": 73,
+ "nodeType": "ParameterList",
+ "parameters": [
+ {
+ "constant": false,
+ "id": 66,
+ "name": "name",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "207:18:1",
+ "stateVariable": false,
+ "storageLocation": "memory",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string"
+ },
+ "typeName": {
+ "id": 65,
+ "name": "string",
+ "nodeType": "ElementaryTypeName",
+ "src": "207:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_storage_ptr",
+ "typeString": "string"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 68,
+ "name": "symbol",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "227:20:1",
+ "stateVariable": false,
+ "storageLocation": "memory",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_memory_ptr",
+ "typeString": "string"
+ },
+ "typeName": {
+ "id": 67,
+ "name": "string",
+ "nodeType": "ElementaryTypeName",
+ "src": "227:6:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_string_storage_ptr",
+ "typeString": "string"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 70,
+ "name": "decimals",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "249:14:1",
+ "stateVariable": false,
+ "storageLocation": "default",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ },
+ "typeName": {
+ "id": 69,
+ "name": "uint8",
+ "nodeType": "ElementaryTypeName",
+ "src": "249:5:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint8",
+ "typeString": "uint8"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ },
+ {
+ "constant": false,
+ "id": 72,
+ "name": "initialSupply",
+ "nodeType": "VariableDeclaration",
+ "scope": 87,
+ "src": "265:21:1",
+ "stateVariable": false,
+ "storageLocation": "default",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ },
+ "typeName": {
+ "id": 71,
+ "name": "uint256",
+ "nodeType": "ElementaryTypeName",
+ "src": "265:7:1",
+ "typeDescriptions": {
+ "typeIdentifier": "t_uint256",
+ "typeString": "uint256"
+ }
+ },
+ "value": null,
+ "visibility": "internal"
+ }
+ ],
+ "src": "206:81:1"
+ },
+ "returnParameters": {
+ "id": 79,
+ "nodeType": "ParameterList",
+ "parameters": [],
+ "src": "333:0:1"
+ },
+ "scope": 88,
+ "src": "195:187:1",
+ "stateMutability": "nonpayable",
+ "superFunction": null,
+ "visibility": "public"
+ }
+ ],
+ "scope": 89,
+ "src": "146:238:1"
+ }
+ ],
+ "src": "0:384:1"
+ },
+ "compiler": {
+ "name": "solc",
+ "version": "0.5.11+commit.c082d0b4.Emscripten.clang"
+ },
+ "networks": {},
+ "schemaVersion": "3.0.11",
+ "updatedAt": "2019-09-21T08:47:25.358Z",
+ "devdoc": {
+ "methods": {
+ "allowance(address,address)": {
+ "details": "See `IERC20.allowance`."
+ },
+ "approve(address,uint256)": {
+ "details": "See `IERC20.approve`. * Requirements: * - `spender` cannot be the zero address."
+ },
+ "balanceOf(address)": {
+ "details": "See `IERC20.balanceOf`."
+ },
+ "decimals()": {
+ "details": "Returns the number of decimals used to get its user representation. For example, if `decimals` equals `2`, a balance of `505` tokens should be displayed to a user as `5,05` (`505 / 10 ** 2`). * Tokens usually opt for a value of 18, imitating the relationship between Ether and Wei. * > Note that this information is only used for _display_ purposes: it in no way affects any of the arithmetic of the contract, including `IERC20.balanceOf` and `IERC20.transfer`."
+ },
+ "decreaseAllowance(address,uint256)": {
+ "details": "Atomically decreases the allowance granted to `spender` by the caller. * This is an alternative to `approve` that can be used as a mitigation for problems described in `IERC20.approve`. * Emits an `Approval` event indicating the updated allowance. * Requirements: * - `spender` cannot be the zero address. - `spender` must have allowance for the caller of at least `subtractedValue`."
+ },
+ "increaseAllowance(address,uint256)": {
+ "details": "Atomically increases the allowance granted to `spender` by the caller. * This is an alternative to `approve` that can be used as a mitigation for problems described in `IERC20.approve`. * Emits an `Approval` event indicating the updated allowance. * Requirements: * - `spender` cannot be the zero address."
+ },
+ "name()": {
+ "details": "Returns the name of the token."
+ },
+ "symbol()": {
+ "details": "Returns the symbol of the token, usually a shorter version of the name."
+ },
+ "totalSupply()": {
+ "details": "See `IERC20.totalSupply`."
+ },
+ "transfer(address,uint256)": {
+ "details": "See `IERC20.transfer`. * Requirements: * - `recipient` cannot be the zero address. - the caller must have a balance of at least `amount`."
+ },
+ "transferFrom(address,address,uint256)": {
+ "details": "See `IERC20.transferFrom`. * Emits an `Approval` event indicating the updated allowance. This is not required by the EIP. See the note at the beginning of `ERC20`; * Requirements: - `sender` and `recipient` cannot be the zero address. - `sender` must have a balance of at least `value`. - the caller must have allowance for `sender`'s tokens of at least `amount`."
+ }
+ }
+ },
+ "userdoc": {
+ "methods": {}
+ }
+}
diff --git a/src/helpers/abi/index.ts b/src/helpers/abi/index.ts
new file mode 100644
index 0000000..28abc70
--- /dev/null
+++ b/src/helpers/abi/index.ts
@@ -0,0 +1,10 @@
+const requireFile = require.context('./', true, /[\w-]+\.json$/);
+
+export default Object.fromEntries(
+ requireFile
+ .keys()
+ .map(fileName => [
+ fileName.replace('./', '').replace('.json', ''),
+ requireFile(fileName).abi
+ ])
+);
diff --git a/src/helpers/client.ts b/src/helpers/client.ts
new file mode 100644
index 0000000..6d07b2d
--- /dev/null
+++ b/src/helpers/client.ts
@@ -0,0 +1,28 @@
+class Client {
+ request(command, body?) {
+ const url = `${process.env.VUE_APP_HUB_URL}/api/${command}`;
+ let init;
+ if (body) {
+ init = {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(body)
+ };
+ }
+ return new Promise((resolve, reject) => {
+ fetch(url, init)
+ .then(res => {
+ if (res.ok) return resolve(res.json());
+ throw res;
+ })
+ .catch(e => e.json().then(json => reject(json)));
+ });
+ }
+}
+
+const client = new Client();
+
+export default client;
diff --git a/src/helpers/config.ts b/src/helpers/config.ts
new file mode 100644
index 0000000..ff5edf2
--- /dev/null
+++ b/src/helpers/config.ts
@@ -0,0 +1,8 @@
+import config from '@/config.json';
+
+let id = 'master';
+const domainName = window.location.hostname;
+if (domainName.includes('localhost:')) id = 'local';
+if (domainName === 'makiswap-dev.thinkincoin.com') id = 'develop';
+
+export default config[id];
diff --git a/src/helpers/ipfs.ts b/src/helpers/ipfs.ts
new file mode 100644
index 0000000..78bb98e
--- /dev/null
+++ b/src/helpers/ipfs.ts
@@ -0,0 +1,10 @@
+class Client {
+ get(ipfsHash) {
+ const url = `https://${process.env.VUE_APP_IPFS_NODE}/ipfs/${ipfsHash}`;
+ return fetch(url).then(res => res.json());
+ }
+}
+
+const client = new Client();
+
+export default client;
diff --git a/src/helpers/lock.ts b/src/helpers/lock.ts
new file mode 100644
index 0000000..c699928
--- /dev/null
+++ b/src/helpers/lock.ts
@@ -0,0 +1,17 @@
+import { Lock } from '@bonustrack/lock/dist/lock.cjs';
+import config from '@/helpers/config';
+import injected from '@bonustrack/lock/connectors/injected';
+import portis from '@bonustrack/lock/connectors/portis';
+import magic from '@bonustrack/lock/connectors/fortmatic';
+
+const connectors = { injected, portis, magic };
+const lock = new Lock();
+Object.entries(config.connectors).forEach((connector: any) => {
+ lock.addConnector({
+ key: connector[0],
+ connector: connectors[connector[0]],
+ options: connector[1].options
+ });
+});
+
+export default lock;
diff --git a/src/helpers/queries.json b/src/helpers/queries.json
new file mode 100644
index 0000000..6a01d51
--- /dev/null
+++ b/src/helpers/queries.json
@@ -0,0 +1,25 @@
+{
+ "getVotingPowers": {
+ "poolShares": {
+ "__args": {
+ "first": 1000,
+ "orderBy": "balance",
+ "orderDirection": "desc",
+ "where": {
+ "balance_gt": 0
+ }
+ },
+ "userAddress": {
+ "id": true
+ },
+ "balance": true,
+ "poolId": {
+ "totalShares": true,
+ "tokens": {
+ "id": true,
+ "balance": true
+ }
+ }
+ }
+ }
+}
diff --git a/src/helpers/subgraph.ts b/src/helpers/subgraph.ts
new file mode 100644
index 0000000..26d340b
--- /dev/null
+++ b/src/helpers/subgraph.ts
@@ -0,0 +1,24 @@
+import merge from 'lodash/merge';
+import { clone } from '@/helpers/utils';
+import { jsonToGraphQLQuery } from 'json-to-graphql-query';
+import config from '@/helpers/config';
+import queries from '@/helpers/queries.json';
+
+// @ts-ignore
+queries.custom = {};
+
+export async function request(key: string | null, params: any = {}) {
+ // @ts-ignore
+ let query = merge(clone(queries[key]), clone(params));
+ query = jsonToGraphQLQuery({ query });
+ const res = await fetch(config.subgraphUrl, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ query })
+ });
+ const { data } = await res.json();
+ return data || {};
+}
diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts
new file mode 100644
index 0000000..f67dedd
--- /dev/null
+++ b/src/helpers/utils.ts
@@ -0,0 +1,62 @@
+import config from '@/helpers/config';
+import pkg from '@/../package.json';
+
+export function shorten(str = '') {
+ return `${str.slice(0, 6)}...${str.slice(str.length - 4)}`;
+}
+
+export function jsonParse(input, fallback?) {
+ if (typeof input !== 'string') {
+ return fallback || {};
+ }
+ try {
+ return JSON.parse(input);
+ } catch (err) {
+ return fallback || {};
+ }
+}
+
+export function clone(item) {
+ return JSON.parse(JSON.stringify(item));
+}
+
+export function etherscanLink(str: string, type = 'address'): string {
+ const network = config.network === 'homestead' ? '' : `${config.network}.`;
+ return `https://${network}etherscan.io/${type}/${str}`;
+}
+
+export function lsSet(key: string, value: any) {
+ return localStorage.setItem(`${pkg.name}.${key}`, JSON.stringify(value));
+}
+
+export function lsGet(key: string) {
+ const item = localStorage.getItem(`${pkg.name}.${key}`);
+ return jsonParse(item, '');
+}
+
+export function lsRemove(key: string) {
+ return localStorage.removeItem(`${pkg.name}.${key}`);
+}
+
+export function formatProposal(proposal) {
+ proposal.msg = jsonParse(proposal.msg, proposal.msg);
+
+ // v0.1.0
+ if (proposal.msg.version === '0.1.0') {
+ proposal.msg.payload.start = 1595088000;
+ proposal.msg.payload.end = 1595174400;
+ proposal.msg.payload.snapshot = 10484400;
+ proposal.bpt_voting_disabled = '1';
+ }
+
+ return proposal;
+}
+
+export function formatProposals(proposals) {
+ return Object.fromEntries(
+ Object.entries(proposals).map(proposal => [
+ proposal[0],
+ formatProposal(proposal[1])
+ ])
+ );
+}
diff --git a/src/helpers/ws.ts b/src/helpers/ws.ts
new file mode 100644
index 0000000..044a705
--- /dev/null
+++ b/src/helpers/ws.ts
@@ -0,0 +1,6 @@
+import { WebSocketProvider } from '@ethersproject/providers';
+
+const wsUrl: any = process.env.VUE_APP_WS_URL;
+const wsProvider = new WebSocketProvider(wsUrl);
+
+export default wsProvider;
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..9e9b2b1
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,55 @@
+import Vue from 'vue';
+import VueI18n from 'vue-i18n';
+
+Vue.use(VueI18n);
+
+const locale = 'en-US';
+
+export default new VueI18n({
+ locale,
+ messages: {
+ en: {
+ messages: {
+ EMPTY_STATE: 'No results found'
+ }
+ }
+ },
+ numberFormats: {
+ en: {
+ currency: {
+ style: 'currency',
+ currency: 'USD',
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 0
+ },
+ price: {
+ style: 'currency',
+ currency: 'USD',
+ minimumFractionDigits: 2,
+ maximumFractionDigits: 6
+ },
+ percent: {
+ style: 'percent',
+ minimumFractionDigits: 0,
+ maximumFractionDigits: 2
+ }
+ }
+ },
+ dateTimeFormats: {
+ 'en-US': {
+ short: {
+ year: 'numeric',
+ month: 'short',
+ day: 'numeric',
+ hour: 'numeric'
+ },
+ long: {
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric',
+ hour: 'numeric',
+ minute: 'numeric'
+ }
+ }
+ }
+});
diff --git a/src/main.ts b/src/main.ts
new file mode 100644
index 0000000..816ec8e
--- /dev/null
+++ b/src/main.ts
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import autofocus from 'vue-autofocus-directive';
+import infiniteScroll from 'vue-infinite-scroll';
+import TextareaAutosize from 'vue-textarea-autosize';
+import Jazzicon from 'vue-jazzicon';
+import upperFirst from 'lodash/upperFirst';
+import camelCase from 'lodash/camelCase';
+import App from '@/App.vue';
+import router from '@/router';
+import store from '@/store';
+import mixins from '@/mixins';
+import i18n from '@/i18n';
+import '@/style.scss';
+
+Vue.use(infiniteScroll);
+Vue.use(TextareaAutosize);
+
+const requireComponent = require.context('@/components', true, /[\w-]+\.vue$/);
+requireComponent.keys().forEach(fileName => {
+ const componentConfig = requireComponent(fileName);
+ const componentName = upperFirst(
+ camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''))
+ );
+ Vue.component(componentName, componentConfig.default || componentConfig);
+});
+
+Vue.component('jazzicon', Jazzicon);
+Vue.mixin(mixins);
+Vue.directive('autofocus', autofocus);
+
+Vue.config.productionTip = false;
+
+new Vue({
+ i18n,
+ router,
+ store,
+ render: h => h(App)
+}).$mount('#app');
diff --git a/src/mixins.ts b/src/mixins.ts
new file mode 100644
index 0000000..7ab8758
--- /dev/null
+++ b/src/mixins.ts
@@ -0,0 +1,33 @@
+import { mapState } from 'vuex';
+import numeral from 'numeral';
+import store from '@/store';
+import config from '@/helpers/config';
+import { shorten, etherscanLink } from '@/helpers/utils';
+
+// @ts-ignore
+const modules = Object.entries(store.state).map(module => module[0]);
+
+export default {
+ data() {
+ return {
+ config
+ };
+ },
+ computed: {
+ ...mapState(modules)
+ },
+ methods: {
+ _numeral(number, format = '(0.[00]a)') {
+ return numeral(number).format(format);
+ },
+ _shorten(str: string): string {
+ return shorten(str);
+ },
+ _ipfsUrl(ipfsHash: string): string {
+ return `https://${process.env.VUE_APP_IPFS_NODE}/ipfs/${ipfsHash}`;
+ },
+ _etherscanLink(str: string, type: string): string {
+ return etherscanLink(str, type);
+ }
+ }
+};
diff --git a/src/namespaces.json b/src/namespaces.json
new file mode 100644
index 0000000..d8e0959
--- /dev/null
+++ b/src/namespaces.json
@@ -0,0 +1,27 @@
+{
+ "SOY": {
+ "key": "soy",
+ "symbol": "SOY",
+ "name": "SoyBar Token",
+ "address": "0x993163cad35162fb579d7b64e6695cb076ef5064",
+ "token": "0x993163cad35162fb579d7b64e6695cb076ef5064",
+ "image": "0x993163cad35162fb579d7b64e6695cb076ef5064",
+ "coreDevs": [
+ "0x07Dee7d1828554a59C8B5E1466Cba8C0B87daF10"
+ ],
+ "min": 100,
+ "max": 1000
+ },
+ "maki": {
+ "key": "maki",
+ "symbol": "MAKI",
+ "name": "MakiSwap Token",
+ "address": "0x89d45ccdae300e9a2a725eec8ec76dda571d6e2b",
+ "token": "0x89d45ccdae300e9a2a725eec8ec76dda571d6e2b",
+ "image": "0x89d45ccdae300e9a2a725eec8ec76dda571d6e2b",
+ "coreDevs": [
+ ],
+ "min": 10,
+ "max": 100
+ }
+}
diff --git a/src/router.ts b/src/router.ts
new file mode 100644
index 0000000..eb0b5bd
--- /dev/null
+++ b/src/router.ts
@@ -0,0 +1,23 @@
+import Vue from 'vue';
+import VueRouter, { RouteConfig } from 'vue-router';
+import Home from '@/views/Home.vue';
+import Proposals from '@/views/Proposals.vue';
+import Proposal from '@/views/Proposal.vue';
+import Create from '@/views/Create.vue';
+
+Vue.use(VueRouter);
+
+const routes: Array = [
+ { path: '/:key/proposal/:id', name: 'proposal', component: Proposal },
+ { path: '/:key/create', name: 'create', component: Create },
+ { path: '/:key', name: 'proposals', component: Proposals },
+ { path: '/', name: 'home', component: Home },
+ { path: '/*', name: 'error-404', beforeEnter: (to, from, next) => next('/') }
+];
+
+const router = new VueRouter({
+ mode: 'hash',
+ routes
+});
+
+export default router;
diff --git a/src/shims-tsx.d.ts b/src/shims-tsx.d.ts
new file mode 100644
index 0000000..3b88b58
--- /dev/null
+++ b/src/shims-tsx.d.ts
@@ -0,0 +1,13 @@
+import Vue, { VNode } from 'vue';
+
+declare global {
+ namespace JSX {
+ // tslint:disable no-empty-interface
+ interface Element extends VNode {}
+ // tslint:disable no-empty-interface
+ interface ElementClass extends Vue {}
+ interface IntrinsicElements {
+ [elem: string]: any;
+ }
+ }
+}
diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts
new file mode 100644
index 0000000..8f6f410
--- /dev/null
+++ b/src/shims-vue.d.ts
@@ -0,0 +1,4 @@
+declare module '*.vue' {
+ import Vue from 'vue';
+ export default Vue;
+}
diff --git a/src/store/index.ts b/src/store/index.ts
new file mode 100644
index 0000000..28d75aa
--- /dev/null
+++ b/src/store/index.ts
@@ -0,0 +1,12 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import modules from '@/store/modules';
+
+Vue.use(Vuex);
+
+const store = new Vuex.Store({
+ modules,
+ strict: process.env.NODE_ENV !== 'production'
+});
+
+export default store;
diff --git a/src/store/modules/gov.ts b/src/store/modules/gov.ts
new file mode 100644
index 0000000..2ac712a
--- /dev/null
+++ b/src/store/modules/gov.ts
@@ -0,0 +1,252 @@
+import { Contract } from '@ethersproject/contracts';
+import { Interface } from '@ethersproject/abi';
+import { formatUnits } from '@ethersproject/units';
+import client from '@/helpers/client';
+import ipfs from '@/helpers/ipfs';
+import config from '@/helpers/config';
+import abi from '@/helpers/abi';
+import wsProvider from '@/helpers/ws';
+import { formatProposal, formatProposals } from '@/helpers/utils';
+import { version } from '@/../package.json';
+
+const mutations = {
+ SEND_REQUEST() {
+ console.debug('SEND_REQUEST');
+ },
+ SEND_SUCCESS() {
+ console.debug('SEND_SUCCESS');
+ },
+ SEND_FAILURE(_state, payload) {
+ console.debug('SEND_FAILURE', payload);
+ },
+ GET_PROPOSALS_REQUEST() {
+ console.debug('GET_PROPOSALS_REQUEST');
+ },
+ GET_PROPOSALS_SUCCESS() {
+ console.debug('GET_PROPOSALS_SUCCESS');
+ },
+ GET_PROPOSALS_FAILURE(_state, payload) {
+ console.debug('GET_PROPOSALS_FAILURE', payload);
+ },
+ GET_PROPOSAL_REQUEST() {
+ console.debug('GET_PROPOSAL_REQUEST');
+ },
+ GET_PROPOSAL_SUCCESS() {
+ console.debug('GET_PROPOSAL_SUCCESS');
+ },
+ GET_PROPOSAL_FAILURE(_state, payload) {
+ console.debug('GET_PROPOSAL_FAILURE', payload);
+ },
+ GET_VOTERS_BALANCES_REQUEST() {
+ console.debug('GET_VOTERS_BALANCES_REQUEST');
+ },
+ GET_VOTERS_BALANCES_SUCCESS() {
+ console.debug('GET_VOTERS_BALANCES_SUCCESS');
+ },
+ GET_VOTERS_BALANCES_FAILURE(_state, payload) {
+ console.debug('GET_VOTERS_BALANCES_FAILURE', payload);
+ },
+ GET_POWER_REQUEST() {
+ console.debug('GET_POWER_REQUEST');
+ },
+ GET_POWER_SUCCESS() {
+ console.debug('GET_POWER_SUCCESS');
+ },
+ GET_POWER_FAILURE(_state, payload) {
+ console.debug('GET_POWER_FAILURE', payload);
+ }
+};
+
+const actions = {
+ send: async ({ commit, dispatch, rootState }, { token, type, payload }) => {
+ commit('SEND_REQUEST');
+ try {
+ const msg: any = {
+ address: rootState.web3.account,
+ msg: JSON.stringify({
+ version,
+ timestamp: (Date.now() / 1e3).toFixed(),
+ token,
+ type,
+ payload
+ })
+ };
+ msg.sig = await dispatch('signMessage', msg.msg);
+ const result = await client.request('message', msg);
+ commit('SEND_SUCCESS');
+ dispatch('notify', ['green', `Your ${type} is in!`]);
+ return result;
+ } catch (e) {
+ commit('SEND_FAILURE', e);
+ const errorMessage =
+ e && e.error_description
+ ? `Oops, ${e.error_description}`
+ : 'Oops, something went wrong!';
+ dispatch('notify', ['red', errorMessage]);
+ return;
+ }
+ },
+ getProposals: async ({ commit, dispatch, rootState }, payload) => {
+ const { decimals } = rootState.web3.namespaces[payload];
+ commit('GET_PROPOSALS_REQUEST');
+ try {
+ let proposals: any = await client.request(`${payload}/proposals`);
+ if (proposals) {
+ let balances = await dispatch('multicall', {
+ name: 'TestToken',
+ calls: Object.values(proposals).map((proposal: any) => {
+ return [proposal.msg.token, 'balanceOf', [proposal.address]];
+ })
+ });
+ balances = balances.map(balance =>
+ parseFloat(formatUnits(balance.toString(), decimals))
+ );
+ proposals = Object.fromEntries(
+ Object.entries(proposals).map((proposal: any, i) => {
+ proposal[1].balance = balances[i];
+ return [proposal[0], proposal[1]];
+ })
+ );
+ }
+ commit('GET_PROPOSALS_SUCCESS');
+ return formatProposals(proposals);
+ } catch (e) {
+ commit('GET_PROPOSALS_FAILURE', e);
+ }
+ },
+ getProposal: async ({ commit, dispatch, rootState }, payload) => {
+ commit('GET_PROPOSAL_REQUEST');
+ try {
+ const result: any = {};
+ const [proposal, votes] = await Promise.all([
+ ipfs.get(payload.id),
+ client.request(`${payload.token}/proposal/${payload.id}`)
+ ]);
+ result.proposal = formatProposal(proposal);
+ result.proposal.ipfsHash = payload.id;
+ result.votes = votes;
+ const bptDisabled = !!result.proposal.bpt_voting_disabled;
+ const { snapshot } = result.proposal.msg.payload;
+ const blockTag =
+ snapshot > rootState.web3.blockNumber ? 'latest' : parseInt(snapshot);
+ const votersBalances = await dispatch('getVotersBalances', {
+ token: payload.token,
+ addresses: Object.values(result.votes).map((vote: any) => vote.address),
+ blockTag
+ });
+ // @ts-ignore
+ const addresses = Object.keys(votes);
+ let votingPowers = {};
+ if (!bptDisabled) {
+ votingPowers = await dispatch('getVotingPowers', {
+ token: result.proposal.msg.token,
+ blockTag,
+ addresses
+ });
+ }
+ result.votes = Object.fromEntries(
+ Object.entries(result.votes)
+ .map((vote: any) => {
+ const bptBalance = bptDisabled ? 0 : votingPowers[vote[1].address];
+ vote[1].balance = votersBalances[vote[1].address] + bptBalance;
+ vote[1].bptBalance = bptBalance;
+ vote[1].walletBalance = votersBalances[vote[1].address];
+ return vote;
+ })
+ .sort((a, b) => b[1].balance - a[1].balance)
+ .filter(vote => vote[1].balance > 0)
+ );
+ result.results = {
+ totalVotes: result.proposal.msg.payload.choices.map(
+ (choice, i) =>
+ Object.values(result.votes).filter(
+ (vote: any) => vote.msg.payload.choice === i + 1
+ ).length
+ ),
+ totalBalances: result.proposal.msg.payload.choices.map((choice, i) =>
+ Object.values(result.votes)
+ .filter((vote: any) => vote.msg.payload.choice === i + 1)
+ .reduce((a, b: any) => a + b.balance, 0)
+ ),
+ totalBptBalances: bptDisabled
+ ? 0
+ : result.proposal.msg.payload.choices.map((choice, i) =>
+ Object.values(result.votes)
+ .filter((vote: any) => vote.msg.payload.choice === i + 1)
+ .reduce((a, b: any) => a + b.bptBalance, 0)
+ ),
+ totalWalletBalances: result.proposal.msg.payload.choices.map(
+ (choice, i) =>
+ Object.values(result.votes)
+ .filter((vote: any) => vote.msg.payload.choice === i + 1)
+ .reduce((a, b: any) => a + b.walletBalance, 0)
+ ),
+ totalVotesBalances: Object.values(result.votes).reduce(
+ (a, b: any) => a + b.balance,
+ 0
+ )
+ };
+ commit('GET_PROPOSAL_SUCCESS');
+ return result;
+ } catch (e) {
+ commit('GET_PROPOSAL_FAILURE', e);
+ }
+ },
+ getVotersBalances: async (
+ { commit, rootState },
+ { token, addresses, blockTag }
+ ) => {
+ commit('GET_VOTERS_BALANCES_REQUEST');
+ const multi = new Contract(config.multicall, abi['Multicall'], wsProvider);
+ const calls = [];
+ const testToken = new Interface(abi.TestToken);
+ addresses.forEach(address => {
+ // @ts-ignore
+ calls.push([token, testToken.encodeFunctionData('balanceOf', [address])]);
+ });
+ const balances: any = {};
+ try {
+ const { decimals } = rootState.web3.namespaces[token];
+ const [, response] = await multi.aggregate(calls, { blockTag });
+ response.forEach((value, i) => {
+ balances[addresses[i]] = parseFloat(
+ formatUnits(value.toString(), decimals)
+ );
+ });
+ commit('GET_VOTERS_BALANCES_SUCCESS');
+ return balances;
+ } catch (e) {
+ commit('GET_VOTERS_BALANCES_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ getPower: async (
+ { commit, dispatch, rootState },
+ { token, address, snapshot }
+ ) => {
+ commit('GET_POWER_REQUEST');
+ const blockTag =
+ snapshot > rootState.web3.blockNumber ? 'latest' : parseInt(snapshot);
+ try {
+ const bpts = await dispatch('getVotingPowersByPools', {
+ blockTag,
+ token,
+ addresses: [address]
+ });
+ const bpt = Object.values(bpts[address]).reduce(
+ (a: any, b: any) => a + b,
+ 0
+ );
+ const base = await dispatch('getBalance', { blockTag, token });
+ commit('GET_POWER_SUCCESS');
+ return { base, bpt, total: base + bpt };
+ } catch (e) {
+ commit('GET_POWER_FAILURE', e);
+ }
+ }
+};
+
+export default {
+ mutations,
+ actions
+};
diff --git a/src/store/modules/index.ts b/src/store/modules/index.ts
new file mode 100644
index 0000000..0c2194c
--- /dev/null
+++ b/src/store/modules/index.ts
@@ -0,0 +1,12 @@
+import camelCase from 'lodash/camelCase';
+
+const requireModule = require.context('.', false, /\.ts$/);
+const modules = {};
+
+requireModule.keys().forEach(fileName => {
+ if (fileName === './index.ts') return;
+ const moduleName = camelCase(fileName.replace(/(\.\/|\.ts)/g, ''));
+ modules[moduleName] = requireModule(fileName).default;
+});
+
+export default modules;
diff --git a/src/store/modules/notifications.ts b/src/store/modules/notifications.ts
new file mode 100644
index 0000000..39efa71
--- /dev/null
+++ b/src/store/modules/notifications.ts
@@ -0,0 +1,23 @@
+const state = {
+ items: []
+};
+
+const mutations = {
+ notify(_state, payload) {
+ _state.items.push({ ...payload, timestamp: Date.now() });
+ }
+};
+
+const actions = {
+ notify({ commit }, payload) {
+ Array.isArray(payload)
+ ? commit('notify', { message: payload[1], type: payload[0] })
+ : commit('notify', { message: payload, type: 'green' });
+ }
+};
+
+export default {
+ state,
+ mutations,
+ actions
+};
diff --git a/src/store/modules/subgraph.ts b/src/store/modules/subgraph.ts
new file mode 100644
index 0000000..bccb5a6
--- /dev/null
+++ b/src/store/modules/subgraph.ts
@@ -0,0 +1,108 @@
+import { getAddress } from '@ethersproject/address';
+import { request } from '@/helpers/subgraph';
+
+const mutations = {
+ GET_VOTING_POWER_REQUEST() {
+ console.debug('GET_VOTING_POWER_REQUEST');
+ },
+ GET_VOTING_POWER_SUCCESS() {
+ console.debug('GET_VOTING_POWER_SUCCESS');
+ },
+ GET_VOTING_POWER_FAILURE(_state, payload) {
+ console.debug('GET_VOTING_POWER_FAILURE', payload);
+ },
+ GET_VOTING_POWERS_REQUEST() {
+ console.debug('GET_VOTING_POWERS_REQUEST');
+ },
+ GET_VOTING_POWERS_SUCCESS() {
+ console.debug('GET_VOTING_POWERS_SUCCESS');
+ },
+ GET_VOTING_POWERS_FAILURE(_state, payload) {
+ console.debug('GET_VOTING_POWERS_FAILURE', payload);
+ }
+};
+
+const actions = {
+ getVotingPowers: async ({ commit }, { blockTag, token, addresses }) => {
+ commit('GET_VOTING_POWERS_REQUEST');
+ try {
+ const block = blockTag === 'latest' ? undefined : { number: blockTag };
+ const result = await request('getVotingPowers', {
+ poolShares: {
+ __args: {
+ block,
+ where: {
+ userAddress_in: addresses.map(address => address.toLowerCase())
+ }
+ }
+ }
+ });
+ const votingPowers: any = Object.fromEntries(
+ addresses.map(address => [address, 0])
+ );
+ if (result && result.poolShares) {
+ result.poolShares.forEach(poolShare =>
+ poolShare.poolId.tokens.map(poolToken => {
+ const [, tokenAddress] = poolToken.id.split('-');
+ if (tokenAddress === token.toLowerCase()) {
+ const userAddress = getAddress(poolShare.userAddress.id);
+ const shares =
+ (poolToken.balance / poolShare.poolId.totalShares) *
+ poolShare.balance;
+ votingPowers[userAddress] = votingPowers[userAddress] + shares;
+ }
+ })
+ );
+ }
+ commit('GET_VOTING_POWERS_SUCCESS');
+ return votingPowers;
+ } catch (e) {
+ commit('GET_VOTING_POWERS_FAILURE', e);
+ }
+ },
+ getVotingPowersByPools: async (
+ { commit },
+ { blockTag, token, addresses }
+ ) => {
+ commit('GET_VOTING_POWERS_REQUEST');
+ try {
+ const block = blockTag === 'latest' ? undefined : { number: blockTag };
+ const result = await request('getVotingPowers', {
+ poolShares: {
+ __args: {
+ block,
+ where: {
+ userAddress_in: addresses.map(address => address.toLowerCase())
+ }
+ }
+ }
+ });
+ const votingPowers: any = Object.fromEntries(
+ addresses.map(address => [address, {}])
+ );
+ if (result && result.poolShares) {
+ result.poolShares.forEach(poolShare =>
+ poolShare.poolId.tokens.map(poolToken => {
+ const [poolId, tokenAddress] = poolToken.id.split('-');
+ if (tokenAddress === token.toLowerCase()) {
+ const userAddress = getAddress(poolShare.userAddress.id);
+ const poolAddress = getAddress(poolId);
+ votingPowers[userAddress][poolAddress] =
+ (poolToken.balance / poolShare.poolId.totalShares) *
+ poolShare.balance;
+ }
+ })
+ );
+ }
+ commit('GET_VOTING_POWERS_SUCCESS');
+ return votingPowers || {};
+ } catch (e) {
+ commit('GET_VOTING_POWERS_FAILURE', e);
+ }
+ }
+};
+
+export default {
+ mutations,
+ actions
+};
diff --git a/src/store/modules/ui.ts b/src/store/modules/ui.ts
new file mode 100644
index 0000000..a4d22bf
--- /dev/null
+++ b/src/store/modules/ui.ts
@@ -0,0 +1,39 @@
+import Vue from 'vue';
+import lock from '@/helpers/lock';
+import { lsGet } from '@/helpers/utils';
+import config from '@/helpers/config';
+
+const state = {
+ init: false,
+ loading: false
+};
+
+const mutations = {
+ SET(_state, payload) {
+ Object.keys(payload).forEach(key => {
+ Vue.set(_state, key, payload[key]);
+ });
+ }
+};
+
+const actions = {
+ init: async ({ commit, dispatch }) => {
+ commit('SET', { loading: true });
+ await Promise.all([dispatch('getBlockNumber'), dispatch('metadata')]);
+ const connector = lsGet('connector');
+ if (Object.keys(config.connectors).includes(connector)) {
+ const lockConnector = lock.getConnector(connector);
+ if (await lockConnector.isLoggedIn()) await dispatch('login', connector);
+ }
+ commit('SET', { loading: false, init: true });
+ },
+ loading: ({ commit }, payload) => {
+ commit('SET', { loading: payload });
+ }
+};
+
+export default {
+ state,
+ mutations,
+ actions
+};
diff --git a/src/store/modules/web3.ts b/src/store/modules/web3.ts
new file mode 100644
index 0000000..f2f0702
--- /dev/null
+++ b/src/store/modules/web3.ts
@@ -0,0 +1,396 @@
+import Vue from 'vue';
+import { Web3Provider } from '@ethersproject/providers';
+import { Contract } from '@ethersproject/contracts';
+import { getAddress } from '@ethersproject/address';
+import { formatUnits } from '@ethersproject/units';
+import { Interface } from '@ethersproject/abi';
+import store from '@/store';
+import abi from '@/helpers/abi';
+import config from '@/helpers/config';
+import lock from '@/helpers/lock';
+import wsProvider from '@/helpers/ws';
+import { lsSet, lsGet, lsRemove } from '@/helpers/utils';
+import namespaces from '@/namespaces.json';
+
+let provider;
+let web3;
+
+wsProvider.on('block', blockNumber => {
+ store.commit('GET_BLOCK_SUCCESS', blockNumber);
+});
+
+const state = {
+ injectedLoaded: false,
+ injectedChainId: null,
+ account: null,
+ name: null,
+ active: false,
+ balances: {},
+ blockNumber: 0,
+ namespaces: {}
+};
+
+const mutations = {
+ LOGOUT(_state) {
+ Vue.set(_state, 'injectedLoaded', false);
+ Vue.set(_state, 'injectedChainId', null);
+ Vue.set(_state, 'account', null);
+ Vue.set(_state, 'name', null);
+ Vue.set(_state, 'active', false);
+ Vue.set(_state, 'balances', {});
+ console.debug('LOGOUT');
+ },
+ LOAD_WEB3_REQUEST() {
+ console.debug('LOAD_WEB3_REQUEST');
+ },
+ LOAD_WEB3_SUCCESS() {
+ console.debug('LOAD_WEB3_SUCCESS');
+ },
+ LOAD_WEB3_FAILURE(_state, payload) {
+ console.debug('LOAD_WEB3_FAILURE', payload);
+ },
+ LOAD_PROVIDER_REQUEST() {
+ console.debug('LOAD_PROVIDER_REQUEST');
+ },
+ LOAD_PROVIDER_SUCCESS(_state, payload) {
+ Vue.set(_state, 'injectedLoaded', payload.injectedLoaded);
+ Vue.set(_state, 'injectedChainId', payload.injectedChainId);
+ Vue.set(_state, 'account', payload.account);
+ Vue.set(_state, 'name', payload.name);
+ console.debug('LOAD_PROVIDER_SUCCESS');
+ },
+ LOAD_PROVIDER_FAILURE(_state, payload) {
+ Vue.set(_state, 'injectedLoaded', false);
+ Vue.set(_state, 'injectedChainId', null);
+ Vue.set(_state, 'account', null);
+ Vue.set(_state, 'active', false);
+ console.debug('LOAD_PROVIDER_FAILURE', payload);
+ },
+ LOAD_BACKUP_PROVIDER_REQUEST() {
+ console.debug('LOAD_BACKUP_PROVIDER_REQUEST');
+ },
+ LOAD_BACKUP_PROVIDER_SUCCESS(_state, payload) {
+ console.debug('LOAD_BACKUP_PROVIDER_SUCCESS', payload);
+ },
+ LOAD_BACKUP_PROVIDER_FAILURE(_state, payload) {
+ Vue.set(_state, 'injectedLoaded', false);
+ Vue.set(_state, 'backUpLoaded', false);
+ Vue.set(_state, 'account', null);
+ Vue.set(_state, 'activeChainId', null);
+ Vue.set(_state, 'active', false);
+ console.debug('LOAD_BACKUP_PROVIDER_FAILURE', payload);
+ },
+ HANDLE_CHAIN_CHANGED() {
+ console.debug('HANDLE_CHAIN_CHANGED');
+ },
+ HANDLE_ACCOUNTS_CHANGED(_state, payload) {
+ Vue.set(_state, 'account', payload);
+ console.debug('HANDLE_ACCOUNTS_CHANGED', payload);
+ },
+ HANDLE_CLOSE_CHANGED() {
+ console.debug('HANDLE_CLOSE_CHANGED');
+ },
+ HANDLE_NETWORK_CHANGED() {
+ console.debug('HANDLE_NETWORK_CHANGED');
+ },
+ LOOKUP_ADDRESS_REQUEST() {
+ console.debug('LOOKUP_ADDRESS_REQUEST');
+ },
+ LOOKUP_ADDRESS_SUCCESS(_state, payload) {
+ Vue.set(_state, 'name', payload);
+ console.debug('LOOKUP_ADDRESS_SUCCESS');
+ },
+ LOOKUP_ADDRESS_FAILURE(_state, payload) {
+ console.debug('LOOKUP_ADDRESS_FAILURE', payload);
+ },
+ RESOLVE_NAME_REQUEST() {
+ console.debug('RESOLVE_NAME_REQUEST');
+ },
+ RESOLVE_NAME_SUCCESS() {
+ console.debug('RESOLVE_NAME_SUCCESS');
+ },
+ RESOLVE_NAME_FAILURE(_state, payload) {
+ console.debug('RESOLVE_NAME_FAILURE', payload);
+ },
+ SEND_TRANSACTION_REQUEST() {
+ console.debug('SEND_TRANSACTION_REQUEST');
+ },
+ SEND_TRANSACTION_SUCCESS() {
+ console.debug('SEND_TRANSACTION_SUCCESS');
+ },
+ SEND_TRANSACTION_FAILURE(_state, payload) {
+ console.debug('SEND_TRANSACTION_FAILURE', payload);
+ },
+ SIGN_MESSAGE_REQUEST() {
+ console.debug('SIGN_MESSAGE_REQUEST');
+ },
+ SIGN_MESSAGE_SUCCESS() {
+ console.debug('SIGN_MESSAGE_SUCCESS');
+ },
+ SIGN_MESSAGE_FAILURE(_state, payload) {
+ console.debug('SIGN_MESSAGE_FAILURE', payload);
+ },
+ GET_BLOCK_REQUEST() {
+ console.debug('GET_BLOCK_REQUEST');
+ },
+ GET_BLOCK_SUCCESS(_state, payload) {
+ Vue.set(_state, 'blockNumber', payload);
+ console.debug('GET_BLOCK_SUCCESS', payload);
+ },
+ GET_BLOCK_FAILURE(_state, payload) {
+ console.debug('GET_BLOCK_FAILURE', payload);
+ },
+ GET_BALANCE_REQUEST() {
+ console.debug('GET_BALANCE_REQUEST');
+ },
+ GET_BALANCE_SUCCESS() {
+ console.debug('GET_BALANCE_SUCCESS');
+ },
+ GET_BALANCE_FAILURE(_state, payload) {
+ console.debug('GET_BALANCE_FAILURE', payload);
+ },
+ MULTICALL_SUCCESS() {
+ console.debug('MULTICALL_SUCCESS');
+ },
+ METADATA_SUCCESS(_state, payload) {
+ Vue.set(_state, 'namespaces', payload);
+ console.debug('METADATA_SUCCESS');
+ }
+};
+
+const actions = {
+ login: async ({ dispatch }, connector = 'injected') => {
+ const lockConnector = lock.getConnector(connector);
+ provider = await lockConnector.connect();
+ if (provider) {
+ web3 = new Web3Provider(provider);
+ await dispatch('loadWeb3');
+ if (state.account) lsSet('connector', connector);
+ }
+ },
+ logout: async ({ commit }) => {
+ const connector = lsGet('connector');
+ if (connector) {
+ const lockConnector = lock.getConnector(connector);
+ await lockConnector.logout();
+ lsRemove('connector');
+ }
+ commit('LOGOUT');
+ },
+ loadWeb3: async ({ commit, dispatch }) => {
+ commit('LOAD_WEB3_REQUEST');
+ try {
+ await dispatch('loadProvider');
+ await dispatch('loadAccount');
+ commit('LOAD_WEB3_SUCCESS');
+ if (!state.injectedLoaded || state.injectedChainId !== config.chainId) {
+ await dispatch('loadBackupProvider');
+ } else {
+ /**
+ this.providerStatus.activeChainId = this.providerStatus.injectedChainId;
+ this.providerStatus.injectedActive = true;
+ if (this.providerStatus.account)
+ this.fetchUserBlockchainData(this.providerStatus.account);
+ */
+ }
+ } catch (e) {
+ commit('LOAD_WEB3_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ loadProvider: async ({ commit, dispatch }) => {
+ commit('LOAD_PROVIDER_REQUEST');
+ try {
+ provider.removeAllListeners();
+ if (provider.on) {
+ provider.on('chainChanged', async () => {
+ commit('HANDLE_CHAIN_CHANGED');
+ if (state.active) {
+ await dispatch('loadWeb3');
+ }
+ });
+ provider.on('accountsChanged', async accounts => {
+ if (accounts.length === 0) {
+ if (state.active) await dispatch('loadWeb3');
+ } else {
+ commit('HANDLE_ACCOUNTS_CHANGED', accounts[0]);
+ await dispatch('loadWeb3');
+ }
+ });
+ provider.on('close', async () => {
+ commit('HANDLE_CLOSE');
+ if (state.active) await dispatch('loadWeb3');
+ });
+ provider.on('networkChanged', async () => {
+ commit('HANDLE_NETWORK_CHANGED');
+ if (state.active) {
+ await dispatch('loadWeb3');
+ }
+ });
+ }
+ const network = await web3.getNetwork();
+ const accounts = await web3.listAccounts();
+ const account = accounts.length > 0 ? accounts[0] : null;
+ commit('LOAD_PROVIDER_SUCCESS', {
+ injectedLoaded: true,
+ injectedChainId: network.chainId,
+ account,
+ name
+ });
+ } catch (e) {
+ commit('LOAD_PROVIDER_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ loadBackupProvider: async ({ commit }) => {
+ try {
+ web3 = wsProvider;
+ const network = await wsProvider.getNetwork();
+ commit('LOAD_BACKUP_PROVIDER_SUCCESS', {
+ injectedActive: false,
+ backUpLoaded: true,
+ account: null,
+ activeChainId: network.chainId
+ // backUpWeb3: web3,
+ });
+ } catch (e) {
+ commit('LOAD_BACKUP_PROVIDER_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ lookupAddress: async ({ commit }) => {
+ commit('LOOKUP_ADDRESS_REQUEST');
+ try {
+ const name = await web3.lookupAddress(state.account);
+ commit('LOOKUP_ADDRESS_SUCCESS', name);
+ return name;
+ } catch (e) {
+ commit('LOOKUP_ADDRESS_FAILURE', e);
+ }
+ },
+ resolveName: async ({ commit }, payload) => {
+ commit('RESOLVE_NAME_REQUEST');
+ try {
+ const address = await web3.resolveName(payload);
+ commit('RESOLVE_NAME_SUCCESS');
+ return address;
+ } catch (e) {
+ commit('RESOLVE_NAME_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ sendTransaction: async (
+ { commit },
+ [contractType, contractAddress, action, params]
+ ) => {
+ commit('SEND_TRANSACTION_REQUEST');
+ try {
+ const signer = web3.getSigner();
+ const contract = new Contract(
+ getAddress(contractAddress),
+ abi[contractType],
+ web3
+ );
+ const contractWithSigner = contract.connect(signer);
+ const tx = await contractWithSigner[action](...params);
+ await tx.wait();
+ commit('SEND_TRANSACTION_SUCCESS');
+ return tx;
+ } catch (e) {
+ commit('SEND_TRANSACTION_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ signMessage: async ({ commit }, message) => {
+ commit('SIGN_MESSAGE_REQUEST');
+ try {
+ const signer = web3.getSigner();
+ const sig = await signer.signMessage(message);
+ commit('SIGN_MESSAGE_SUCCESS');
+ return sig;
+ } catch (e) {
+ commit('SIGN_MESSAGE_FAILURE', e);
+ return Promise.reject(e);
+ }
+ },
+ loadAccount: async ({ dispatch }) => {
+ await dispatch('lookupAddress');
+ },
+ getBlockNumber: async ({ commit }) => {
+ commit('GET_BLOCK_REQUEST');
+ try {
+ const blockNumber: any = await wsProvider.getBlockNumber();
+ commit('GET_BLOCK_SUCCESS', parseInt(blockNumber));
+ return blockNumber;
+ } catch (e) {
+ commit('GET_BLOCK_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ getBalance: async ({ commit, dispatch }, { blockTag, token }) => {
+ const { decimals } = state.namespaces[token];
+ commit('GET_BALANCE_REQUEST');
+ try {
+ const response = await dispatch('multicall', {
+ name: 'TestToken',
+ calls: [[token, 'balanceOf', [state.account]]],
+ options: { blockTag }
+ });
+ const balance = parseFloat(formatUnits(response[0].toString(), decimals));
+ commit('GET_BALANCE_SUCCESS');
+ return balance;
+ } catch (e) {
+ commit('GET_BALANCE_FAILURE', e);
+ return Promise.reject();
+ }
+ },
+ multicall: async ({ commit }, { name, calls, options }) => {
+ const multi = new Contract(config.multicall, abi['Multicall'], wsProvider);
+ const itf = new Interface(abi[name]);
+ try {
+ let [, response] = await multi.aggregate(
+ calls.map(call => [
+ call[0].toLowerCase(),
+ itf.encodeFunctionData(call[1], call[2])
+ ]),
+ options || {}
+ );
+ response = response.map((call, i) =>
+ itf.decodeFunctionResult(calls[i][1], call)
+ );
+ commit('MULTICALL_SUCCESS');
+ return response;
+ } catch (e) {
+ return Promise.reject();
+ }
+ },
+ metadata: async ({ commit, dispatch }) => {
+ try {
+ const response = await dispatch('multicall', {
+ name: 'TestToken',
+ calls: Object.values(namespaces).map((namespace: any) => [
+ namespace.address,
+ 'decimals',
+ []
+ ])
+ });
+ const payload = Object.fromEntries(
+ response.map((item, i) => [
+ // @ts-ignore
+ Object.values(namespaces)[i].address,
+ { decimals: response[i][0] }
+ ])
+ );
+ commit('METADATA_SUCCESS', payload);
+ return payload;
+ } catch (e) {
+ return Promise.reject();
+ }
+ }
+};
+
+export default {
+ state,
+ mutations,
+ actions
+};
diff --git a/src/style.scss b/src/style.scss
new file mode 100644
index 0000000..33278e5
--- /dev/null
+++ b/src/style.scss
@@ -0,0 +1,99 @@
+@import './fonts';
+@import './vars';
+@import "~@primer/css/index.scss";
+
+html, body, #app {
+ background-color: $black;
+ color: $gray;
+ font-family: $font-weight-normal;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+* {
+ outline: none !important;
+}
+
+h1, h2, h3, h4 {
+ color: $white;
+ font-family: $font-weight-bold;
+}
+
+b {
+ font-family: $font-weight-bold;
+}
+
+p {
+ font-size: 22px;
+}
+
+#app {
+ min-height: 100vh;
+}
+
+a {
+ color: $white;
+
+ &:hover {
+ color: $white !important;
+ cursor: pointer;
+ text-decoration: none !important;
+ }
+}
+
+::placeholder {
+ color: $gray;
+}
+
+.input {
+ outline: none;
+ color: $white;
+ background-color: transparent;
+ border: none;
+}
+
+textarea {
+ font-size: 20px;
+}
+
+::-webkit-scrollbar-thumb {
+ background-color: $border-color;
+ background-clip: padding-box;
+ border: 0;
+ border-radius: 0;
+
+ &:hover {
+ background-color: $border-color;
+ }
+}
+
+.eyebrow {
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ font-size: 16px;
+}
+
+.column {
+ width: 160px;
+}
+
+.anim-fade-in {
+ animation-duration: 0.6s !important;
+}
+
+.line-height-0 {
+ line-height: 0;
+}
+
+.bg-black {
+ background-color: $black;
+}
+
+.State {
+ font-size: 16px;
+ line-height: 30px;
+ height: 28px;
+ vertical-align: middle;
+ padding: 0 12px;
+ border-radius: 14px;
+}
diff --git a/src/vars.scss b/src/vars.scss
new file mode 100644
index 0000000..6ba276e
--- /dev/null
+++ b/src/vars.scss
@@ -0,0 +1,30 @@
+@import '~primer-support';
+
+// Default skin
+$black: #0f1011;
+$border-color: #353d45;
+$blue: #384AFF;
+$green: #21b66f;
+$red: #ff3856;
+$bg-blue: $blue;
+$bg-green: $green;
+$bg-red: $red;
+$text-blue: $blue;
+$text-green: $green;
+$text-red: $red;
+$bg-gray-dark: lighten($black, 2);
+
+@import './yam';
+
+$border: 1px solid $border-color;
+$border-radius: 4px;
+$body-font-size: 18px;
+$body-line-height: 1.4;
+$h1-size: 36px;
+$h2-size: 28px;
+$h3-size: 24px;
+$h4-size: 20px;
+$font-weight-normal: 'Calibre-Medium', -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
+$font-weight-bold: 'Calibre-Semibold', -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji;
+$body-font: $font-weight-normal;
+$font-mktg: $font-weight-bold;
diff --git a/src/views/Create.vue b/src/views/Create.vue
new file mode 100644
index 0000000..c146b94
--- /dev/null
+++ b/src/views/Create.vue
@@ -0,0 +1,185 @@
+
+
+
+
+
+ {{ namespace.name || _shorten(namespace.address) }}
+
+
+
+
+
+
+
+
+
+ {{ i + 1 }}
+
+
+
+
+
+
+
+
+ Add choice
+
+
+
+
+
+
+
+ Select start date
+
+
+
+ Select end date
+
+
+
+
+
+
+
+ Publish
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Home.vue b/src/views/Home.vue
new file mode 100644
index 0000000..c7fb4bc
--- /dev/null
+++ b/src/views/Home.vue
@@ -0,0 +1,45 @@
+
+
+
+ Dashboard
+
+
+
+
+
+
+
+ {{ namespace.name }}
+ {{ namespace.symbol }}
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Proposal.vue b/src/views/Proposal.vue
new file mode 100644
index 0000000..2ca6dc3
--- /dev/null
+++ b/src/views/Proposal.vue
@@ -0,0 +1,193 @@
+
+
+
+
+
+
+ {{ namespace.name || _shorten(namespace.address) }}
+
+
+
+
+
+
+ {{ payload.name }}
+
+
+
+
+
+
+
+
+
+
+ Vote
+
+
+
+
+
+
+
+ Token
+
+
+ {{ namespace.symbol }}
+
+
+
+ Author
+
+
+
+
+
+ Start date
+
+
+
+ End date
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Proposals.vue b/src/views/Proposals.vue
new file mode 100644
index 0000000..68488d6
--- /dev/null
+++ b/src/views/Proposals.vue
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+ Proposals
+
+
+
+
+
+ New proposal
+
+
+
+
+
+
+
+
+
+
+
+ There isn't any proposal here yet!
+
+
+
+
+
+
+
diff --git a/src/yam.scss b/src/yam.scss
new file mode 100644
index 0000000..0f901ac
--- /dev/null
+++ b/src/yam.scss
@@ -0,0 +1,23 @@
+$white: #5b2739;
+$text-white: $white;
+$black: #efe7ea;
+$border-color: #e2cfd5;
+$bg-gray-dark: lighten($black, 2);
+$gray: #a98592;
+$text-gray: $gray;
+$blue: #d2004a;
+$gray-900: $gray;
+$bg-blue: $blue;
+
+.State, .Counter, .button--submit {
+ color: $black !important;
+
+ &:disabled {
+ border: 1px solid $border-color !important;
+ background-color: $border-color !important;
+ }
+}
+
+.bg-gray-9 {
+ background-color: $border-color !important;
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 0000000..00c6365
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,41 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "esnext",
+ "strict": true,
+ "jsx": "preserve",
+ "importHelpers": true,
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "sourceMap": true,
+ "baseUrl": ".",
+ "types": [
+ "webpack-env"
+ ],
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ],
+ "noImplicitAny": false,
+ "resolveJsonModule": true,
+ "skipLibCheck": true
+ },
+ "include": [
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "src/**/*.vue",
+ "tests/**/*.ts",
+ "tests/**/*.tsx"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
+}
diff --git a/vue.config.js b/vue.config.js
new file mode 100644
index 0000000..d272bf2
--- /dev/null
+++ b/vue.config.js
@@ -0,0 +1,7 @@
+module.exports = {
+ pluginOptions: {
+ webpackBundleAnalyzer: {
+ openAnalyzer: false
+ }
+ }
+};