commit 4738e61f88bb928c048d15e07ddd074838b3fde7
parent a2975206dc3a1c77df5b1b35ede95f3f122073c3
Author: William Muli <willi.wambu@gmail.com>
Date: Thu, 15 Jun 2023 23:40:10 +0300
Add chain configuration
Diffstat:
18 files changed, 2088 insertions(+), 74 deletions(-)
diff --git a/.env.example b/.env.example
@@ -0,0 +1,6 @@
+# Public
+PUBLIC_RPC_URL=http://localhost:8545
+PUBLIC_CHAIN_ID=1337
+PUBLIC_DECIMALS=18
+PUBLIC_VOTE_CONTRACT_ADDRESS=0xa170d45e0e34cb5b72736dfa6d1a30e83d7f0d0f32fc79d4e2ab135be4482348
+PUBLIC_ERC20_CONTRACT_ADDRESS=0xefd6e2143651dca5f836bdf27debc773139037a4
+\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
@@ -7,6 +7,11 @@
"": {
"name": "frontend",
"version": "0.0.1",
+ "dependencies": {
+ "@wagmi/chains": "^1.1.0",
+ "ethers": "^6.5.1",
+ "viem": "^1.0.7"
+ },
"devDependencies": {
"@fontsource/fira-mono": "^4.5.10",
"@neoconfetti/svelte": "^1.0.0",
@@ -16,6 +21,7 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.14",
+ "daisyui": "^3.1.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.26.0",
@@ -31,6 +37,11 @@
"vitest": "^0.25.3"
}
},
+ "node_modules/@adraffy/ens-normalize": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz",
+ "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg=="
+ },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -550,6 +561,53 @@
"integrity": "sha512-SmksyaJAdSlMa9cTidVSIqYo1qti+WTsviNDwgjNVm+KQ3DRP2Df9umDIzC4vCcpEYY+chQe0i2IKnLw03AT8Q==",
"dev": true
},
+ "node_modules/@noble/curves": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz",
+ "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "@noble/hashes": "1.3.0"
+ }
+ },
+ "node_modules/@noble/curves/node_modules/@noble/hashes": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
+ "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
+ "node_modules/@noble/hashes": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz",
+ "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
+ "node_modules/@noble/secp256k1": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
+ "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -591,6 +649,70 @@
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true
},
+ "node_modules/@scure/base": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
+ "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
+ "node_modules/@scure/bip32": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz",
+ "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "@noble/curves": "~1.0.0",
+ "@noble/hashes": "~1.3.0",
+ "@scure/base": "~1.1.0"
+ }
+ },
+ "node_modules/@scure/bip32/node_modules/@noble/hashes": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
+ "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/@scure/bip39": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
+ "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ],
+ "dependencies": {
+ "@noble/hashes": "~1.3.0",
+ "@scure/base": "~1.1.0"
+ }
+ },
+ "node_modules/@scure/bip39/node_modules/@noble/hashes": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
+ "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==",
+ "engines": {
+ "node": ">= 16"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
"node_modules/@sveltejs/adapter-auto": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-2.1.0.tgz",
@@ -907,6 +1029,43 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
+ "node_modules/@wagmi/chains": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@wagmi/chains/-/chains-1.1.0.tgz",
+ "integrity": "sha512-pWZlxBk0Ql8E7DV8DwqlbBpOyUdaG9UDlQPBxJNALuEK1I0tbQ3AVvSDnlsEIt06UPmPo5o27gzs3hwPQ/A+UA==",
+ "funding": [
+ {
+ "type": "gitcoin",
+ "url": "https://wagmi.sh/gitcoin"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/wagmi-dev"
+ }
+ ],
+ "peerDependencies": {
+ "typescript": ">=5.0.4"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/abitype": {
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.8.7.tgz",
+ "integrity": "sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==",
+ "peerDependencies": {
+ "typescript": ">=5.0.4",
+ "zod": "^3 >=3.19.1"
+ },
+ "peerDependenciesMeta": {
+ "zod": {
+ "optional": true
+ }
+ }
+ },
"node_modules/acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -937,6 +1096,11 @@
"node": ">=0.4.0"
}
},
+ "node_modules/aes-js": {
+ "version": "4.0.0-beta.5",
+ "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
+ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -1287,6 +1451,12 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
+ "node_modules/colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "dev": true
+ },
"node_modules/commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -1325,6 +1495,16 @@
"node": ">= 8"
}
},
+ "node_modules/css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dev": true,
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -1337,6 +1517,28 @@
"node": ">=4"
}
},
+ "node_modules/daisyui": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.1.0.tgz",
+ "integrity": "sha512-G4dz/bRZVvlhQ/FtezXSg0rXOXzDJ0PcnMqeLSwCYNWXxf46fNJ8LWeV5qwsYOdJbXiXoZLnwyy+BsNoWZ+Bjg==",
+ "dev": true,
+ "dependencies": {
+ "colord": "^2.9",
+ "css-selector-tokenizer": "^0.8",
+ "postcss-js": "^4",
+ "tailwindcss": "^3"
+ },
+ "engines": {
+ "node": ">=16.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/daisyui"
+ },
+ "peerDependencies": {
+ "postcss": "^8"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -1735,6 +1937,43 @@
"node": ">=0.10.0"
}
},
+ "node_modules/ethers": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.5.1.tgz",
+ "integrity": "sha512-jDpCnUGcyn39hnRUEtrulDZOtJcIPEz4Whccl3N9qhwdLsn1ELuDM9TgGgGJq6ph0p8/Uri+Wezmo/r69E+xkA==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/ethers-io/"
+ },
+ {
+ "type": "individual",
+ "url": "https://www.buymeacoffee.com/ricmoo"
+ }
+ ],
+ "dependencies": {
+ "@adraffy/ens-normalize": "1.9.2",
+ "@noble/hashes": "1.1.2",
+ "@noble/secp256k1": "1.7.1",
+ "@types/node": "18.15.13",
+ "aes-js": "4.0.0-beta.5",
+ "tslib": "2.4.0",
+ "ws": "8.5.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/ethers/node_modules/@types/node": {
+ "version": "18.15.13",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
+ "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
+ },
+ "node_modules/ethers/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -1781,6 +2020,12 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
+ "node_modules/fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
"node_modules/fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@@ -2144,6 +2389,14 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
+ "node_modules/isomorphic-ws": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
+ "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
+ "peerDependencies": {
+ "ws": "*"
+ }
+ },
"node_modules/jiti": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
@@ -3597,7 +3850,6 @@
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
"integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
- "dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -3663,6 +3915,61 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
+ "node_modules/viem": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/viem/-/viem-1.0.7.tgz",
+ "integrity": "sha512-P/T2Zn8+V74kxO2e2NdhNR/MBtldovssigvc36+7g3DgTeETKnSS1fMQdBl0jE+Atlal+M6cuJ2HcFY7U45o0Q==",
+ "dependencies": {
+ "@adraffy/ens-normalize": "1.9.0",
+ "@noble/curves": "1.0.0",
+ "@noble/hashes": "1.3.0",
+ "@scure/bip32": "1.3.0",
+ "@scure/bip39": "1.2.0",
+ "@wagmi/chains": "1.1.0",
+ "abitype": "0.8.7",
+ "isomorphic-ws": "5.0.0",
+ "ws": "8.12.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.4"
+ }
+ },
+ "node_modules/viem/node_modules/@adraffy/ens-normalize": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz",
+ "integrity": "sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ=="
+ },
+ "node_modules/viem/node_modules/@noble/hashes": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
+ "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ ]
+ },
+ "node_modules/viem/node_modules/ws": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
+ "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/vite": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
@@ -3810,6 +4117,26 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
+ "node_modules/ws": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
+ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
@@ -3839,6 +4166,11 @@
}
},
"dependencies": {
+ "@adraffy/ens-normalize": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz",
+ "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg=="
+ },
"@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -4119,6 +4451,31 @@
"integrity": "sha512-SmksyaJAdSlMa9cTidVSIqYo1qti+WTsviNDwgjNVm+KQ3DRP2Df9umDIzC4vCcpEYY+chQe0i2IKnLw03AT8Q==",
"dev": true
},
+ "@noble/curves": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.0.0.tgz",
+ "integrity": "sha512-2upgEu0iLiDVDZkNLeFV2+ht0BAVgQnEmCk6JsOch9Rp8xfkMCbvbAZlA2pBHQc73dbl+vFOXfqkf4uemdn0bw==",
+ "requires": {
+ "@noble/hashes": "1.3.0"
+ },
+ "dependencies": {
+ "@noble/hashes": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
+ "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg=="
+ }
+ }
+ },
+ "@noble/hashes": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz",
+ "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA=="
+ },
+ "@noble/secp256k1": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz",
+ "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw=="
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -4151,6 +4508,44 @@
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true
},
+ "@scure/base": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz",
+ "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA=="
+ },
+ "@scure/bip32": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.0.tgz",
+ "integrity": "sha512-bcKpo1oj54hGholplGLpqPHRbIsnbixFtc06nwuNM5/dwSXOq/AAYoIBRsBmnZJSdfeNW5rnff7NTAz3ZCqR9Q==",
+ "requires": {
+ "@noble/curves": "~1.0.0",
+ "@noble/hashes": "~1.3.0",
+ "@scure/base": "~1.1.0"
+ },
+ "dependencies": {
+ "@noble/hashes": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
+ "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA=="
+ }
+ }
+ },
+ "@scure/bip39": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.0.tgz",
+ "integrity": "sha512-SX/uKq52cuxm4YFXWFaVByaSHJh2w3BnokVSeUJVCv6K7WulT9u2BuNRBhuFl8vAuYnzx9bEu9WgpcNYTrYieg==",
+ "requires": {
+ "@noble/hashes": "~1.3.0",
+ "@scure/base": "~1.1.0"
+ },
+ "dependencies": {
+ "@noble/hashes": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz",
+ "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA=="
+ }
+ }
+ },
"@sveltejs/adapter-auto": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-2.1.0.tgz",
@@ -4349,6 +4744,18 @@
"eslint-visitor-keys": "^3.3.0"
}
},
+ "@wagmi/chains": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@wagmi/chains/-/chains-1.1.0.tgz",
+ "integrity": "sha512-pWZlxBk0Ql8E7DV8DwqlbBpOyUdaG9UDlQPBxJNALuEK1I0tbQ3AVvSDnlsEIt06UPmPo5o27gzs3hwPQ/A+UA==",
+ "requires": {}
+ },
+ "abitype": {
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/abitype/-/abitype-0.8.7.tgz",
+ "integrity": "sha512-wQ7hV8Yg/yKmGyFpqrNZufCxbszDe5es4AZGYPBitocfSqXtjrTG9JMWFcc4N30ukl2ve48aBTwt7NJxVQdU3w==",
+ "requires": {}
+ },
"acorn": {
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
@@ -4368,6 +4775,11 @@
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true
},
+ "aes-js": {
+ "version": "4.0.0-beta.5",
+ "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz",
+ "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q=="
+ },
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -4598,6 +5010,12 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true
},
+ "colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "dev": true
+ },
"commander": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
@@ -4627,12 +5045,34 @@
"which": "^2.0.1"
}
},
+ "css-selector-tokenizer": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
+ "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
+ "dev": true,
+ "requires": {
+ "cssesc": "^3.0.0",
+ "fastparse": "^1.1.2"
+ }
+ },
"cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true
},
+ "daisyui": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-3.1.0.tgz",
+ "integrity": "sha512-G4dz/bRZVvlhQ/FtezXSg0rXOXzDJ0PcnMqeLSwCYNWXxf46fNJ8LWeV5qwsYOdJbXiXoZLnwyy+BsNoWZ+Bjg==",
+ "dev": true,
+ "requires": {
+ "colord": "^2.9",
+ "css-selector-tokenizer": "^0.8",
+ "postcss-js": "^4",
+ "tailwindcss": "^3"
+ }
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -4927,6 +5367,32 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "ethers": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.5.1.tgz",
+ "integrity": "sha512-jDpCnUGcyn39hnRUEtrulDZOtJcIPEz4Whccl3N9qhwdLsn1ELuDM9TgGgGJq6ph0p8/Uri+Wezmo/r69E+xkA==",
+ "requires": {
+ "@adraffy/ens-normalize": "1.9.2",
+ "@noble/hashes": "1.1.2",
+ "@noble/secp256k1": "1.7.1",
+ "@types/node": "18.15.13",
+ "aes-js": "4.0.0-beta.5",
+ "tslib": "2.4.0",
+ "ws": "8.5.0"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "18.15.13",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz",
+ "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q=="
+ },
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4969,6 +5435,12 @@
"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
"dev": true
},
+ "fastparse": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+ "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+ "dev": true
+ },
"fastq": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
@@ -5239,6 +5711,12 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"dev": true
},
+ "isomorphic-ws": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz",
+ "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==",
+ "requires": {}
+ },
"jiti": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
@@ -6198,8 +6676,7 @@
"typescript": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz",
- "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==",
- "dev": true
+ "integrity": "sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw=="
},
"undici": {
"version": "5.22.1",
@@ -6235,6 +6712,40 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
+ "viem": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/viem/-/viem-1.0.7.tgz",
+ "integrity": "sha512-P/T2Zn8+V74kxO2e2NdhNR/MBtldovssigvc36+7g3DgTeETKnSS1fMQdBl0jE+Atlal+M6cuJ2HcFY7U45o0Q==",
+ "requires": {
+ "@adraffy/ens-normalize": "1.9.0",
+ "@noble/curves": "1.0.0",
+ "@noble/hashes": "1.3.0",
+ "@scure/bip32": "1.3.0",
+ "@scure/bip39": "1.2.0",
+ "@wagmi/chains": "1.1.0",
+ "abitype": "0.8.7",
+ "isomorphic-ws": "5.0.0",
+ "ws": "8.12.0"
+ },
+ "dependencies": {
+ "@adraffy/ens-normalize": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.0.tgz",
+ "integrity": "sha512-iowxq3U30sghZotgl4s/oJRci6WPBfNO5YYgk2cIOMCHr3LeGPcsZjCEr+33Q4N+oV3OABDAtA+pyvWjbvBifQ=="
+ },
+ "@noble/hashes": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz",
+ "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg=="
+ },
+ "ws": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
+ "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+ "requires": {}
+ }
+ }
+ },
"vite": {
"version": "4.3.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz",
@@ -6297,6 +6808,12 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
+ "ws": {
+ "version": "8.5.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz",
+ "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==",
+ "requires": {}
+ },
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
diff --git a/package.json b/package.json
@@ -20,6 +20,7 @@
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"autoprefixer": "^10.4.14",
+ "daisyui": "^3.1.0",
"eslint": "^8.28.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte": "^2.26.0",
@@ -34,5 +35,10 @@
"vite": "^4.3.0",
"vitest": "^0.25.3"
},
- "type": "module"
+ "type": "module",
+ "dependencies": {
+ "@wagmi/chains": "^1.1.0",
+ "ethers": "^6.5.1",
+ "viem": "^1.0.7"
+ }
}
diff --git a/src/app.css b/src/app.css
@@ -1,4 +1,11 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins&display=swap");
@tailwind base;
@tailwind components;
-@tailwind utilities;
-\ No newline at end of file
+@tailwind utilities;
+
+body {
+ background: linear-gradient(180deg,#fff 22%,#d7caec 100%);
+ overflow: scroll;
+ overscroll-behavior-y: none;
+}
+
diff --git a/src/client.ts b/src/client.ts
@@ -0,0 +1,12 @@
+import { createPublicClient, createWalletClient, custom, http } from 'viem'
+import { localhost } from '@wagmi/chains'
+
+export const walletClient = () => createWalletClient({
+ chain: localhost,
+ transport: custom(window.ethereum)
+})
+
+export const publicClient = () => createPublicClient({
+ chain: localhost,
+ transport: http()
+})
+\ No newline at end of file
diff --git a/src/components/Nav.svelte b/src/components/Nav.svelte
@@ -0,0 +1,50 @@
+<script lang="ts">
+ import { NavOptions } from "../options/nav-options";
+</script>
+
+<nav class="flex items-center justify-between flex-wrap bg-black p-6">
+ <div class="flex items-center flex-shrink-0 text-white mr-6">
+ <svg
+ class="fill-current h-8 w-8 mr-2"
+ width="54"
+ height="54"
+ viewBox="0 0 54 54"
+ xmlns="http://www.w3.org/2000/svg"
+ ><path
+ d="M13.5 22.1c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05zM0 38.3c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05z"
+ /></svg
+ >
+ <span class="font-semibold text-xl tracking-tight">EVM Token Vote</span>
+ </div>
+ <div class="block lg:hidden">
+ <button
+ class="flex items-center px-3 py-2 border rounded text-white border-teal-400 hover:text-white hover:border-white"
+ >
+ <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
+ ><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" /></svg
+ >
+ </button>
+ </div>
+ <div class="w-full block flex-grow lg:flex lg:items-center lg:w-auto lg:ml-20">
+ <div class="text-sm lg:flex-grow">
+ {#each NavOptions as { url, name} }
+ <a
+ href={url}
+ class="block mt-4 lg:inline-block lg:mt-0 text-gray-400 font-bold hover:text-white hover:text-md mr-4"
+ >
+ {name}
+ </a>
+ {/each}
+ </div>
+ <div>
+ <button
+ class="inline-block text-sm px-4 py-2 leading-none rounded text-white bg-emerald-500 hover:text-teal-500 hover:bg-emerald-600 mt-4 lg:mt-0"
+ on:click
+ on:keydown
+ >
+ Connect wallet
+ </button
+ >
+ </div>
+ </div>
+</nav>
diff --git a/src/components/NetworkForm.svelte b/src/components/NetworkForm.svelte
@@ -0,0 +1,213 @@
+<script lang="ts">
+ import { numberToHex } from 'viem'
+ import type { Chain } from '@wagmi/chains'
+ import { configuredChain, votingConfig } from '../store'
+ $configuredChain
+ $votingConfig
+
+ type ConfigFormData = {
+ rpcEndpoint: string
+ chainName: string
+ currencyName: string
+ currencySymbol: string
+ chainId: number
+ decimals: number
+ contractAddress: string
+ erc20ContractAddress: string
+ }
+
+ let configData: ConfigFormData = {
+ rpcEndpoint: $configuredChain.rpcUrls.default.http[0],
+ chainName: $configuredChain.name,
+ currencyName: $configuredChain.nativeCurrency.name,
+ currencySymbol: $configuredChain.nativeCurrency.symbol,
+ chainId: $configuredChain.id,
+ decimals: $configuredChain.nativeCurrency.decimals,
+ contractAddress: $votingConfig.contractAddress,
+ erc20ContractAddress: $votingConfig.erc20ContractAddress
+ }
+
+ const onSubmit = async () => {
+ await addNetworkToWallet(configData)
+ }
+
+ async function addNetworkToWallet(configData: ConfigFormData) {
+ if (!window.ethereum) alert('Please install a wallet to continue')
+ try {
+ updateConfiguredChain()
+ votingConfig.updateVotingConfig({
+ contractAddress: configData.contractAddress,
+ erc20ContractAddress: configData.erc20ContractAddress
+ })
+
+ await window.ethereum.request({
+ method: 'wallet_addEthereumChain',
+ params: [
+ {
+ chainId: numberToHex(configData.chainId),
+ rpcUrls: [configData.rpcEndpoint],
+ chainName: configData.chainName,
+ nativeCurrency: {
+ name: configData.currencyName,
+ symbol: configData.currencySymbol,
+ decimals: configData.decimals
+ },
+ blockExplorerUrls: ['https://example.com']
+ }
+ ]
+ })
+ } catch (error) {
+ console.log(error)
+ }
+ }
+
+ const updateConfiguredChain = () => {
+ const updatedChain: Chain = {
+ id: configData.chainId,
+ name: configData.chainName,
+ rpcUrls: {
+ default: {
+ http: [configData.rpcEndpoint],
+ webSocket: undefined
+ },
+ public: {
+ http: [],
+ webSocket: undefined
+ }
+ },
+ nativeCurrency: {
+ name: configData.currencyName,
+ symbol: configData.currencySymbol,
+ decimals: configData.decimals
+ },
+ network: $configuredChain.name
+ }
+ configuredChain.updateChain(updatedChain)
+ }
+</script>
+
+<div class="flex justify-center items-center w-full py-10">
+ <div class="flex w-full items-center justify-center">
+ <div class="card w-full md:w-2/5 m-2 md:m-0 shadow-xl bg-white">
+ <div class="card-body">
+ <h2 class="text-gray-900 text-center w-full font-semibold text-xl">Network Details</h2>
+ <form
+ on:submit|preventDefault={onSubmit}
+ class="flex flex-col justify-center w-full flex-1"
+ >
+ <div class="form-control w-full">
+ <label for="rpcUrl" class="label">
+ <span class="label-text text-gray-800">RPC endpoint</span>
+ </label>
+ <input
+ name="rpcUrl"
+ type="url"
+ placeholder="Enter RPC endpoint"
+ class="input input-bordered w-full"
+ bind:value={configData.rpcEndpoint}
+ />
+ </div>
+
+ <div class="flex flex-col md:flex-row w-full gap-3 mt-3">
+ <div class="form-control w-full">
+ <label for="chainName" class="label">
+ <span class="label-text text-gray-800">Chain Name</span>
+ </label>
+ <input
+ name="chainName"
+ type="text"
+ placeholder="Enter chain name"
+ class="input input-bordered w-full"
+ bind:value={configData.chainName}
+ />
+ </div>
+
+ <div class="form-control w-full">
+ <label for="currencyName" class="label">
+ <span class="label-text text-gray-800">Currency Name</span>
+ </label>
+ <input
+ name="currencyName"
+ type="text"
+ placeholder="Enter currency name"
+ class="input input-bordered w-full"
+ bind:value={configData.currencyName}
+ />
+ </div>
+ </div>
+
+ <div class="flex flex-col md:flex-row w-full gap-3 mt-3">
+ <div class="form-control w-full">
+ <label for="currencySymbol" class="label">
+ <span class="label-text text-gray-800">Currency symbol</span>
+ </label>
+ <input
+ name="currencySymbol"
+ type="text"
+ placeholder="Enter currency symbol(2-6 characters)"
+ class="input input-bordered w-full"
+ minlength="2"
+ maxlength="6"
+ bind:value={configData.currencySymbol}
+ />
+ </div>
+
+ <div class="form-control w-full">
+ <label for="chainId" class="label">
+ <span class="label-text text-gray-800">Chain ID</span>
+ </label>
+ <input
+ name="chainId"
+ type="number"
+ placeholder="Enter chainId"
+ class="input input-bordered w-full"
+ bind:value={configData.chainId}
+ />
+ </div>
+ <div class="form-control w-full">
+ <label for="chainId" class="label">
+ <span class="label-text text-gray-800">Decimals</span>
+ </label>
+ <input
+ name="chainId"
+ type="number"
+ placeholder="Enter decimals"
+ class="input input-bordered w-full"
+ bind:value={configData.decimals}
+ />
+ </div>
+ </div>
+
+ <div class="form-control w-full mt-3">
+ <label for="contractAddress" class="label">
+ <span class="label-text text-gray-800">Contract address</span>
+ </label>
+ <input
+ name="contractAddress"
+ type="text"
+ placeholder="Enter voting contract address"
+ class="input input-bordered w-full"
+ bind:value={configData.contractAddress}
+ />
+ </div>
+
+ <div class="form-control w-full mt-3">
+ <label for="erc20ContractAddress" class="label">
+ <span class="label-text text-gray-800">ERC-20 Contract address</span>
+ </label>
+ <input
+ name="erc20ContractAddress"
+ type="text"
+ placeholder="Enter ERC-20 contract address"
+ class="input input-bordered w-full"
+ bind:value={configData.erc20ContractAddress}
+ />
+ </div>
+ <button type="submit" class="btn btn-primary w-40 self-center mt-6 normal-case text-white"
+ >Add to wallet</button
+ >
+ </form>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/src/components/nav/nav.svelte b/src/components/nav/nav.svelte
@@ -1,46 +0,0 @@
-<script lang="ts">
- import { NavOptions } from "../../options/nav-options";
-</script>
-
-<nav class="flex items-center justify-between flex-wrap bg-black p-6">
- <div class="flex items-center flex-shrink-0 text-white mr-6">
- <svg
- class="fill-current h-8 w-8 mr-2"
- width="54"
- height="54"
- viewBox="0 0 54 54"
- xmlns="http://www.w3.org/2000/svg"
- ><path
- d="M13.5 22.1c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05zM0 38.3c1.8-7.2 6.3-10.8 13.5-10.8 10.8 0 12.15 8.1 17.55 9.45 3.6.9 6.75-.45 9.45-4.05-1.8 7.2-6.3 10.8-13.5 10.8-10.8 0-12.15-8.1-17.55-9.45-3.6-.9-6.75.45-9.45 4.05z"
- /></svg
- >
- <span class="font-semibold text-xl tracking-tight">EVM Token Vote</span>
- </div>
- <div class="block lg:hidden">
- <button
- class="flex items-center px-3 py-2 border rounded text-white border-teal-400 hover:text-white hover:border-white"
- >
- <svg class="fill-current h-3 w-3" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"
- ><title>Menu</title><path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" /></svg
- >
- </button>
- </div>
- <div class="w-full block flex-grow lg:flex lg:items-center lg:w-auto lg:ml-20">
- <div class="text-sm lg:flex-grow">
- {#each NavOptions as { url, name} }
- <a
- href={url}
- class="block mt-4 lg:inline-block lg:mt-0 text-gray-400 font-bold hover:text-white hover:text-md mr-4"
- >
- {name}
- </a>
- {/each}
- </div>
- <div>
- <button
- class="inline-block text-sm px-4 py-2 leading-none rounded text-white bg-emerald-500 hover:text-teal-500 hover:bg-emerald-600 mt-4 lg:mt-0"
- >Connect wallet</button
- >
- </div>
- </div>
-</nav>
diff --git a/src/global.d.ts b/src/global.d.ts
@@ -0,0 +1,7 @@
+export {}
+
+declare global {
+ interface Window {
+ ethereum: EthereumProvider
+ }
+}
+\ No newline at end of file
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
@@ -1,5 +1,130 @@
-<script>
- import "../app.css";
+<script lang="ts">
+ import { onMount } from 'svelte'
+ import { formatEther, getContract, parseEther, type RequestAddressesReturnType, stringToHex } from 'viem'
+ import { walletClient, publicClient } from '../client'
+ import Nav from '../components/Nav.svelte'
+ import '../app.css'
+ import { PUBLIC_ERC20_CONTRACT_ADDRESS, PUBLIC_VOTE_CONTRACT_ADDRESS } from '$env/static/public'
+ import { erc20TokenAbi, gitableAbi } from '../shared/erc20-token-abi'
+ import { voteContractAbi } from '../shared/token-vote-abi'
+ import { configuredChain, votingConfig } from '../store'
+
+ let userAddress: `0x${string}` | undefined
+ let balance: bigint | undefined
+ let isConnected: boolean = false
+ // $configuredChain
+
+ // console.log($configuredChain)
+ configuredChain.subscribe(value => console.log(value))
+ votingConfig.subscribe(value => console.log(value))
+
+ const setup = async (accounts: RequestAddressesReturnType) => {
+ userAddress = accounts[0]
+ try {
+ balance = await publicClient().getBalance({
+ address: userAddress
+ })
+ isConnected = true
+
+ window.ethereum.on('accountsChanged', () => {
+ window.location.reload()
+ })
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ const connectWallet = async () => {
+ if (window.ethereum) {
+ const accounts = await walletClient().requestAddresses()
+
+ if (accounts.length > 0) {
+ await setup(accounts)
+ }
+ }
+ }
+
+ const sendTransaction = async () => {
+ if (!userAddress || !window.ethereum) return
+ await walletClient().sendTransaction({
+ account: userAddress,
+ to: '0x0000000000000000000000000000000000000000',
+ value: parseEther('0.000001')
+ })
+ }
+
+ const checkBalance = async () => {
+ if (!userAddress) return
+
+ const ethBalance = await publicClient().getBalance({
+ address: userAddress as `0x${string}`
+ })
+
+ console.log({ ethBalance })
+
+ const contract = getContract({
+ address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
+ publicClient: publicClient(),
+ walletClient: walletClient(),
+ abi: erc20TokenAbi
+ })
+ const result = await contract.read.balanceOf([userAddress] as [`0x${string}`])
+ console.log(result)
+ }
+
+ const createProposal = async () => {
+ const description = stringToHex('Testing proposal creation', { size: 32 })
+ const blockWait = 100
+ const targetVote = 500000
+
+ const { request } = await publicClient().simulateContract({
+ address: PUBLIC_VOTE_CONTRACT_ADDRESS as `0x${string}`,
+ abi: voteContractAbi,
+ functionName: 'propose',
+ args: [description, BigInt(blockWait), targetVote],
+ account: userAddress
+ })
+ const result = await walletClient().writeContract(request)
+ console.log(result)
+ }
+
+ const getCurrentProposal = async () => {
+ const contract = getContract({
+ address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
+ publicClient: publicClient(),
+ walletClient: walletClient(),
+ abi: voteContractAbi
+ })
+ const result = await contract.read.getProposal([BigInt(1)])
+ console.log(result)
+ }
+
+ onMount(async () => {
+ if (window.ethereum) {
+ const accounts = await walletClient().getAddresses()
+
+ if (accounts.length > 0) {
+ await setup(accounts)
+ }
+ }
+ })
</script>
-<slot />
-\ No newline at end of file
+<Nav on:click={connectWallet} />
+{#if isConnected}
+ <p class="text-xl text-green-600">
+ Successfully connected with account: <strong>{userAddress}</strong>
+ </p>
+ <button class="btn btn-sm" on:click={sendTransaction}>Send transaction</button>
+ <button class="btn bt-sm" on:click={checkBalance}>Check balance</button>
+ <button class="btn" on:click={createProposal}>Create proposal</button>
+ <button class="btn" on:click={getCurrentProposal}>Get current proposal</button>
+ <ul>
+ <li>Current Network: {walletClient().chain.name}</li>
+ <li>Your current balance: {balance && formatEther(balance)} eth</li>
+ </ul>
+{:else}
+ <button class="btn" on:click={connectWallet}>Connect with Wallet </button>
+{/if}
+
+<slot />
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
@@ -1,17 +1,15 @@
+<script lang="ts">
+ import NetworkForm from '../components/NetworkForm.svelte'
+
+</script>
<svelte:head>
<title>EVM Token Vote</title>
- <meta name="description" content="Vote on propositions with zero or more options using ERC20 tokens." />
+ <meta
+ name="description"
+ content="Vote on propositions with zero or more options using ERC20 tokens."
+ />
</svelte:head>
-<script lang="ts">
- import Nav from "../components/nav/nav.svelte";
-</script>
-
-<Nav />
-
-<style lang="postcss">
- :global(html) {
- background-color: theme(colors.gray.100);
- }
-</style>
-
-\ No newline at end of file
+<div class="flex w-full min-h-screen">
+ <NetworkForm />
+</div>
+\ No newline at end of file
diff --git a/src/routes/+page.ts b/src/routes/+page.ts
@@ -1,3 +1 @@
-// since there's no dynamic data here, we can prerender
-// it so that it gets served as a static asset in production
-export const prerender = true;
+
diff --git a/src/shared/erc20-token-abi.ts b/src/shared/erc20-token-abi.ts
@@ -0,0 +1,492 @@
+export const erc20TokenAbi = [
+ {
+ constant: true,
+ inputs: [],
+ name: 'name',
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_spender',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'approve',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_from',
+ type: 'address'
+ },
+ {
+ name: '_to',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'transferFrom',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'decimals',
+ outputs: [
+ {
+ name: '',
+ type: 'uint8'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_owner',
+ type: 'address'
+ }
+ ],
+ name: 'balanceOf',
+ outputs: [
+ {
+ name: 'balance',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [],
+ name: 'symbol',
+ outputs: [
+ {
+ name: '',
+ type: 'string'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ constant: false,
+ inputs: [
+ {
+ name: '_to',
+ type: 'address'
+ },
+ {
+ name: '_value',
+ type: 'uint256'
+ }
+ ],
+ name: 'transfer',
+ outputs: [
+ {
+ name: '',
+ type: 'bool'
+ }
+ ],
+ payable: false,
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ constant: true,
+ inputs: [
+ {
+ name: '_owner',
+ type: 'address'
+ },
+ {
+ name: '_spender',
+ type: 'address'
+ }
+ ],
+ name: 'allowance',
+ outputs: [
+ {
+ name: '',
+ type: 'uint256'
+ }
+ ],
+ payable: false,
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ payable: true,
+ stateMutability: 'payable',
+ type: 'fallback'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'owner',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'spender',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ],
+ name: 'Approval',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ {
+ indexed: true,
+ name: 'from',
+ type: 'address'
+ },
+ {
+ indexed: true,
+ name: 'to',
+ type: 'address'
+ },
+ {
+ indexed: false,
+ name: 'value',
+ type: 'uint256'
+ }
+ ],
+ name: 'Transfer',
+ type: 'event'
+ }
+] as const
+
+export const gitableAbi = [
+ {
+ inputs: [
+ { internalType: 'string', name: '_name', type: 'string' },
+ { internalType: 'string', name: '_symbol', type: 'string' },
+ { internalType: 'uint8', name: '_decimals', type: 'uint8' },
+ { internalType: 'uint256', name: '_expireTimestamp', type: 'uint256' }
+ ],
+ stateMutability: 'nonpayable',
+ type: 'constructor'
+ },
+ {
+ 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'
+ },
+ {
+ anonymous: false,
+ inputs: [{ indexed: false, internalType: 'uint256', name: '_value', type: 'uint256' }],
+ name: 'Burn',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [{ indexed: false, internalType: 'uint256', name: '_timestamp', type: 'uint256' }],
+ name: 'Expired',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [
+ { indexed: true, internalType: 'address', name: '_minter', type: 'address' },
+ { indexed: true, internalType: 'address', name: '_beneficiary', type: 'address' },
+ { indexed: false, internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'Mint',
+ type: 'event'
+ },
+ {
+ 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: '_from', type: 'address' },
+ { indexed: true, internalType: 'address', name: '_to', type: 'address' },
+ { indexed: true, internalType: 'address', name: '_spender', type: 'address' },
+ { indexed: false, internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'TransferFrom',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [{ indexed: false, internalType: 'address', name: '_writer', type: 'address' }],
+ name: 'WriterAdded',
+ type: 'event'
+ },
+ {
+ anonymous: false,
+ inputs: [{ indexed: false, internalType: 'address', name: '_writer', type: 'address' }],
+ name: 'WriterRemoved',
+ type: 'event'
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_minter', type: 'address' }],
+ name: 'addWriter',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '', type: 'address' },
+ { internalType: 'address', name: '', type: 'address' }
+ ],
+ name: 'allowance',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'applyExpiry',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_spender', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'approve',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'address', name: '', type: 'address' }],
+ name: 'balanceOf',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'uint256', name: '_value', type: 'uint256' }],
+ name: 'burn',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_from', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' },
+ { internalType: 'bytes', name: '_data', type: 'bytes' }
+ ],
+ name: 'burn',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'burn',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'decimals',
+ outputs: [{ internalType: 'uint8', name: '', type: 'uint8' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_minter', type: 'address' }],
+ name: 'deleteWriter',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'expires',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_minter', type: 'address' }],
+ name: 'isWriter',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_to', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' },
+ { internalType: 'bytes', name: '_data', type: 'bytes' }
+ ],
+ name: 'mint',
+ outputs: [],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_to', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'mintTo',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'name',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'owner',
+ outputs: [{ internalType: 'address', name: '', type: 'address' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'bytes4', name: '_sum', type: 'bytes4' }],
+ name: 'supportsInterface',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'pure',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'symbol',
+ outputs: [{ internalType: 'string', name: '', type: 'string' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'totalBurned',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'totalMinted',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [],
+ name: 'totalSupply',
+ outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
+ stateMutability: 'view',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_to', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'transfer',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [
+ { internalType: 'address', name: '_from', type: 'address' },
+ { internalType: 'address', name: '_to', type: 'address' },
+ { internalType: 'uint256', name: '_value', type: 'uint256' }
+ ],
+ name: 'transferFrom',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ },
+ {
+ inputs: [{ internalType: 'address', name: '_newOwner', type: 'address' }],
+ name: 'transferOwnership',
+ outputs: [{ internalType: 'bool', name: '', type: 'bool' }],
+ stateMutability: 'nonpayable',
+ type: 'function'
+ }
+] as const
+\ No newline at end of file
diff --git a/src/shared/localstorage-keys.ts b/src/shared/localstorage-keys.ts
@@ -0,0 +1,4 @@
+export const LOCAL_STORAGE_KEYS = {
+ CHAIN_CONFIG: 'EVM_TOKEN_VOTE_CHAIN_CONFIG',
+ VOTING_CONFIG: 'EVM_TOKEN_VOTE_VOTING_CONFIG'
+}
+\ No newline at end of file
diff --git a/src/shared/token-vote-abi.ts b/src/shared/token-vote-abi.ts
@@ -0,0 +1,523 @@
+export const voteContractAbi = [
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_token",
+ "type": "address"
+ },
+ {
+ "internalType": "bool",
+ "name": "_protectSupply",
+ "type": "bool"
+ },
+ {
+ "internalType": "address",
+ "name": "_voterRegistry",
+ "type": "address"
+ },
+ {
+ "internalType": "address",
+ "name": "_proposerRegistry",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "constructor"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_blockDeadline",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "voteTargetPpm",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ }
+ ],
+ "name": "ProposalAdded",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "internalType": "bool",
+ "name": "_cancelled",
+ "type": "bool"
+ },
+ {
+ "indexed": true,
+ "internalType": "bool",
+ "name": "_insufficient",
+ "type": "bool"
+ },
+ {
+ "indexed": false,
+ "internalType": "uint256",
+ "name": "_totalVote",
+ "type": "uint256"
+ }
+ ],
+ "name": "ProposalCompleted",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "finalize",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "getCurrentProposal",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "description",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32[]",
+ "name": "options",
+ "type": "bytes32[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "optionVotes",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "cancelVotes",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "supply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "total",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "blockDeadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint24",
+ "name": "targetVotePpm",
+ "type": "uint24"
+ },
+ {
+ "internalType": "address",
+ "name": "proposer",
+ "type": "address"
+ },
+ {
+ "internalType": "uint8",
+ "name": "state",
+ "type": "uint8"
+ },
+ {
+ "internalType": "uint8",
+ "name": "scanCursor",
+ "type": "uint8"
+ }
+ ],
+ "internalType": "struct ERC20Vote.Proposal",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_optionIdx",
+ "type": "uint256"
+ }
+ ],
+ "name": "getOption",
+ "outputs": [
+ {
+ "internalType": "bytes32",
+ "name": "",
+ "type": "bytes32"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ }
+ ],
+ "name": "getProposal",
+ "outputs": [
+ {
+ "components": [
+ {
+ "internalType": "bytes32",
+ "name": "description",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32[]",
+ "name": "options",
+ "type": "bytes32[]"
+ },
+ {
+ "internalType": "uint256[]",
+ "name": "optionVotes",
+ "type": "uint256[]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "cancelVotes",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "supply",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "total",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "blockDeadline",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint24",
+ "name": "targetVotePpm",
+ "type": "uint24"
+ },
+ {
+ "internalType": "address",
+ "name": "proposer",
+ "type": "address"
+ },
+ {
+ "internalType": "uint8",
+ "name": "state",
+ "type": "uint8"
+ },
+ {
+ "internalType": "uint8",
+ "name": "scanCursor",
+ "type": "uint8"
+ }
+ ],
+ "internalType": "struct ERC20Vote.Proposal",
+ "name": "",
+ "type": "tuple"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ }
+ ],
+ "name": "optionCount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "_description",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_blockWait",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint24",
+ "name": "_targetVotePpm",
+ "type": "uint24"
+ }
+ ],
+ "name": "propose",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "bytes32",
+ "name": "_description",
+ "type": "bytes32"
+ },
+ {
+ "internalType": "bytes32[]",
+ "name": "_options",
+ "type": "bytes32[]"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_blockWait",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint24",
+ "name": "_targetVotePpm",
+ "type": "uint24"
+ }
+ ],
+ "name": "proposeMulti",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_proposalIndex",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint8",
+ "name": "_count",
+ "type": "uint8"
+ }
+ ],
+ "name": "scan",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "token",
+ "outputs": [
+ {
+ "internalType": "address",
+ "name": "",
+ "type": "address"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "vote",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "voteCancel",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_proposalIdx",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_optionIdx",
+ "type": "uint256"
+ }
+ ],
+ "name": "voteCount",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_optionIndex",
+ "type": "uint256"
+ },
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "voteOption",
+ "outputs": [
+ {
+ "internalType": "bool",
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "uint256",
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "withdraw",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [],
+ "name": "withdraw",
+ "outputs": [
+ {
+ "internalType": "uint256",
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+] as const
diff --git a/src/shared/types.ts b/src/shared/types.ts
@@ -0,0 +1,4 @@
+export interface VotingConfig {
+ contractAddress: string
+ erc20ContractAddress: string
+}
+\ No newline at end of file
diff --git a/src/store.ts b/src/store.ts
@@ -0,0 +1,77 @@
+import { writable } from 'svelte/store'
+import { browser } from '$app/environment'
+import type { Chain } from '@wagmi/chains'
+import {
+ PUBLIC_RPC_URL,
+ PUBLIC_CHAIN_ID,
+ PUBLIC_CHAIN_NAME,
+ PUBLIC_CURRENCY_NAME,
+ PUBLIC_CURRENCY_SYMBOL,
+ PUBLIC_DECIMALS,
+ PUBLIC_VOTE_CONTRACT_ADDRESS,
+ PUBLIC_ERC20_CONTRACT_ADDRESS
+} from '$env/static/public'
+import type { VotingConfig } from './shared/types'
+import { LOCAL_STORAGE_KEYS } from './shared/localstorage-keys'
+
+const createChain = () => {
+ const initialChain: Chain = {
+ id: parseInt(PUBLIC_CHAIN_ID, 10),
+ name: PUBLIC_CHAIN_NAME,
+ rpcUrls: {
+ default: {
+ http: [PUBLIC_RPC_URL],
+ webSocket: undefined
+ },
+ public: {
+ http: [],
+ webSocket: undefined
+ }
+ },
+ nativeCurrency: {
+ name: PUBLIC_CURRENCY_NAME,
+ symbol: PUBLIC_CURRENCY_SYMBOL,
+ decimals: parseInt(PUBLIC_DECIMALS, 10)
+ },
+ network: PUBLIC_CHAIN_NAME
+ }
+
+ let localValue;
+ if (browser) {
+ localValue = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.CHAIN_CONFIG) || '{}')
+ }
+ console.log({localValue})
+
+ const { subscribe, update } = writable<Chain>(localValue || initialChain)
+
+ return {
+ subscribe,
+ updateChain: (newChain: Chain) =>
+ update((current) => {
+ const chain = { ...current, ...newChain }
+ // update localstorage
+ if (browser) {
+ localStorage.setItem(LOCAL_STORAGE_KEYS.CHAIN_CONFIG, JSON.stringify(chain))
+ }
+ return chain
+ })
+ }
+}
+
+export const createVotingConfig = () => {
+ const initialVotingConfig: VotingConfig = {
+ contractAddress: PUBLIC_VOTE_CONTRACT_ADDRESS,
+ erc20ContractAddress: PUBLIC_ERC20_CONTRACT_ADDRESS
+ }
+
+ const { subscribe, update } = writable<VotingConfig>(initialVotingConfig)
+
+ return {
+ subscribe,
+ updateVotingConfig: (newConfig: VotingConfig) =>
+ update((current) => ({ ...current, ...newConfig }))
+ }
+}
+
+export const configuredChain = createChain()
+export const votingConfig = createVotingConfig()
diff --git a/tailwind.config.js b/tailwind.config.js
@@ -8,6 +8,23 @@ export default {
}
},
},
- plugins: [],
+ daisyui: {
+ themes: [
+ {
+ mytheme: {
+ "primary": "#00d1b2",
+ "secondary": "#a989f9",
+ "accent": "#ffcce8",
+ "neutral": "#322541",
+ "base-100": "#ffffff",
+ "info": "#abceed",
+ "success": "#65e2b2",
+ "warning": "#eeb21b",
+ "error": "#f71d62",
+ },
+ },
+ ],
+ },
+ plugins: [require("daisyui")],
}