├── .gitignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── lerna.json ├── package.json ├── packages ├── lib │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── scripts │ │ └── prepArc.js │ ├── src │ │ ├── dependency │ │ │ ├── arc │ │ │ │ ├── index.ts │ │ │ │ ├── migration.ts │ │ │ │ ├── src │ │ │ │ │ ├── contracts-optimized │ │ │ │ │ │ └── 0.0.1-rc.41 │ │ │ │ │ │ │ ├── ARCDebug.json │ │ │ │ │ │ │ ├── ARCVotingMachineCallbacksMock.json │ │ │ │ │ │ │ ├── AbsoluteVote.json │ │ │ │ │ │ │ ├── AbsoluteVoteExecuteMock.json │ │ │ │ │ │ │ ├── ActionMock.json │ │ │ │ │ │ │ ├── Address.json │ │ │ │ │ │ │ ├── Agreement.json │ │ │ │ │ │ │ ├── AgreementMock.json │ │ │ │ │ │ │ ├── Auction4Reputation.json │ │ │ │ │ │ │ ├── Avatar.json │ │ │ │ │ │ │ ├── BadERC20.json │ │ │ │ │ │ │ ├── Competition.json │ │ │ │ │ │ │ ├── Context.json │ │ │ │ │ │ │ ├── ContinuousLocking4Reputation.json │ │ │ │ │ │ │ ├── ContributionReward.json │ │ │ │ │ │ │ ├── ContributionRewardExt.json │ │ │ │ │ │ │ ├── Controller.json │ │ │ │ │ │ │ ├── ControllerCreator.json │ │ │ │ │ │ │ ├── CurveInterface.json │ │ │ │ │ │ │ ├── DAORegistry.json │ │ │ │ │ │ │ ├── DAOToken.json │ │ │ │ │ │ │ ├── DAOTracker.json │ │ │ │ │ │ │ ├── DaoCreator.json │ │ │ │ │ │ │ ├── Debug.json │ │ │ │ │ │ │ ├── ECDSA.json │ │ │ │ │ │ │ ├── ERC20.json │ │ │ │ │ │ │ ├── ERC20Burnable.json │ │ │ │ │ │ │ ├── ERC20Mock.json │ │ │ │ │ │ │ ├── ERC827.json │ │ │ │ │ │ │ ├── ERC827Token.json │ │ │ │ │ │ │ ├── ERC827TokenMock.json │ │ │ │ │ │ │ ├── ExternalLocking4Reputation.json │ │ │ │ │ │ │ ├── ExternalTokenLockerMock.json │ │ │ │ │ │ │ ├── FixedReputationAllocation.json │ │ │ │ │ │ │ ├── Forwarder.json │ │ │ │ │ │ │ ├── GenericScheme.json │ │ │ │ │ │ │ ├── GenesisProtocol.json │ │ │ │ │ │ │ ├── GenesisProtocolCallbacksMock.json │ │ │ │ │ │ │ ├── GenesisProtocolLogic.json │ │ │ │ │ │ │ ├── GlobalConstraintInterface.json │ │ │ │ │ │ │ ├── GlobalConstraintMock.json │ │ │ │ │ │ │ ├── GlobalConstraintRegistrar.json │ │ │ │ │ │ │ ├── IERC20.json │ │ │ │ │ │ │ ├── IntVoteInterface.json │ │ │ │ │ │ │ ├── Locking4Reputation.json │ │ │ │ │ │ │ ├── LockingEth4Reputation.json │ │ │ │ │ │ │ ├── LockingToken4Reputation.json │ │ │ │ │ │ │ ├── Math.json │ │ │ │ │ │ │ ├── Migrations.json │ │ │ │ │ │ │ ├── MiniMeToken.json │ │ │ │ │ │ │ ├── NectarRepAllocation.json │ │ │ │ │ │ │ ├── OrganizationRegister.json │ │ │ │ │ │ │ ├── Ownable.json │ │ │ │ │ │ │ ├── PolkaCurve.json │ │ │ │ │ │ │ ├── PriceOracleInterface.json │ │ │ │ │ │ │ ├── PriceOracleMock.json │ │ │ │ │ │ │ ├── ProposalExecuteInterface.json │ │ │ │ │ │ │ ├── QuorumVote.json │ │ │ │ │ │ │ ├── RealMath.json │ │ │ │ │ │ │ ├── RealMathTester.json │ │ │ │ │ │ │ ├── Redeemer.json │ │ │ │ │ │ │ ├── RepAllocation.json │ │ │ │ │ │ │ ├── Reputation.json │ │ │ │ │ │ │ ├── ReputationAdmin.json │ │ │ │ │ │ │ ├── ReputationFromToken.json │ │ │ │ │ │ │ ├── SafeERC20.json │ │ │ │ │ │ │ ├── SafeERC20Mock.json │ │ │ │ │ │ │ ├── SafeMath.json │ │ │ │ │ │ │ ├── SchemeRegistrar.json │ │ │ │ │ │ │ ├── SignalScheme.json │ │ │ │ │ │ │ ├── TokenCapGC.json │ │ │ │ │ │ │ ├── UniversalScheme.json │ │ │ │ │ │ │ ├── UniversalSchemeInterface.json │ │ │ │ │ │ │ ├── UniversalSchemeMock.json │ │ │ │ │ │ │ ├── UpgradeScheme.json │ │ │ │ │ │ │ ├── VoteInOrganizationScheme.json │ │ │ │ │ │ │ ├── VotingMachineCallbacks.json │ │ │ │ │ │ │ ├── VotingMachineCallbacksInterface.json │ │ │ │ │ │ │ └── Wallet.json │ │ │ │ │ ├── migrate-dao.js │ │ │ │ │ ├── migration.json │ │ │ │ │ ├── sanitize.js │ │ │ │ │ └── utils.js │ │ │ │ └── types │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── migration.ts │ │ │ │ │ ├── schemes.ts │ │ │ │ │ └── votingMachines.ts │ │ │ └── web3 │ │ │ │ ├── declarations.d.ts │ │ │ │ ├── index.ts │ │ │ │ ├── typeConversion.ts │ │ │ │ ├── typeValidation.ts │ │ │ │ └── types.ts │ │ ├── forms │ │ │ ├── Field.ts │ │ │ ├── Form.ts │ │ │ ├── dao │ │ │ │ ├── DAOConfigForm.ts │ │ │ │ ├── DAOForm.ts │ │ │ │ ├── GenesisProtocolForm.ts │ │ │ │ ├── MemberForm.ts │ │ │ │ ├── SchemeForm.ts │ │ │ │ ├── index.ts │ │ │ │ └── schemes │ │ │ │ │ ├── ContributionRewardForm.ts │ │ │ │ │ ├── SchemeRegistrarForm.ts │ │ │ │ │ └── index.ts │ │ │ ├── fields │ │ │ │ ├── AddressField.ts │ │ │ │ ├── DateTimeField.ts │ │ │ │ ├── DurationField.ts │ │ │ │ ├── NumberField.ts │ │ │ │ ├── PercentageField.ts │ │ │ │ ├── StringField.ts │ │ │ │ ├── TokenField.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── validators.ts │ │ ├── index.ts │ │ └── state.ts │ ├── test │ │ ├── dao-params │ │ │ ├── dao-params-test-1.json │ │ │ ├── dao-params-test-2.json │ │ │ └── dao-params-test-3.json │ │ └── members-csv │ │ │ ├── bad-test.csv │ │ │ ├── bad-test2.csv │ │ │ ├── bad-test3.csv │ │ │ ├── test.csv │ │ │ ├── test2.csv │ │ │ ├── test3.csv │ │ │ ├── test4.csv │ │ │ ├── testzero.csv │ │ │ └── whitespace.csv │ └── tsconfig.json ├── ui_v1 │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── components │ │ │ ├── DAOcreator │ │ │ │ ├── DeployStep.tsx │ │ │ │ ├── MembersStep.tsx │ │ │ │ ├── NamingStep.tsx │ │ │ │ ├── ReviewStep.tsx │ │ │ │ ├── SchemesStep.tsx │ │ │ │ └── index.tsx │ │ │ ├── README.md │ │ │ ├── common │ │ │ │ ├── EthAddressAvatar │ │ │ │ │ ├── declarations.d.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── FormField │ │ │ │ │ ├── declarations.d.ts │ │ │ │ │ └── index.tsx │ │ │ │ ├── PieChart.tsx │ │ │ │ └── dao │ │ │ │ │ ├── DAOConfigEditor.tsx │ │ │ │ │ ├── GenesisProtocolAnalytics │ │ │ │ │ ├── AnalysisResultView.tsx │ │ │ │ │ ├── declarations.d.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── GenesisProtocolEditor.tsx │ │ │ │ │ ├── GenesisProtocolPresetEditor.tsx │ │ │ │ │ ├── MemberEditor.tsx │ │ │ │ │ ├── MembersAnalytics.tsx │ │ │ │ │ ├── MembersEditor.tsx │ │ │ │ │ ├── MembersSaveLoad.tsx │ │ │ │ │ ├── MigrationParamsImport.tsx │ │ │ │ │ ├── Migrator │ │ │ │ │ ├── LogLineTypes.ts │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── SchemeEditor.tsx │ │ │ │ │ └── SchemesEditor.tsx │ │ │ ├── index.tsx │ │ │ └── theme.ts │ │ ├── index.tsx │ │ └── react-app-env.d.ts │ ├── tsconfig.json │ └── tsconfig.release.json └── ui_v2 │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json │ ├── src │ ├── components │ │ ├── DAOcreatorV2 │ │ │ ├── InstallStep.tsx │ │ │ ├── MembersStep.tsx │ │ │ ├── NamingStep.tsx │ │ │ ├── Review.tsx │ │ │ ├── SchemesStep.tsx │ │ │ ├── index.tsx │ │ │ └── styles.css │ │ ├── README.md │ │ ├── assets │ │ │ ├── icons │ │ │ │ ├── more.svg │ │ │ │ └── pencil.svg │ │ │ ├── logos │ │ │ │ └── dao-logo-gray.svg │ │ │ └── styles │ │ │ │ ├── bootstrap.css │ │ │ │ └── mdbreact.css │ │ ├── commonV2 │ │ │ ├── DAOstackLogo.tsx │ │ │ ├── EthAddressAvatar │ │ │ │ ├── declarations.d.ts │ │ │ │ └── index.tsx │ │ │ ├── FormField │ │ │ │ ├── index.tsx │ │ │ │ └── styles.css │ │ │ ├── LineGraphic.tsx │ │ │ ├── Stepper │ │ │ │ ├── ImporterModal.tsx │ │ │ │ ├── Preview.tsx │ │ │ │ ├── UtilityButton.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.css │ │ │ └── dao │ │ │ │ ├── DAOConfigEditor.tsx │ │ │ │ ├── Members │ │ │ │ ├── MemberEditor.tsx │ │ │ │ ├── MembersAnalytics.tsx │ │ │ │ ├── MembersEditor.tsx │ │ │ │ ├── MembersTable.tsx │ │ │ │ ├── index.ts │ │ │ │ └── styles.css │ │ │ │ ├── Migrator │ │ │ │ ├── DeployButton.tsx │ │ │ │ ├── LogLineTypes.ts │ │ │ │ ├── OrganizationLine.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.css │ │ │ │ ├── Schemes │ │ │ │ ├── AdvancedEditor.tsx │ │ │ │ ├── SchemeEditor.tsx │ │ │ │ ├── Toggle.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── styles.css │ │ │ │ └── VotingMachineEditor.tsx │ │ ├── index.tsx │ │ ├── utils │ │ │ ├── hooks │ │ │ │ ├── forceUpdate.hook.ts │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── schemesUtils.ts │ │ │ └── stringUtils.ts │ │ └── web3 │ │ │ └── core.ts │ ├── index.tsx │ └── react-app-env.d.ts │ ├── tsconfig.json │ └── tsconfig.release.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | ganache-accounts.json 24 | #/src/contracts/interfaces 25 | secret.json 26 | 27 | # vscode chrome debugger cache 28 | .vscode/chrome 29 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v10.16.3 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | cache: 4 | directories: 5 | - node_modules 6 | - packages/ui_v1/node_modules 7 | - packages/lib/node_modules 8 | 9 | script: 10 | - npm run build 11 | # TODO automatically deploy npm packages to npmjs when merged to master 12 | # deploy: 13 | # provider: npmjs 14 | # skip-cleanup: true 15 | # github-token: $GITHUB_TOKEN # Set in the settings page of your repository, as a secure variable 16 | # local_dir: build 17 | # on: 18 | # branch: master 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 dOrg BBLLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DAOcreator Monorepo 2 | 3 | Making DAO deployment as simple as 1, 2, 3. 4 | 5 | ## Packages 6 | 7 | [DAOcreator UI (v1)](./packages/ui_v1/README.md) 8 | [DAOcreator Core Library](./packages/lib/README.md) 9 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["./packages/*"], 3 | "npmClient": "yarn", 4 | "useWorkspaces": true, 5 | "version": "1.0.0" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "version": "1.0.0", 5 | "scripts": { 6 | "start:v1": "lerna exec --scope @dorgtech/daocreator-ui-v1 -- yarn start", 7 | "start:v2": "lerna exec --scope @dorgtech/daocreator-ui -- yarn start", 8 | "build": "lerna exec -- yarn build", 9 | "build:lib": "lerna exec --scope @dorgtech/daocreator-lib -- yarn build", 10 | "release:lib": "lerna exec --scope @dorgtech/daocreator-lib -- yarn release", 11 | "release:v1": "lerna exec --scope @dorgtech/daocreator-ui-v1 -- yarn release", 12 | "release:v2": "lerna exec --scope @dorgtech/daocreator-ui -- yarn release" 13 | }, 14 | "devDependencies": { 15 | "lerna": "^3.18.4" 16 | }, 17 | "workspaces": { 18 | "packages": [ 19 | "./packages/*" 20 | ], 21 | "nohoist": [ 22 | "./packages/lib" 23 | ] 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/lib/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | ganache-accounts.json 24 | #/src/contracts/interfaces 25 | secret.json 26 | 27 | # vscode chrome debugger cache 28 | .vscode/chrome 29 | 30 | dist 31 | package 32 | -------------------------------------------------------------------------------- /packages/lib/README.md: -------------------------------------------------------------------------------- 1 | # DAOcreator Library 2 | 3 | Utility library for configuring and deploying DAOstack DAOs. 4 | 5 | ## Why? 6 | 7 | Configuring DAOstack DAOs can be confusing, and building a UI around that process is an even greater task. This library aims to implement all the necessary logic and data types (with sanitization) for the DAO's configuration and deployment process. This helps reduce the code needed for implementing new UI drastically, which will enable multiple DAOcreator experiences (Web UI, CLI, etc), without having to duplicate code. 8 | 9 | To see an existing UI that uses this library, see the [@dorgtech/daocreator-ui-v1](../ui_v1/) package. 10 | 11 | ## How? 12 | 13 | Documentation describing how to properly use this library will be added shortly. If you have any questions please reach out to anyone at dOrg (contact@dorg.tech). You can also look through the sample application linked above. [Here's a good place to start](../ui_v1/src/components/pages/DAOcreator/index.tsx). 14 | 15 | ## Project Architecture 16 | 17 | ### 3 Layers Of Data Types 18 | 19 | We view the different data types in this project as if they are in 3 layers: 20 | 21 | 1. _Form Data_ 22 | 2. _State Data_ 23 | 3. _Dependency Data_ 24 | 25 | Data in each layer can flow in either direction, 1 <> 2 <> 3. We did this to avoid as many **run-time type related errors** as possible, and to decouple our user-friendly form data from the backing state & dependency data. 26 | 27 | These type definitions can be found in: 28 | 29 | 1. `src/forms` 30 | 2. `src/state` 31 | 3. `src/dependency` 32 | 33 | Confused? So were we, that's why we wrote this... here's a brief description of each layer: 34 | 35 | - **Form Data**: Form classes that (1) take in user input data, (2) sanitized the data, and (3) convert it into a "state friendly" format. This layer also contains user friendly descriptions, which always remain outside of the state. 36 | 37 | - **State Data**: The core state of the application. 38 | 39 | - **Dependency Data**: These are types that are either provided by external dependencies, or created to make interacting with dependencies easier. These types should not be accessible to the project as a whole, they should be constrained to the dependency's module. This way we can easily change dependencies, and even add new ones without changing the top level interface! 40 | -------------------------------------------------------------------------------- /packages/lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dorgtech/daocreator-lib", 3 | "version": "1.0.2", 4 | "main": "dist/index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "prep:arc": "node scripts/prepArc.js", 8 | "build": "rimraf ./dist && tsc && copyfiles -u 1 src/**/*.js src/**/*.json dist", 9 | "package:release": "rm -rf ./package && mkdir ./package && cp -r ./dist/ ./package/dist && cp README.md package.json ./package && cp -r ./src ./package/src", 10 | "release": "yarn build && yarn package:release && yarn publish ./package --access public" 11 | }, 12 | "dependencies": { 13 | "bn.js": "^5.0.0", 14 | "csv": "^5.1.2", 15 | "csv-stringify": "^5.3.3", 16 | "formstate": "^1.3.0", 17 | "web3": "1.2.4", 18 | "jsonschema": "^1.2.5" 19 | }, 20 | "devDependencies": { 21 | "@daostack/migration": "0.0.1-rc.41-v7", 22 | "@types/bn.js": "^4.11.5", 23 | "@types/node": "^10.12.18", 24 | "@types/web3": "1.0.19", 25 | "copyfiles": "2.1.1", 26 | "ncp": "2.0.0", 27 | "rimraf": "^3.0.0", 28 | "typescript": "3.4.5" 29 | }, 30 | "peerDependencies": { 31 | "mobx": ">=5.11.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/lib/scripts/prepArc.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const ncp = require("ncp").ncp; 3 | const path = require("path"); 4 | const rimraf = require("rimraf"); 5 | const optimizer = require("@daostack/migration/optimize-abis"); 6 | 7 | async function optimizeABIs() { 8 | optimizer.initDirectory(); 9 | await optimizer.noBytecode(); 10 | await optimizer.noWhitespace(); 11 | } 12 | 13 | async function copyMigrationScript() { 14 | const toCopy = [ 15 | "migrate-dao.js", 16 | "utils.js", 17 | "sanitize.js", 18 | "migration.json", 19 | "contracts-optimized/0.0.1-rc.41" 20 | ]; 21 | const baseDir = path.dirname(require.resolve("@daostack/migration")); 22 | const destDir = path.join(__dirname, "../src/dependency/arc/src"); 23 | 24 | // Remove all existing files in the destination directory 25 | fs.readdirSync(destDir).forEach(file => { 26 | rimraf.sync(path.join(destDir, file)); 27 | }); 28 | 29 | // Copy all required files to the destination directory 30 | toCopy.forEach(async file => { 31 | await new Promise((resolve, reject) => { 32 | // Create nested folders if there are any 33 | const dest = path.join(destDir, file); 34 | const dir = path.dirname(dest); 35 | if (!fs.existsSync(dir)) { 36 | fs.mkdirSync(dir); 37 | } 38 | 39 | ncp(path.join(baseDir, file), dest, err => { 40 | if (err) { 41 | reject(err); 42 | } else { 43 | resolve(); 44 | } 45 | }); 46 | }); 47 | }); 48 | } 49 | 50 | async function run() { 51 | await optimizeABIs(); 52 | await copyMigrationScript(); 53 | } 54 | 55 | if (require.main === module) { 56 | run().catch(err => { 57 | console.log(err); 58 | process.exit(1); 59 | }); 60 | } else { 61 | module.exports = optimizeABIs; 62 | } 63 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | export * from "./migration"; 3 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/migration.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DAOMigrationParams, 3 | DAOMigrationCallbacks, 4 | DAOMigrationResult 5 | } from "./types"; 6 | import { getWeb3, getNetworkName, getDefaultOpts } from "../../dependency/web3"; 7 | 8 | const migrate = require("./src/migrate-dao"); 9 | const addresses = require("./src/migration.json"); 10 | 11 | export const migrateDAO = async ( 12 | dao: DAOMigrationParams, 13 | callbacks: DAOMigrationCallbacks 14 | ): Promise => { 15 | try { 16 | const web3 = await getWeb3(); 17 | const opts = await getDefaultOpts(); 18 | let network = await getNetworkName(); 19 | 20 | if (network === 'private') { 21 | if (await web3.eth.net.getId() === 100) { 22 | network = 'xdai' 23 | } else if (await web3.eth.net.getId() === 77) { 24 | network = 'sokol' 25 | } 26 | } 27 | 28 | const logTx = async ({ transactionHash, gasUsed }: any, msg: string) => { 29 | const tx = await web3.eth.getTransaction(transactionHash); 30 | 31 | if (tx != null) { 32 | const gasPrice = tx.gasPrice; 33 | const txCost = web3.utils.fromWei( 34 | (gasUsed * gasPrice).toString(), 35 | "ether" 36 | ); 37 | callbacks.txComplete(msg, transactionHash, txCost); 38 | } 39 | }; 40 | 41 | const sendTx = async ( 42 | tx: any, 43 | msg: string 44 | ): Promise<{ receipt: any; result: any }> => { 45 | callbacks.info(msg); 46 | 47 | let gas = 0; 48 | const nonce = await web3.eth.getTransactionCount(web3.eth.defaultAccount); 49 | const blockLimit = await web3.eth.getBlock("latest").gasLimit; 50 | 51 | try { 52 | gas = await tx.estimateGas(); 53 | if (gas * 1.1 < blockLimit - 100000) { 54 | gas *= 1.1; 55 | } 56 | } catch (error) { 57 | gas = blockLimit - 100000; 58 | } 59 | 60 | let result = tx.send({ gas, nonce }); 61 | let receipt = await new Promise(resolve => 62 | result.on("receipt", resolve).on("error", async (error: Error) => { 63 | callbacks.error("Transaction failed: " + error.message); 64 | resolve(); 65 | }) 66 | ); 67 | 68 | if (receipt === "failed") { 69 | return sendTx(tx, "Retrying..."); 70 | } 71 | 72 | result = await result; 73 | return { receipt, result }; 74 | }; 75 | 76 | const arcVersion = "0.0.1-rc.41"; 77 | const getArcVersionNumber = (ver: string) => Number(ver.slice(-2)); 78 | 79 | // If the user doesn't have a supported network chosen, abort 80 | if (addresses[network] === undefined) { 81 | throw Error( 82 | `The network you have chosen (${network}) isn't supported. ` + 83 | `Please select one of the supported networks: ${Object.keys( 84 | addresses 85 | )}` 86 | ); 87 | } 88 | 89 | // Get the stored deployment state, and ask the user if they'd like to 90 | // resume it (if one exists) 91 | const prevState = callbacks.getState(network); 92 | let restartDeployment = true; 93 | 94 | if (Object.keys(prevState).length > 0) { 95 | restartDeployment = !(await callbacks.userApproval( 96 | "We found a deployment that's was in progress, pickup where you left off?" 97 | )); 98 | } 99 | 100 | // Report back to caller the version of Arc being used 101 | callbacks.info(`Using Arc Version: ${arcVersion}`); 102 | 103 | const migration = await migrate({ 104 | arcVersion, 105 | getArcVersionNumber, 106 | migrationParams: dao, 107 | web3, 108 | spinner: { 109 | start: callbacks.info, 110 | fail: callbacks.error, 111 | succeed: callbacks.info 112 | }, 113 | confirm: callbacks.userApproval, 114 | logTx, 115 | sendTx, 116 | opts, 117 | previousMigration: { ...addresses[network] }, 118 | customabislocation: undefined, 119 | restart: restartDeployment, 120 | getState: callbacks.getState, 121 | setState: callbacks.setState, 122 | cleanState: callbacks.cleanState, 123 | optimizedAbis: true 124 | }); 125 | 126 | if (migration === undefined) { 127 | throw Error( 128 | "Something terrible has gone wrong! Please be sure to hit 'yes' on the prompts asking" + 129 | " for your approval. If this isn't your issue, please report this as a bug." 130 | ); 131 | } 132 | 133 | const result = migration!.dao[arcVersion]; 134 | console.log(result); 135 | 136 | return { 137 | arcVersion: arcVersion, 138 | name: result.name, 139 | Avatar: result.Avatar, 140 | DAOToken: result.DAOToken, 141 | Reputation: result.Reputation, 142 | Controller: result.Controller 143 | }; 144 | } catch (e) { 145 | callbacks.migrationAborted(e.message); 146 | return undefined; 147 | } 148 | }; 149 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/src/contracts-optimized/0.0.1-rc.41/CurveInterface.json: -------------------------------------------------------------------------------- 1 | {"contractName":"CurveInterface","abi":[{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"calc","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"}],"metadata":"{\"compiler\":{\"version\":\"0.5.13+commit.5b0b510c\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"calc\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/Users/oren/daostack/arc/contracts/schemes/CurveInterface.sol\":\"CurveInterface\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/Users/oren/daostack/arc/contracts/schemes/CurveInterface.sol\":{\"keccak256\":\"0x4e67086c005d04579132bf539abcf0f698a9db496a3478ce9cda6c54a379ee4c\",\"urls\":[\"bzz-raw://514910f66b7de63fa2d556211ce91550e0ab3337c8010a5b5a5e2598243a2107\",\"dweb:/ipfs/QmYycJYmPLrh5r3Uv65pACXM3Z28jSSKESFCfFqALdBi3j\"]}},\"version\":1}","sourceMap":"","deployedSourceMap":"","source":"pragma solidity 0.5.13;\n\ninterface CurveInterface {\n\n function calc(uint) external pure returns (uint);\n\n}\n","sourcePath":"/Users/oren/daostack/arc/contracts/schemes/CurveInterface.sol","ast":{"absolutePath":"/Users/oren/daostack/arc/contracts/schemes/CurveInterface.sol","exportedSymbols":{"CurveInterface":[6303]},"id":6304,"nodeType":"SourceUnit","nodes":[{"id":6295,"literals":["solidity","0.5",".13"],"nodeType":"PragmaDirective","src":"0:23:12"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":6303,"linearizedBaseContracts":[6303],"name":"CurveInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":6302,"implemented":false,"kind":"function","modifiers":[],"name":"calc","nodeType":"FunctionDefinition","parameters":{"id":6298,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6297,"name":"","nodeType":"VariableDeclaration","scope":6302,"src":"71:4:12","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":6296,"name":"uint","nodeType":"ElementaryTypeName","src":"71:4:12","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"70:6:12"},"returnParameters":{"id":6301,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6300,"name":"","nodeType":"VariableDeclaration","scope":6302,"src":"100:4:12","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":6299,"name":"uint","nodeType":"ElementaryTypeName","src":"100:4:12","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"99:6:12"},"scope":6303,"src":"57:49:12","stateMutability":"pure","superFunction":null,"visibility":"external"}],"scope":6304,"src":"25:84:12"}],"src":"0:110:12"},"legacyAST":{"absolutePath":"/Users/oren/daostack/arc/contracts/schemes/CurveInterface.sol","exportedSymbols":{"CurveInterface":[6303]},"id":6304,"nodeType":"SourceUnit","nodes":[{"id":6295,"literals":["solidity","0.5",".13"],"nodeType":"PragmaDirective","src":"0:23:12"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":6303,"linearizedBaseContracts":[6303],"name":"CurveInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":6302,"implemented":false,"kind":"function","modifiers":[],"name":"calc","nodeType":"FunctionDefinition","parameters":{"id":6298,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6297,"name":"","nodeType":"VariableDeclaration","scope":6302,"src":"71:4:12","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":6296,"name":"uint","nodeType":"ElementaryTypeName","src":"71:4:12","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"70:6:12"},"returnParameters":{"id":6301,"nodeType":"ParameterList","parameters":[{"constant":false,"id":6300,"name":"","nodeType":"VariableDeclaration","scope":6302,"src":"100:4:12","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":6299,"name":"uint","nodeType":"ElementaryTypeName","src":"100:4:12","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"99:6:12"},"scope":6303,"src":"57:49:12","stateMutability":"pure","superFunction":null,"visibility":"external"}],"scope":6304,"src":"25:84:12"}],"src":"0:110:12"},"compiler":{"name":"solc","version":"0.5.13+commit.5b0b510c.Emscripten.clang"},"networks":{},"schemaVersion":"3.0.20","updatedAt":"2020-02-10T15:44:06.112Z","devdoc":{"methods":{}},"userdoc":{"methods":{}}} -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/src/contracts-optimized/0.0.1-rc.41/PriceOracleInterface.json: -------------------------------------------------------------------------------- 1 | {"contractName":"PriceOracleInterface","abi":[{"constant":true,"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"getPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}],"metadata":"{\"compiler\":{\"version\":\"0.5.13+commit.5b0b510c\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":true,\"inputs\":[{\"internalType\":\"address\",\"name\":\"token\",\"type\":\"address\"}],\"name\":\"getPrice\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"/Users/oren/daostack/arc/contracts/schemes/PriceOracleInterface.sol\":\"PriceOracleInterface\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"/Users/oren/daostack/arc/contracts/schemes/PriceOracleInterface.sol\":{\"keccak256\":\"0x039506b7d17da35e14379bc12cb2896e11f527f89827f2abb5001dd32fff911b\",\"urls\":[\"bzz-raw://0d629d58127bcb1808e61152e3deb8e9381829316be5abc0fac4a363f6f1733f\",\"dweb:/ipfs/QmfRzBypSmVxWCuvPMFduxKv9sqBfJBxB5VXqmUi7Aw1EE\"]}},\"version\":1}","sourceMap":"","deployedSourceMap":"","source":"pragma solidity 0.5.13;\n\ninterface PriceOracleInterface {\n\n function getPrice(address token) external view returns (uint, uint);\n\n}\n","sourcePath":"/Users/oren/daostack/arc/contracts/schemes/PriceOracleInterface.sol","ast":{"absolutePath":"/Users/oren/daostack/arc/contracts/schemes/PriceOracleInterface.sol","exportedSymbols":{"PriceOracleInterface":[7860]},"id":7861,"nodeType":"SourceUnit","nodes":[{"id":7850,"literals":["solidity","0.5",".13"],"nodeType":"PragmaDirective","src":"0:23:20"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":7860,"linearizedBaseContracts":[7860],"name":"PriceOracleInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":7859,"implemented":false,"kind":"function","modifiers":[],"name":"getPrice","nodeType":"FunctionDefinition","parameters":{"id":7853,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7852,"name":"token","nodeType":"VariableDeclaration","scope":7859,"src":"81:13:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":7851,"name":"address","nodeType":"ElementaryTypeName","src":"81:7:20","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":null,"visibility":"internal"}],"src":"80:15:20"},"returnParameters":{"id":7858,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7855,"name":"","nodeType":"VariableDeclaration","scope":7859,"src":"119:4:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7854,"name":"uint","nodeType":"ElementaryTypeName","src":"119:4:20","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"},{"constant":false,"id":7857,"name":"","nodeType":"VariableDeclaration","scope":7859,"src":"125:4:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7856,"name":"uint","nodeType":"ElementaryTypeName","src":"125:4:20","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"118:12:20"},"scope":7860,"src":"63:68:20","stateMutability":"view","superFunction":null,"visibility":"external"}],"scope":7861,"src":"25:109:20"}],"src":"0:135:20"},"legacyAST":{"absolutePath":"/Users/oren/daostack/arc/contracts/schemes/PriceOracleInterface.sol","exportedSymbols":{"PriceOracleInterface":[7860]},"id":7861,"nodeType":"SourceUnit","nodes":[{"id":7850,"literals":["solidity","0.5",".13"],"nodeType":"PragmaDirective","src":"0:23:20"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":7860,"linearizedBaseContracts":[7860],"name":"PriceOracleInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":7859,"implemented":false,"kind":"function","modifiers":[],"name":"getPrice","nodeType":"FunctionDefinition","parameters":{"id":7853,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7852,"name":"token","nodeType":"VariableDeclaration","scope":7859,"src":"81:13:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":7851,"name":"address","nodeType":"ElementaryTypeName","src":"81:7:20","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"value":null,"visibility":"internal"}],"src":"80:15:20"},"returnParameters":{"id":7858,"nodeType":"ParameterList","parameters":[{"constant":false,"id":7855,"name":"","nodeType":"VariableDeclaration","scope":7859,"src":"119:4:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7854,"name":"uint","nodeType":"ElementaryTypeName","src":"119:4:20","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"},{"constant":false,"id":7857,"name":"","nodeType":"VariableDeclaration","scope":7859,"src":"125:4:20","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7856,"name":"uint","nodeType":"ElementaryTypeName","src":"125:4:20","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":null,"visibility":"internal"}],"src":"118:12:20"},"scope":7860,"src":"63:68:20","stateMutability":"view","superFunction":null,"visibility":"external"}],"scope":7861,"src":"25:109:20"}],"src":"0:135:20"},"compiler":{"name":"solc","version":"0.5.13+commit.5b0b510c.Emscripten.clang"},"networks":{},"schemaVersion":"3.0.20","updatedAt":"2020-02-10T15:44:06.131Z","devdoc":{"methods":{}},"userdoc":{"methods":{}}} -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/src/contracts-optimized/0.0.1-rc.41/ProposalExecuteInterface.json: -------------------------------------------------------------------------------- 1 | {"contractName":"ProposalExecuteInterface","abi":[{"constant":false,"inputs":[{"internalType":"bytes32","name":"_proposalId","type":"bytes32"},{"internalType":"int256","name":"_decision","type":"int256"}],"name":"executeProposal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}],"metadata":"{\"compiler\":{\"version\":\"0.5.13+commit.5b0b510c\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":false,\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_proposalId\",\"type\":\"bytes32\"},{\"internalType\":\"int256\",\"name\":\"_decision\",\"type\":\"int256\"}],\"name\":\"executeProposal\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol\":\"ProposalExecuteInterface\"},\"evmVersion\":\"petersburg\",\"libraries\":{},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[]},\"sources\":{\"@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol\":{\"keccak256\":\"0x2533e7b1e0ac8adb4c04968a4c5a02e56d1c9ae406a38c8591c36a24a3572f7c\",\"urls\":[\"bzz-raw://86c6cb4c9fae74235d2b5b602759c4459d739c1e69bf9ca39573a5f878f20106\",\"dweb:/ipfs/QmVtX6HGDGJzRs7CV9cLyNnS3egNYTcFWpCEQSDQb9YEoN\"]}},\"version\":1}","sourceMap":"","deployedSourceMap":"","source":"pragma solidity ^0.5.11;\n\ninterface ProposalExecuteInterface {\n function executeProposal(bytes32 _proposalId, int _decision) external returns(bool);\n}\n","sourcePath":"@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol","ast":{"absolutePath":"@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol","exportedSymbols":{"ProposalExecuteInterface":[19828]},"id":19829,"nodeType":"SourceUnit","nodes":[{"id":19818,"literals":["solidity","^","0.5",".11"],"nodeType":"PragmaDirective","src":"0:24:60"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":19828,"linearizedBaseContracts":[19828],"name":"ProposalExecuteInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":19827,"implemented":false,"kind":"function","modifiers":[],"name":"executeProposal","nodeType":"FunctionDefinition","parameters":{"id":19823,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19820,"name":"_proposalId","nodeType":"VariableDeclaration","scope":19827,"src":"92:19:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":19819,"name":"bytes32","nodeType":"ElementaryTypeName","src":"92:7:60","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"value":null,"visibility":"internal"},{"constant":false,"id":19822,"name":"_decision","nodeType":"VariableDeclaration","scope":19827,"src":"113:13:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":19821,"name":"int","nodeType":"ElementaryTypeName","src":"113:3:60","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"value":null,"visibility":"internal"}],"src":"91:36:60"},"returnParameters":{"id":19826,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19825,"name":"","nodeType":"VariableDeclaration","scope":19827,"src":"145:4:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":19824,"name":"bool","nodeType":"ElementaryTypeName","src":"145:4:60","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"value":null,"visibility":"internal"}],"src":"144:6:60"},"scope":19828,"src":"67:84:60","stateMutability":"nonpayable","superFunction":null,"visibility":"external"}],"scope":19829,"src":"26:127:60"}],"src":"0:154:60"},"legacyAST":{"absolutePath":"@daostack/infra/contracts/votingMachines/ProposalExecuteInterface.sol","exportedSymbols":{"ProposalExecuteInterface":[19828]},"id":19829,"nodeType":"SourceUnit","nodes":[{"id":19818,"literals":["solidity","^","0.5",".11"],"nodeType":"PragmaDirective","src":"0:24:60"},{"baseContracts":[],"contractDependencies":[],"contractKind":"interface","documentation":null,"fullyImplemented":false,"id":19828,"linearizedBaseContracts":[19828],"name":"ProposalExecuteInterface","nodeType":"ContractDefinition","nodes":[{"body":null,"documentation":null,"id":19827,"implemented":false,"kind":"function","modifiers":[],"name":"executeProposal","nodeType":"FunctionDefinition","parameters":{"id":19823,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19820,"name":"_proposalId","nodeType":"VariableDeclaration","scope":19827,"src":"92:19:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":19819,"name":"bytes32","nodeType":"ElementaryTypeName","src":"92:7:60","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"value":null,"visibility":"internal"},{"constant":false,"id":19822,"name":"_decision","nodeType":"VariableDeclaration","scope":19827,"src":"113:13:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"},"typeName":{"id":19821,"name":"int","nodeType":"ElementaryTypeName","src":"113:3:60","typeDescriptions":{"typeIdentifier":"t_int256","typeString":"int256"}},"value":null,"visibility":"internal"}],"src":"91:36:60"},"returnParameters":{"id":19826,"nodeType":"ParameterList","parameters":[{"constant":false,"id":19825,"name":"","nodeType":"VariableDeclaration","scope":19827,"src":"145:4:60","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":19824,"name":"bool","nodeType":"ElementaryTypeName","src":"145:4:60","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"value":null,"visibility":"internal"}],"src":"144:6:60"},"scope":19828,"src":"67:84:60","stateMutability":"nonpayable","superFunction":null,"visibility":"external"}],"scope":19829,"src":"26:127:60"}],"src":"0:154:60"},"compiler":{"name":"solc","version":"0.5.13+commit.5b0b510c.Emscripten.clang"},"networks":{},"schemaVersion":"3.0.20","updatedAt":"2020-02-10T15:44:06.265Z","devdoc":{"methods":{}},"userdoc":{"methods":{}}} -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/src/utils.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | function randomEl (list) { 4 | var i = Math.floor(Math.random() * list.length) 5 | return list[i] 6 | } 7 | 8 | var adjectives = ['adamant', 'adroit', 'amatory', 'animistic', 'antic', 'arcadian', 'baleful', 'bellicose', 'bilious', 'boorish', 'calamitous', 'caustic', 'cerulean', 'comely', 'concomitant', 'contumacious', 'corpulent', 'crapulous', 'defamatory', 'didactic', 'dilatory', 'dowdy', 'efficacious', 'effulgent', 'egregious', 'endemic', 'equanimous', 'execrable', 'fastidious', 'feckless', 'fecund', 'friable', 'fulsome', 'garrulous', 'guileless', 'gustatory', 'heuristic', 'histrionic', 'hubristic', 'incendiary', 'insidious', 'insolent', 'intransigent', 'inveterate', 'invidious', 'irksome', 'jejune', 'jocular', 'judicious', 'lachrymose', 'limpid', 'loquacious', 'luminous', 'mannered', 'mendacious', 'meretricious', 'minatory', 'mordant', 'munificent', 'nefarious', 'noxious', 'obtuse', 'parsimonious', 'pendulous', 'pernicious', 'pervasive', 'petulant', 'platitudinous', 'precipitate', 'propitious', 'puckish', 'querulous', 'quiescent', 'rebarbative', 'recalcitant', 'redolent', 'rhadamanthine', 'risible', 'ruminative', 'sagacious', 'salubrious', 'sartorial', 'sclerotic', 'serpentine', 'spasmodic', 'strident', 'taciturn', 'tenacious', 'tremulous', 'trenchant', 'turbulent', 'turgid', 'ubiquitous', 'uxorious', 'verdant', 'voluble', 'voracious', 'wheedling', 'withering', 'zealous'] 9 | var nouns = ['ninja', 'chair', 'pancake', 'statue', 'unicorn', 'rainbows', 'laser', 'senor', 'bunny', 'captain', 'nibblets', 'cupcake', 'carrot', 'gnomes', 'glitter', 'potato', 'salad', 'toejam', 'curtains', 'beets', 'toilet', 'exorcism', 'stick figures', 'mermaid eggs', 'sea barnacles', 'dragons', 'jellybeans', 'snakes', 'dolls', 'bushes', 'cookies', 'apples', 'ukulele', 'kazoo', 'banjo', 'opera singer', 'circus', 'trampoline', 'carousel', 'carnival', 'locomotive', 'hot air balloon', 'animator', 'artisan', 'artist', 'colorist', 'inker', 'coppersmith', 'director', 'designer', 'flatter', 'stylist', 'leadman', 'limner', 'make-up artist', 'model', 'musician', 'penciller', 'producer', 'scenographer', 'silversmith', 'teacher', 'beader', 'foreman', 'maintenance', 'engineering', 'mechanic', 'miller', 'moldmaker', 'panel beater', 'patternmaker', 'plant operator', 'plumber', 'sawfiler', 'shop foreman', 'soaper', 'wheelwright', 'woodworkers'] 10 | 11 | const capitalize = (s) => { 12 | if (typeof s !== 'string') return '' 13 | return s.charAt(0).toUpperCase() + s.slice(1) 14 | } 15 | 16 | exports.generateRnadomName = function () { 17 | return capitalize(randomEl(adjectives)) + ' ' + capitalize(randomEl(nouns)) 18 | } 19 | 20 | exports.importAbi = function (abiPath) { 21 | let abi = require(`${abiPath}`) 22 | if (abi.rootVersion) { 23 | const abiName = abiPath.substring(abiPath.lastIndexOf('/') + 1) 24 | const abiFolder = path.dirname(abiPath) 25 | const rootPath = path.join( 26 | abiFolder, `../${abi.rootVersion}/${abiName}` 27 | ) 28 | abi = require(`./${rootPath}`) 29 | } 30 | return abi 31 | } 32 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Address } from "../../../dependency/web3"; 2 | 3 | export * from "./schemes"; 4 | export * from "./votingMachines"; 5 | export * from "./migration"; 6 | 7 | export interface DAOConfig { 8 | daoName: string; 9 | tokenName: string; 10 | tokenSymbol: string; 11 | } 12 | 13 | export interface Member { 14 | address: Address; 15 | reputation: number; 16 | tokens: number | undefined; 17 | } 18 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/types/migration.ts: -------------------------------------------------------------------------------- 1 | import { Member, GenesisProtocolConfig } from "./index"; 2 | import { Address } from "../../../dependency/web3"; 3 | 4 | export interface DAOMigrationParams { 5 | orgName: string; 6 | tokenName: string; 7 | tokenSymbol: string; 8 | VotingMachinesParams: GenesisProtocolConfig[]; 9 | schemes: { 10 | ContributionReward?: boolean; 11 | SchemeRegistrar?: boolean; 12 | }; 13 | ContributionReward?: { 14 | voteParams?: number; 15 | }[]; 16 | SchemeRegistrar?: { 17 | voteRegisterParams?: number; 18 | voteRemoveParams?: number; 19 | }[]; 20 | unregisterOwner: boolean; 21 | useUController: boolean; 22 | useDaoCreator: boolean; 23 | founders: Member[]; 24 | } 25 | 26 | export interface DAOMigrationResult { 27 | arcVersion: string; 28 | name: string; 29 | Avatar: Address; 30 | DAOToken: Address; 31 | Reputation: Address; 32 | Controller: Address; 33 | } 34 | 35 | export interface DAOMigrationCallbacks { 36 | userApproval: (msg: string) => Promise; 37 | info: (msg: string) => void; 38 | error: (msg: string) => void; 39 | txComplete: (msg: string, txHash: string, txCost: number) => Promise; 40 | migrationAborted: (err: Error) => void; 41 | migrationComplete: (result: DAOMigrationResult) => void; 42 | getState: (network: string) => any; 43 | setState: (state: any, network: string) => void; 44 | cleanState: (network: string) => void; 45 | } 46 | 47 | export const toJSON = (params: DAOMigrationParams): string => { 48 | return JSON.stringify(params, null, 2); 49 | }; 50 | 51 | export const fromJSON = (params: string): DAOMigrationParams => { 52 | return JSON.parse(params); 53 | }; 54 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/types/schemes.ts: -------------------------------------------------------------------------------- 1 | import { VotingMachine } from "./index"; 2 | import { Address } from "../../../dependency/web3"; 3 | 4 | export enum SchemeType { 5 | ContributionReward, 6 | SchemeRegistrar 7 | } 8 | 9 | export interface Scheme { 10 | type: SchemeType; 11 | permissions: string; 12 | votingMachine: VotingMachine; 13 | } 14 | 15 | export class ContributionReward implements Scheme { 16 | type = SchemeType.ContributionReward; 17 | permissions: string = "0x00000000"; 18 | votingMachine: VotingMachine; 19 | 20 | constructor(votingMachine: VotingMachine) { 21 | this.votingMachine = votingMachine; 22 | } 23 | } 24 | 25 | // TODO: support multiple voting machine configurations 26 | export class SchemeRegistrar implements Scheme { 27 | type = SchemeType.SchemeRegistrar; 28 | permissions: string = "0x0000001F"; 29 | votingMachine: VotingMachine; 30 | 31 | constructor(votingMachine: VotingMachine) { 32 | this.votingMachine = votingMachine; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/arc/types/votingMachines.ts: -------------------------------------------------------------------------------- 1 | import { Address } from "../../../dependency/web3"; 2 | 3 | export interface VotingMachine { 4 | typeName: string; 5 | } 6 | 7 | export interface GenesisProtocolConfig { 8 | queuedVoteRequiredPercentage: number; 9 | queuedVotePeriodLimit: number; 10 | thresholdConst: number; 11 | proposingRepReward: number; 12 | minimumDaoBounty: number; 13 | boostedVotePeriodLimit: number; 14 | daoBountyConst: number; 15 | activationTime: number; 16 | preBoostedVotePeriodLimit: number; 17 | quietEndingPeriod: number; 18 | voteOnBehalf: Address; 19 | votersReputationLossRatio: number; 20 | } 21 | 22 | export enum GenesisProtocolPreset { 23 | Easy = 1, 24 | Normal, 25 | Critical 26 | } 27 | 28 | export interface GenesisProtocolOpts { 29 | config?: GenesisProtocolConfig; 30 | preset?: GenesisProtocolPreset; 31 | } 32 | 33 | export class GenesisProtocol implements VotingMachine { 34 | public typeName: string = "GenesisProtocol"; 35 | public config: GenesisProtocolConfig; 36 | public preset?: GenesisProtocolPreset; 37 | 38 | public static get EasyConfig(): GenesisProtocolConfig { 39 | return { 40 | boostedVotePeriodLimit: 129600, // 1.5 days 41 | daoBountyConst: 10, 42 | minimumDaoBounty: 50, // 50 GEN 43 | queuedVotePeriodLimit: 604800, // 7 days 44 | queuedVoteRequiredPercentage: 50, // 50% 45 | preBoostedVotePeriodLimit: 43200, // 12 hours 46 | proposingRepReward: 10, // 10 REP 47 | quietEndingPeriod: 86400, // 1 day 48 | thresholdConst: 1200, 49 | votersReputationLossRatio: 1, // 1% 50 | voteOnBehalf: "0x0000000000000000000000000000000000000000", 51 | activationTime: 0 52 | }; 53 | } 54 | 55 | public static get NormalConfig(): GenesisProtocolConfig { 56 | return { 57 | boostedVotePeriodLimit: 345600, // 4 days 58 | daoBountyConst: 10, 59 | minimumDaoBounty: 150, // 150 GEN 60 | queuedVotePeriodLimit: 2592000, // 30 days 61 | queuedVoteRequiredPercentage: 50, // 50% 62 | preBoostedVotePeriodLimit: 86400, // 1 day 63 | proposingRepReward: 50, // 50 REP 64 | quietEndingPeriod: 172800, // 2 day 65 | thresholdConst: 1200, 66 | votersReputationLossRatio: 4, // 4% 67 | voteOnBehalf: "0x0000000000000000000000000000000000000000", 68 | activationTime: 0 69 | }; 70 | } 71 | 72 | public static get CriticalConfig(): GenesisProtocolConfig { 73 | return { 74 | boostedVotePeriodLimit: 691200, // 8 days 75 | daoBountyConst: 10, 76 | minimumDaoBounty: 500, // 500 GEN 77 | queuedVotePeriodLimit: 5184000, // 60 days 78 | queuedVoteRequiredPercentage: 50, // 50% 79 | preBoostedVotePeriodLimit: 172800, // 2 day 80 | proposingRepReward: 200, // 200 REP 81 | quietEndingPeriod: 345600, // 4 day 82 | thresholdConst: 1500, 83 | votersReputationLossRatio: 4, // 4% 84 | voteOnBehalf: "0x0000000000000000000000000000000000000000", 85 | activationTime: 0 86 | }; 87 | } 88 | 89 | constructor(opts: GenesisProtocolOpts) { 90 | if (opts.preset) { 91 | if (typeof opts.preset === "string") { 92 | opts.preset = Number(opts.preset); 93 | } 94 | 95 | this.preset = opts.preset; 96 | 97 | switch (opts.preset) { 98 | case GenesisProtocolPreset.Easy: 99 | this.config = GenesisProtocol.EasyConfig; 100 | break; 101 | case GenesisProtocolPreset.Normal: 102 | this.config = GenesisProtocol.NormalConfig; 103 | break; 104 | case GenesisProtocolPreset.Critical: 105 | this.config = GenesisProtocol.CriticalConfig; 106 | break; 107 | default: 108 | throw Error("Preset not implemented."); 109 | } 110 | } else if (opts.config) { 111 | this.config = opts.config; 112 | } else { 113 | throw Error( 114 | "Invalid construction arguments. Please use a custom config or a preset." 115 | ); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/web3/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "ethjs-unit"; 2 | declare module "web3-utils"; 3 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/web3/index.ts: -------------------------------------------------------------------------------- 1 | import BN from "bn.js"; 2 | import Web3 from "web3"; 3 | import * as typeValidation from "./typeValidation"; 4 | import * as typeConversion from "./typeConversion"; 5 | 6 | export * from "./types"; 7 | export const TypeValidation = typeValidation; 8 | export const TypeConversion = typeConversion; 9 | 10 | export type ProviderOrGetter = any | (() => Promise); 11 | let web3Provider: ProviderOrGetter; 12 | 13 | export const setWeb3Provider = (providerOrGetter: ProviderOrGetter) => { 14 | web3Provider = providerOrGetter; 15 | }; 16 | 17 | export const getWeb3 = async (): Promise => { 18 | let readyWeb3; 19 | 20 | // Default behaviour is to look for an injected 21 | // web3 instance in the window 22 | const ethereum = (window as any).ethereum; 23 | const web3 = (window as any).web3; 24 | 25 | // Ignore the window injection if a specific getter has 26 | // been set. 27 | if (web3Provider) { 28 | let provider = web3Provider; 29 | if (typeof provider === "function") { 30 | provider = await provider(); 31 | } 32 | readyWeb3 = new Web3(provider); 33 | } else if (ethereum) { 34 | try { 35 | // Request account access if needed 36 | await ethereum.enable(); 37 | 38 | // Acccounts now exposed 39 | readyWeb3 = new Web3(ethereum); 40 | } catch (error) { 41 | return Promise.reject("User denied account access..."); 42 | } 43 | } 44 | // Legacy dapp browsers... 45 | else if (web3) { 46 | readyWeb3 = new Web3(web3.currentProvider); 47 | } 48 | // Non-dapp browsers... 49 | else { 50 | return Promise.reject( 51 | "Non-Ethereum browser detected. You should consider trying MetaMask!" 52 | ); 53 | } 54 | 55 | const accounts = await readyWeb3.eth.getAccounts(); 56 | readyWeb3.eth.defaultAccount = accounts[0]; 57 | 58 | return readyWeb3; 59 | }; 60 | 61 | export const getDefaultOpts = async (): Promise => { 62 | const web3 = await getWeb3(); 63 | const block = await web3.eth.getBlock("latest"); 64 | return { 65 | from: web3.eth.defaultAccount, 66 | gas: block.gasLimit - 100000, 67 | gasPrice: web3.utils.toWei("7", "gwei") 68 | }; 69 | }; 70 | 71 | export const getNetworkName = async (): Promise => { 72 | const web3 = await getWeb3(); 73 | let network = await web3.eth.net.getNetworkType(); 74 | 75 | if (network === "main") { 76 | network = "mainnet"; 77 | } 78 | 79 | return network; 80 | }; 81 | 82 | export const keccak256 = (value: string | BN): string => { 83 | const web3 = new Web3(); 84 | 85 | if (typeof value === "string") { 86 | return web3.utils.keccak256(value); 87 | } else { 88 | return web3.utils.keccak256(value.toString()); 89 | } 90 | }; 91 | 92 | export const encodeParameters = ( 93 | types: string[], 94 | parameters: any[] 95 | ): string => { 96 | const web3 = new Web3(); 97 | return web3.eth.abi.encodeParameters(types, parameters); 98 | }; 99 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/web3/typeConversion.ts: -------------------------------------------------------------------------------- 1 | import * as EthJsUnits from "ethjs-unit"; 2 | import BN from "bn.js"; 3 | 4 | type Endianness = "le" | "be"; 5 | export const toBN = ( 6 | number: number | string | number[] | Uint8Array | Buffer | BN, 7 | base?: number | "hex", 8 | endian?: Endianness 9 | ) => new BN(number, base, endian); 10 | 11 | export const fromWei = (wei: BN): string => EthJsUnits.fromWei(wei, "ether"); 12 | export const toWei = (eth: BN): string => EthJsUnits.toWei(eth, "ether"); 13 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/web3/typeValidation.ts: -------------------------------------------------------------------------------- 1 | import * as Web3Utils from "web3-utils"; 2 | import { Address } from "./types"; 3 | 4 | export const isAddress = (address: Address): boolean => { 5 | const addr = address.toLowerCase(); 6 | return addr[0] === "0" && addr[1] === "x" && Web3Utils.isAddress(addr); 7 | }; 8 | 9 | export const isBN = (number: Object): boolean => { 10 | return Web3Utils.isBN(number); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/lib/src/dependency/web3/types.ts: -------------------------------------------------------------------------------- 1 | export type Address = string; 2 | -------------------------------------------------------------------------------- /packages/lib/src/forms/Field.ts: -------------------------------------------------------------------------------- 1 | import { FieldState } from "formstate"; 2 | import { 3 | StringField, 4 | NumberField, 5 | TokenField, 6 | DateTimeField, 7 | DurationField, 8 | AddressField, 9 | PercentageField 10 | } from "../forms"; 11 | 12 | export enum FieldType { 13 | String, 14 | Number, 15 | Token, 16 | DateTime, 17 | Duration, 18 | Address, 19 | Percentage 20 | } 21 | 22 | export type AnyField = 23 | | StringField 24 | | NumberField 25 | | TokenField 26 | | DateTimeField 27 | | DurationField 28 | | AddressField 29 | | PercentageField; 30 | 31 | export abstract class Field< 32 | ValueType, 33 | DerivedType extends Field 34 | > extends FieldState { 35 | private _description: string = ""; 36 | private _displayName: string = ""; 37 | private _story: string = ""; 38 | private _type: FieldType; 39 | 40 | constructor(init: ValueType, type: FieldType) { 41 | super(init); 42 | this._type = type; 43 | } 44 | 45 | setDescription(description: string): DerivedType { 46 | this._description = description; 47 | return (this as any) as DerivedType; 48 | } 49 | 50 | get description(): string { 51 | return this._description; 52 | } 53 | 54 | setDisplayName(displayName: string): DerivedType { 55 | this._displayName = displayName; 56 | return (this as any) as DerivedType; 57 | } 58 | 59 | get displayName(): string { 60 | return this._displayName; 61 | } 62 | 63 | setStory(story: string): DerivedType { 64 | this._story = story; 65 | return (this as any) as DerivedType; 66 | } 67 | 68 | get story(): string { 69 | return this._story; 70 | } 71 | 72 | get type(): FieldType { 73 | return this._type; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/lib/src/forms/Form.ts: -------------------------------------------------------------------------------- 1 | import { FormState, ValidatableMapOrArray } from "formstate"; 2 | 3 | export abstract class Form< 4 | StateType, 5 | T extends ValidatableMapOrArray 6 | > extends FormState { 7 | public abstract toState(): StateType; 8 | public abstract fromState(state: StateType): void; 9 | 10 | private _description: string = ""; 11 | private _displayName: string = ""; 12 | 13 | setDescription(description: string): Form { 14 | this._description = description; 15 | return this; 16 | } 17 | 18 | get description(): string { 19 | return this._description; 20 | } 21 | 22 | setDisplayName(displayName: string): Form { 23 | this._displayName = displayName; 24 | return this; 25 | } 26 | 27 | get displayName(): string { 28 | return this._displayName; 29 | } 30 | 31 | setValues(values: { [key in keyof T]?: any }): Form { 32 | // iterate through all the possible keys 33 | for (let [key, value] of Object.entries(values)) { 34 | const field = (this.$ as any)[key]; 35 | // if it's a FieldState, it has the property "value" 36 | if ((field as Object).hasOwnProperty("value")) { 37 | field.value = value; 38 | } else { 39 | (this.$ as any)[key] = value; 40 | } 41 | } 42 | return this; 43 | } 44 | 45 | get values(): { [key in keyof T]: any } { 46 | let values: any = {}; 47 | 48 | for (let [key, value] of Object.entries(this.$)) { 49 | if ((value as Object).hasOwnProperty("value")) { 50 | values[key] = value.value; 51 | } else { 52 | values[key] = value; 53 | } 54 | } 55 | 56 | return values; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/DAOConfigForm.ts: -------------------------------------------------------------------------------- 1 | import { Form } from "../../forms/Form"; 2 | import { 3 | StringField, 4 | requiredText, 5 | validTokenSymbol, 6 | validName 7 | } from "../../forms"; 8 | import { DAOConfig } from "../../dependency/arc"; 9 | 10 | export class DAOConfigForm extends Form< 11 | DAOConfig, 12 | { 13 | daoName: StringField; 14 | tokenName: StringField; 15 | tokenSymbol: StringField; 16 | } 17 | > { 18 | constructor(form?: DAOConfigForm) { 19 | super({ 20 | daoName: new StringField(form ? form.$.daoName.value : "") 21 | .validators(requiredText, validName) 22 | .setDisplayName("DAO Name") 23 | .setDescription( 24 | "Your organization’s name (cannot be changed after launch)." 25 | ), 26 | 27 | tokenName: new StringField(form ? form.$.tokenName.value : "") 28 | .validators(requiredText, validName) 29 | .setDisplayName("Token Name") 30 | .setDescription("The name of the DAO's token."), 31 | 32 | tokenSymbol: new StringField(form ? form.$.tokenSymbol.value : "") 33 | .validators(requiredText, validTokenSymbol) 34 | .setDisplayName("Token Symbol") 35 | .setDescription( 36 | "Abbreviation to identify your organization’s token (cannot be changed after launch)." 37 | ) 38 | }); 39 | } 40 | 41 | public toState(): DAOConfig { 42 | return { 43 | daoName: this.$.daoName.value, 44 | tokenName: this.$.tokenName.value, 45 | tokenSymbol: this.$.tokenSymbol.value 46 | }; 47 | } 48 | 49 | public fromState(state: DAOConfig) { 50 | this.$.daoName.value = state.daoName; 51 | this.$.tokenName.value = state.tokenName; 52 | this.$.tokenSymbol.value = state.tokenSymbol; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/DAOForm.ts: -------------------------------------------------------------------------------- 1 | import { Form } from "../../forms/Form"; 2 | import { DAOConfigForm, MembersForm, SchemesForm } from "../../forms"; 3 | import { DAOcreatorState, fromDAOMigrationParams } from "../../state"; 4 | import { fromJSON, DAOMigrationParams } from "../../dependency/arc"; 5 | 6 | export class DAOForm extends Form< 7 | DAOcreatorState, 8 | { 9 | config: DAOConfigForm; 10 | members: MembersForm; 11 | schemes: SchemesForm; 12 | } 13 | > { 14 | constructor(form?: DAOForm) { 15 | const daoConfig = new DAOConfigForm(form ? form.$.config : undefined); 16 | const getDAOTokenSymbol = () => daoConfig.$.tokenSymbol.value; 17 | 18 | super({ 19 | config: daoConfig, 20 | members: new MembersForm( 21 | getDAOTokenSymbol, 22 | form ? form.$.members : undefined 23 | ), 24 | schemes: new SchemesForm(form ? form.$.schemes : undefined) 25 | }); 26 | } 27 | 28 | public toState(): DAOcreatorState { 29 | return { 30 | config: this.$.config.toState(), 31 | members: this.$.members.toState(), 32 | schemes: this.$.schemes.toState() 33 | }; 34 | } 35 | 36 | public fromState(state: DAOcreatorState) { 37 | this.$.config.fromState(state.config); 38 | this.$.members.fromState(state.members); 39 | this.$.schemes.fromState(state.schemes); 40 | } 41 | 42 | public async fromMigrationParamsFile(file: File): Promise { 43 | const fileReader = new FileReader(); 44 | fileReader.readAsText(file); 45 | 46 | await new Promise( 47 | (resolve, reject) => (fileReader.onloadend = () => resolve()) 48 | ); 49 | 50 | if (fileReader.result === null) { 51 | throw Error("Unaable to read file."); 52 | } 53 | 54 | const json = fileReader.result as string | ArrayBuffer; 55 | let params: DAOMigrationParams; 56 | 57 | if (typeof json === "string") { 58 | params = fromJSON(json as string); 59 | } else { 60 | const decoder = new TextDecoder(); 61 | params = fromJSON(decoder.decode(json as ArrayBuffer)); 62 | } 63 | 64 | this.fromState(fromDAOMigrationParams(params)); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/MemberForm.ts: -------------------------------------------------------------------------------- 1 | import { Form } from "../../forms/Form"; 2 | import { 3 | TokenField, 4 | AddressField, 5 | requiredText, 6 | validAddress, 7 | validNumber, 8 | requireElement, 9 | noDuplicates, 10 | nonZeroAddress, 11 | greaterThanOrEqual 12 | } from "../../forms"; 13 | import { Member } from "../../dependency/arc"; 14 | import csvParse from "csv-parse"; 15 | import csvStringify from "csv-stringify"; 16 | 17 | export class MemberForm extends Form< 18 | Member, 19 | { 20 | address: AddressField; 21 | reputation: TokenField; 22 | tokens: TokenField; 23 | } 24 | > { 25 | private _getDAOTokenSymbol: () => string; 26 | 27 | get getDAOTokenSymbol() { 28 | return this._getDAOTokenSymbol; 29 | } 30 | 31 | constructor(getDAOTokenSymbol: () => string, form?: MemberForm) { 32 | super({ 33 | address: new AddressField(form ? form.$.address.value : "") 34 | .validators(requiredText, validAddress, nonZeroAddress) 35 | .setDisplayName("Address") 36 | .setDescription("The member's public address."), 37 | 38 | reputation: new TokenField("REP", form ? form.$.reputation.value : "") 39 | .validators(requiredText, validNumber, greaterThanOrEqual(0)) 40 | .setDisplayName("Reputation") 41 | .setDescription( 42 | "The member's reputation (voting power) within the DAO." 43 | ), 44 | 45 | tokens: new TokenField(getDAOTokenSymbol, form ? form.$.tokens.value : "") 46 | .validators(requiredText, validNumber, greaterThanOrEqual(0)) 47 | .setDisplayName("Tokens") 48 | .setDescription("The number of DAO tokens this member owns.") 49 | }); 50 | 51 | this._getDAOTokenSymbol = getDAOTokenSymbol; 52 | } 53 | 54 | public toState(): Member { 55 | return { 56 | address: this.$.address.value, 57 | tokens: Number(this.$.tokens.value), 58 | reputation: Number(this.$.reputation.value) 59 | }; 60 | } 61 | 62 | public fromState(state: Member) { 63 | this.$.address.value = state.address; 64 | this.$.reputation.value = state.reputation.toString(); 65 | this.$.tokens.value = state.tokens ? state.tokens.toString() : "0"; 66 | } 67 | } 68 | 69 | export class MembersForm extends Form { 70 | private _getDAOTokenSymbol: () => string; 71 | 72 | public get getDAOTokenSymbol(): () => string { 73 | return this._getDAOTokenSymbol; 74 | } 75 | 76 | constructor(getDAOTokenSymbol: () => string, form?: MembersForm) { 77 | super(form ? form.$ : ([] as MemberForm[])); 78 | this._getDAOTokenSymbol = getDAOTokenSymbol; 79 | this.validators( 80 | requireElement("Member"), 81 | noDuplicates( 82 | (a: MemberForm, b: MemberForm) => 83 | a.$.address.value.toLowerCase() === b.$.address.value.toLowerCase(), 84 | (value: MemberForm) => value.$.address.value 85 | ) 86 | ); 87 | } 88 | 89 | public toState(): Member[] { 90 | return this.$.map((member: MemberForm): Member => member.toState()); 91 | } 92 | 93 | public fromState(state: Member[]) { 94 | this.$ = state.map(member => { 95 | const memberForm = new MemberForm(this._getDAOTokenSymbol); 96 | memberForm.fromState(member); 97 | return memberForm; 98 | }); 99 | } 100 | 101 | public async fromCSV(file: File): Promise { 102 | const fileReader = new FileReader(); 103 | fileReader.readAsText(file); 104 | 105 | await new Promise( 106 | (resolve, reject) => (fileReader.onloadend = () => resolve()) 107 | ); 108 | 109 | const csv = fileReader.result; 110 | 111 | if (csv === null) { 112 | throw Error("Unable to read file."); 113 | } 114 | 115 | const parseCSV = (resolve: () => void, reject: (error: Error) => void) => ( 116 | error: Error | undefined, 117 | rows: any 118 | ) => { 119 | if (error !== undefined) { 120 | throw error; 121 | } 122 | 123 | if (!rows || rows.length === 0) { 124 | reject(new Error("Empty CSV")); 125 | return; 126 | } 127 | 128 | const colNames = Object.keys(rows[0]); 129 | 130 | // Verify all necessary columns are present 131 | let columns = ["address", "reputation", "tokens"]; 132 | 133 | for (const column of columns) { 134 | if (colNames.findIndex(name => column === name) === -1) { 135 | reject(new Error(`Missing '${name}' column.`)); 136 | return; 137 | } 138 | } 139 | 140 | rows.forEach(async (row: any, index: number) => { 141 | // Create the member 142 | const member = new MemberForm(this._getDAOTokenSymbol); 143 | member.$.address.value = row.address.replace(/\s/g, ""); 144 | member.$.reputation.value = row.reputation.replace(/\s/g, ""); 145 | member.$.tokens.value = row.tokens.replace(/\s/g, ""); 146 | 147 | // Validate the member 148 | const memberValidate = await member.validate(); 149 | if (memberValidate.hasError) { 150 | reject( 151 | new Error(`Invalid member on row ${index}. Error: ${member.error}`) 152 | ); 153 | return; 154 | } 155 | 156 | // Add the member to ourselves 157 | this.$.push(member); 158 | 159 | // Validate the collection 160 | await this.validate(); 161 | if (this.hasError) { 162 | reject( 163 | new Error( 164 | `Member on row ${index} is invalid within the collection. Error: ${this.error}` 165 | ) 166 | ); 167 | return; 168 | } 169 | 170 | if (index === rows.length - 1) { 171 | resolve(); 172 | } 173 | }); 174 | }; 175 | 176 | await new Promise((resolve, reject) => { 177 | csvParse( 178 | csv as string | Buffer, 179 | { columns: true }, 180 | parseCSV(resolve, reject) 181 | ); 182 | }); 183 | } 184 | 185 | public toCSV(): Promise { 186 | const csvData = [ 187 | ["address", "reputation", "tokens"], 188 | ...this.$.map(member => [ 189 | member.$.address.value, 190 | member.$.reputation.value, 191 | member.$.tokens.value 192 | ]) 193 | ]; 194 | 195 | return new Promise((resolve, reject) => { 196 | csvStringify(csvData, (err, output) => { 197 | if (output === undefined) { 198 | reject(new Error("CSV Stringify result should always be defined.")); 199 | } else { 200 | resolve(output); 201 | } 202 | }); 203 | }); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/SchemeForm.ts: -------------------------------------------------------------------------------- 1 | import { ValidatableMapOrArray } from "formstate"; 2 | import { Form } from "../../forms/Form"; 3 | import { 4 | AnyField, 5 | requireElement, 6 | ContributionRewardForm, 7 | SchemeRegistrarForm, 8 | GenesisProtocolForm 9 | } from "../../forms"; 10 | import { 11 | ContributionReward, 12 | SchemeRegistrar, 13 | SchemeType 14 | } from "../../state"; 15 | import { Scheme } from "../../dependency/arc"; 16 | 17 | export type AnySchemeForm = 18 | | ContributionRewardForm 19 | | SchemeRegistrarForm; 20 | 21 | export abstract class SchemeForm< 22 | StateType extends Scheme, 23 | T extends ValidatableMapOrArray & { votingMachine: GenesisProtocolForm } 24 | > extends Form { 25 | public abstract getParams(): AnyField[]; 26 | 27 | private _type: SchemeType; 28 | 29 | get type() { 30 | return this._type; 31 | } 32 | 33 | constructor(type: SchemeType, $: T) { 34 | super($); 35 | this._type = type; 36 | } 37 | } 38 | 39 | export class SchemesForm extends Form { 40 | constructor(form?: SchemesForm) { 41 | super(form ? form.$ : ([] as AnySchemeForm[])); 42 | 43 | this.validators(requireElement("Scheme")); 44 | } 45 | 46 | public toState(): Scheme[] { 47 | return this.$.map( 48 | (schemeForm: AnySchemeForm): Scheme => schemeForm.toState() 49 | ); 50 | } 51 | 52 | public fromState(state: Scheme[]) { 53 | this.$ = state.map(scheme => { 54 | let schemeForm: AnySchemeForm; 55 | 56 | switch (scheme.type) { 57 | case SchemeType.ContributionReward: 58 | schemeForm = new ContributionRewardForm(); 59 | schemeForm.fromState(scheme as ContributionReward); 60 | break; 61 | case SchemeType.SchemeRegistrar: 62 | schemeForm = new SchemeRegistrarForm(); 63 | schemeForm.fromState(scheme as SchemeRegistrar); 64 | break; 65 | default: 66 | throw Error(`Unimplemented SchemeType ${SchemeType[scheme.type]}`); 67 | } 68 | 69 | return schemeForm; 70 | }); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./DAOForm"; 2 | export * from "./DAOConfigForm"; 3 | export * from "./MemberForm"; 4 | export * from "./SchemeForm"; 5 | export * from "./schemes"; 6 | export * from "./GenesisProtocolForm"; 7 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/schemes/ContributionRewardForm.ts: -------------------------------------------------------------------------------- 1 | import { SchemeForm } from "../../../forms/dao/SchemeForm"; 2 | import { AnyField, GenesisProtocolForm } from "../../../forms"; 3 | import { 4 | SchemeType, 5 | ContributionReward, 6 | GenesisProtocol, 7 | GenesisProtocolPreset 8 | } from "../../../state"; 9 | 10 | export class ContributionRewardForm extends SchemeForm< 11 | ContributionReward, 12 | { 13 | votingMachine: GenesisProtocolForm; 14 | } 15 | > { 16 | constructor(form?: ContributionRewardForm) { 17 | super(SchemeType.ContributionReward, { 18 | votingMachine: form 19 | ? form.$.votingMachine 20 | : new GenesisProtocolForm({ preset: GenesisProtocolPreset.Normal }) 21 | }); 22 | 23 | this.setDisplayName("Funding and Voting Power"); 24 | this.setDescription( 25 | "Contributors can propose rewards for themselves and others. These rewards can be tokens, reputation, or a combination." 26 | ); 27 | } 28 | 29 | public toState(): ContributionReward { 30 | return new ContributionReward(this.$.votingMachine.toState()); 31 | } 32 | 33 | public fromState(state: ContributionReward) { 34 | this.$.votingMachine.fromState(state.votingMachine as GenesisProtocol); 35 | } 36 | 37 | public getParams(): AnyField[] { 38 | return []; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/schemes/SchemeRegistrarForm.ts: -------------------------------------------------------------------------------- 1 | import { SchemeForm } from "../../../forms/dao/SchemeForm"; 2 | import { AnyField, GenesisProtocolForm } from "../../../forms"; 3 | import { 4 | SchemeType, 5 | SchemeRegistrar, 6 | GenesisProtocol, 7 | GenesisProtocolPreset 8 | } from "../../../state"; 9 | 10 | export class SchemeRegistrarForm extends SchemeForm< 11 | SchemeRegistrar, 12 | { 13 | votingMachine: GenesisProtocolForm; 14 | } 15 | > { 16 | constructor(form?: SchemeRegistrarForm) { 17 | super(SchemeType.SchemeRegistrar, { 18 | votingMachine: form 19 | ? form.$.votingMachine 20 | : new GenesisProtocolForm({ preset: GenesisProtocolPreset.Critical }) 21 | }); 22 | 23 | this.setDisplayName("Plugin Manager"); 24 | this.setDescription( 25 | "Manages post-creation adding/modifying/removing of plugins. Plugins add functionality to the DAO." 26 | ); 27 | } 28 | 29 | public toState(): SchemeRegistrar { 30 | return new SchemeRegistrar(this.$.votingMachine.toState()); 31 | } 32 | 33 | public fromState(state: SchemeRegistrar) { 34 | // TODO: support multiple voting machine types 35 | this.$.votingMachine.fromState(state.votingMachine as GenesisProtocol); 36 | } 37 | 38 | public getParams(): AnyField[] { 39 | return []; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/lib/src/forms/dao/schemes/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./ContributionRewardForm"; 2 | export * from "./SchemeRegistrarForm"; 3 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/AddressField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType } from "../../forms"; 2 | 3 | // TODO: add standard verifiers for known types 4 | export class AddressField extends Field { 5 | constructor(init: string) { 6 | super(init, FieldType.Address); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/DateTimeField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType } from "../../forms"; 2 | 3 | export class DateTimeField extends Field { 4 | constructor(init?: Date) { 5 | super(init, FieldType.DateTime); 6 | } 7 | 8 | public getunixTime(): number { 9 | if (this.value === undefined) { 10 | return 0; 11 | } 12 | 13 | // div by 1000 to convert to seconds 14 | return this.value.getTime() / 1000; 15 | } 16 | 17 | public fromUnixTime(unix: number): void { 18 | if (unix === 0) { 19 | // now 20 | this.value = undefined; 21 | } else { 22 | // mul by 1000 to convert to milliseconds 23 | this.value = new Date(unix * 1000); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/DurationField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType, validDuration, positiveDuration } from "../../forms"; 2 | 3 | // TODO: enforce formatting 4 | // Format: DD:hh:mm:ss 5 | export class DurationField extends Field { 6 | get days(): number { 7 | const parts = this.value.split(":"); 8 | return Number(parts[0]); 9 | } 10 | 11 | get hours(): number { 12 | const parts = this.value.split(":"); 13 | return Number(parts[1]); 14 | } 15 | 16 | get minutes(): number { 17 | const parts = this.value.split(":"); 18 | return Number(parts[2]); 19 | } 20 | 21 | get seconds(): number { 22 | const parts = this.value.split(":"); 23 | return Number(parts[3]); 24 | } 25 | 26 | constructor(init: string) { 27 | super(init, FieldType.Duration); 28 | this.validators(validDuration, positiveDuration); 29 | } 30 | 31 | // TODO: put these constants somewhere (86400, 3600, etc) 32 | public toSeconds(): number { 33 | const parts = this.value.split(":"); 34 | const days = Number(parts[0]); 35 | const hours = Number(parts[1]); 36 | const minutes = Number(parts[2]); 37 | const seconds = Number(parts[3]); 38 | 39 | return days * 86400 + hours * 3600 + minutes * 60 + seconds; 40 | } 41 | 42 | public fromSeconds(seconds: number): void { 43 | const days = Math.trunc(seconds / 86400); 44 | seconds -= days * 86400; 45 | const hours = Math.trunc(seconds / 3600); 46 | seconds -= hours * 3600; 47 | const minutes = Math.trunc(seconds / 60); 48 | seconds -= minutes * 60; 49 | seconds = Math.trunc(seconds); 50 | this.value = `${days}:${hours}:${minutes}:${seconds}`; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/NumberField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType, validNumber } from "../../forms"; 2 | 3 | export class NumberField extends Field { 4 | constructor(init: string) { 5 | super(init, FieldType.Number); 6 | this.validators(validNumber); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/PercentageField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType, validPercentage } from "../../forms"; 2 | 3 | export class PercentageField extends Field { 4 | constructor(init: number) { 5 | super(init, FieldType.Percentage); 6 | this.validators(validPercentage); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/StringField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType } from "../../forms"; 2 | 3 | export class StringField extends Field { 4 | constructor(init: string) { 5 | super(init, FieldType.String); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/TokenField.ts: -------------------------------------------------------------------------------- 1 | import { Field, FieldType } from "../../forms"; 2 | 3 | export class TokenField extends Field { 4 | private _symbol: string | (() => string); 5 | 6 | constructor(symbol: string | (() => string), init: string) { 7 | super(init, FieldType.Token); 8 | this._symbol = symbol; 9 | } 10 | 11 | get symbol(): string { 12 | if (typeof this._symbol === "string") { 13 | return this._symbol as string; 14 | } else { 15 | return this._symbol(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/lib/src/forms/fields/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./AddressField"; 2 | export * from "./DateTimeField"; 3 | export * from "./DurationField"; 4 | export * from "./PercentageField"; 5 | export * from "./StringField"; 6 | export * from "./TokenField"; 7 | export * from "./NumberField"; 8 | -------------------------------------------------------------------------------- /packages/lib/src/forms/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./dao"; 2 | export * from "./Field"; 3 | export * from "./fields"; 4 | export * from "./validators"; 5 | -------------------------------------------------------------------------------- /packages/lib/src/forms/validators.ts: -------------------------------------------------------------------------------- 1 | import { Validator } from "formstate"; 2 | import { TypeValidation, TypeConversion } from "../dependency/web3"; 3 | 4 | type StringOrNull = string | null | undefined; 5 | 6 | export const requiredText: Validator = value => { 7 | const error = "This is required."; 8 | 9 | if (value == null || value.trim().length === 0) { 10 | return error; 11 | } 12 | 13 | return null; 14 | }; 15 | 16 | export const validAddress: Validator = value => { 17 | const error = "Please enter a valid address."; 18 | value = value.trim(); 19 | 20 | if (!TypeValidation.isAddress(value)) { 21 | return error; 22 | } 23 | 24 | return null; 25 | }; 26 | 27 | export const validTokenSymbol: Validator = value => { 28 | const error = "Must be all caps and 4 characters or less"; 29 | value = value.trim(); 30 | 31 | if (value.length > 4 || !/^[A-Z]+$/.test(value)) { 32 | return error; 33 | } 34 | 35 | return null; 36 | }; 37 | 38 | export const validBigNumber: Validator = value => { 39 | const error = "Please enter a valid whole number."; 40 | value = value.trim(); 41 | 42 | try { 43 | TypeConversion.toBN(value); 44 | } catch (e) { 45 | return error; 46 | } 47 | 48 | return null; 49 | }; 50 | 51 | export const validNumber: Validator = value => { 52 | value = value.trim(); 53 | 54 | const number = Number(value); 55 | 56 | if (isNaN(number)) { 57 | return "Please enter a valid number."; 58 | } 59 | 60 | // Serializes to exponential value 61 | if (number.toString().indexOf('e') > -1) { 62 | return "Please remove decimal places."; 63 | } 64 | 65 | return null; 66 | }; 67 | 68 | export const validName: Validator = value => { 69 | const error = "Names must be less than 70 characters."; 70 | value = value.trim(); 71 | 72 | if (value.length > 70) { 73 | return error; 74 | } 75 | 76 | return null; 77 | }; 78 | 79 | export const validPercentage: Validator = value => { 80 | const error = "Percentages must be between 0 and 100."; 81 | 82 | if (value > 100 || value < 0) { 83 | return error; 84 | } 85 | 86 | return null; 87 | }; 88 | 89 | export const validDuration: Validator = value => { 90 | const error = "Duration format is incorrect. Please use DD:hh:mm:ss"; 91 | value = value.trim(); 92 | const parts = value.split(":"); 93 | 94 | if (parts.length !== 4) { 95 | return error; 96 | } 97 | 98 | return null; 99 | }; 100 | 101 | export const positiveDuration: Validator = value => { 102 | let error = null; 103 | value = value.trim(); 104 | const parts = value.split(":"); 105 | 106 | parts.forEach((part, index) => { 107 | if (Number(part) < 0) { 108 | switch (index) { 109 | case 0: 110 | error = "Days cannot be negative."; 111 | return; 112 | case 1: 113 | error = "Hours cannot be negative."; 114 | return; 115 | case 2: 116 | error = "Minutes cannot be negative."; 117 | return; 118 | case 3: 119 | error = "Seconds cannot be negative."; 120 | return; 121 | default: 122 | throw Error("This should never happen."); 123 | } 124 | } 125 | }); 126 | 127 | return error; 128 | }; 129 | 130 | export const futureDate: Validator = value => { 131 | let error = "Date must be in the future."; 132 | const currentTime = new Date().getTime(); 133 | 134 | if (value && value.getTime() < currentTime) { 135 | return error; 136 | } 137 | 138 | return null; 139 | }; 140 | 141 | export const greaterThan = (bound: number) => (value: string | number) => { 142 | const error = `Number must be greater than ${bound}.`; 143 | 144 | if (typeof value === "number") { 145 | if (value > bound) { 146 | return null; 147 | } 148 | } else { 149 | value = value.trim(); 150 | 151 | if (validNumber(value) === null && Number(value) > bound) { 152 | return null; 153 | } 154 | } 155 | 156 | return error; 157 | }; 158 | 159 | export const greaterThanOrEqual = (bound: number) => ( 160 | value: string | number 161 | ) => { 162 | const error = `Number must be greater than or equal to ${bound}.`; 163 | 164 | if (typeof value === "number") { 165 | if (value >= bound) { 166 | return null; 167 | } 168 | } else { 169 | value = value.trim(); 170 | 171 | if (validNumber(value) === null && Number(value) >= bound) { 172 | return null; 173 | } 174 | } 175 | 176 | return error; 177 | }; 178 | 179 | export const lessThanOrEqual = (bound: number) => (value: string | number) => { 180 | const error = `Number must be less than or equal to ${bound}.`; 181 | 182 | if (typeof value === "number") { 183 | if (value >= bound) { 184 | return null; 185 | } 186 | } else { 187 | value = value.trim(); 188 | 189 | if (validNumber(value) === null && Number(value) <= bound) { 190 | return null; 191 | } 192 | } 193 | 194 | return error; 195 | }; 196 | 197 | export const minMaxInclusive = (min: number, max: number) => (value: string | number) => { 198 | const error = `Number must be between ${min} and ${max}.`; 199 | 200 | if (typeof value === "number") { 201 | if (value >= min && value <= max) { 202 | return null; 203 | } 204 | } else { 205 | value = value.trim(); 206 | 207 | if (validNumber(value) === null) { 208 | const number = Number(value); 209 | 210 | if (number >= min && number <= max) { 211 | return null; 212 | } 213 | } 214 | } 215 | 216 | return error; 217 | }; 218 | 219 | export const nonZeroAddress: Validator = value => { 220 | const error = "Address must not be zero."; 221 | value = value.trim(); 222 | 223 | if (value === "0x0000000000000000000000000000000000000000") { 224 | return error; 225 | } 226 | 227 | return null; 228 | }; 229 | 230 | export const requireElement = (elementName: string) => (array: any[]) => 231 | !array.length && `Please add a ${elementName}.`; 232 | 233 | export const noDuplicates = ( 234 | evaluate: (a: any, b: any) => boolean, 235 | toString: (value: any) => string 236 | ) => (array: any[]) => { 237 | for (let i = 0; i < array.length; ++i) { 238 | const a = array[i]; 239 | 240 | for (let k = 0; k < array.length; ++k) { 241 | if (k === i) continue; 242 | const b = array[k]; 243 | 244 | if (evaluate(a, b)) { 245 | return `Duplicate entry detected: ${toString(a)}`; 246 | } 247 | } 248 | } 249 | }; 250 | -------------------------------------------------------------------------------- /packages/lib/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./forms"; 2 | export * from "./state"; 3 | export { 4 | getNetworkName, 5 | getWeb3, 6 | setWeb3Provider, 7 | ProviderOrGetter 8 | } from "./dependency/web3"; 9 | export { migrateDAO, toJSON, fromJSON } from "./dependency/arc"; 10 | -------------------------------------------------------------------------------- /packages/lib/src/state.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DAOConfig, 3 | DAOMigrationParams, 4 | Member, 5 | Scheme, 6 | SchemeType, 7 | ContributionReward, 8 | SchemeRegistrar, 9 | GenesisProtocol 10 | } from "./dependency/arc"; 11 | export { 12 | SchemeType, 13 | ContributionReward, 14 | SchemeRegistrar, 15 | GenesisProtocol, 16 | GenesisProtocolPreset, 17 | DAOMigrationCallbacks, 18 | DAOMigrationParams, 19 | DAOMigrationResult 20 | } from "./dependency/arc"; 21 | 22 | export type DAOConfig = DAOConfig; 23 | export type Member = Member; 24 | export type Scheme = Scheme; 25 | 26 | export interface DAOcreatorState { 27 | config: DAOConfig; 28 | members: Member[]; 29 | schemes: Scheme[]; 30 | } 31 | 32 | export const toDAOMigrationParams = ( 33 | dao: DAOcreatorState 34 | ): DAOMigrationParams => { 35 | const { config, members, schemes } = dao; 36 | const params: DAOMigrationParams = { 37 | orgName: config.daoName, 38 | tokenName: config.tokenName, 39 | tokenSymbol: config.tokenSymbol, 40 | unregisterOwner: true, 41 | useUController: false, 42 | useDaoCreator: true, 43 | schemes: {}, 44 | VotingMachinesParams: [], 45 | founders: [] 46 | }; 47 | 48 | // schemes & voting machine params 49 | for (const scheme of schemes) { 50 | switch (scheme.type) { 51 | case SchemeType.ContributionReward: { 52 | if (!params.ContributionReward) { 53 | params.ContributionReward = []; 54 | } 55 | params.ContributionReward.push({ 56 | voteParams: params.VotingMachinesParams.length 57 | }); 58 | params.schemes.ContributionReward = true; 59 | break; 60 | } 61 | case SchemeType.SchemeRegistrar: { 62 | if (!params.SchemeRegistrar) { 63 | params.SchemeRegistrar = []; 64 | } 65 | params.SchemeRegistrar.push({ 66 | voteRegisterParams: params.VotingMachinesParams.length, 67 | voteRemoveParams: params.VotingMachinesParams.length 68 | }); 69 | params.schemes.SchemeRegistrar = true; 70 | break; 71 | } 72 | } 73 | 74 | const genProtocol = scheme.votingMachine as GenesisProtocol; 75 | params.VotingMachinesParams.push(genProtocol.config); 76 | } 77 | 78 | for (const member of members) { 79 | params.founders.push(member); 80 | } 81 | 82 | return params; 83 | }; 84 | 85 | export const fromDAOMigrationParams = ( 86 | params: DAOMigrationParams 87 | ): DAOcreatorState => { 88 | // config 89 | const config: DAOConfig = { 90 | daoName: params.orgName, 91 | tokenSymbol: params.tokenSymbol, 92 | tokenName: params.tokenName 93 | }; 94 | 95 | // members 96 | let members: Member[] = []; 97 | 98 | for (const member of params.founders) { 99 | members.push({ 100 | address: member.address, 101 | tokens: member.tokens ? member.tokens : 0, 102 | reputation: member.reputation 103 | }); 104 | } 105 | 106 | // schemes 107 | let schemes: Scheme[] = []; 108 | 109 | if (params.schemes) { 110 | Object.keys(params.schemes).forEach(type => { 111 | // TODO: support multiple schemes of a single type 112 | switch (type) { 113 | case "ContributionReward": 114 | if (params.schemes[type]) { 115 | const config = params.ContributionReward 116 | ? params.ContributionReward[0] 117 | : undefined; 118 | let index; 119 | 120 | if (config && config.voteParams) { 121 | index = config.voteParams; 122 | } else { 123 | index = 0; 124 | } 125 | 126 | const votingMachine = new GenesisProtocol({ 127 | config: params.VotingMachinesParams[index] 128 | }); 129 | schemes.push(new ContributionReward(votingMachine)); 130 | } 131 | break; 132 | case "SchemeRegistrar": 133 | if (params.schemes[type]) { 134 | const config = params.SchemeRegistrar 135 | ? params.SchemeRegistrar[0] 136 | : undefined; 137 | let index; 138 | 139 | if (config) { 140 | if (config.voteRegisterParams) { 141 | index = config.voteRegisterParams; 142 | } else if (config.voteRemoveParams) { 143 | index = config.voteRemoveParams; 144 | } else { 145 | index = 0; 146 | } 147 | } else { 148 | index = 0; 149 | } 150 | 151 | const votingMachine = new GenesisProtocol({ 152 | config: params.VotingMachinesParams[index] 153 | }); 154 | 155 | schemes.push(new SchemeRegistrar(votingMachine)); 156 | } 157 | break; 158 | default: 159 | break; 160 | } 161 | }); 162 | } 163 | 164 | return { 165 | config, 166 | members, 167 | schemes 168 | }; 169 | }; 170 | -------------------------------------------------------------------------------- /packages/lib/test/dao-params/dao-params-test-3.json: -------------------------------------------------------------------------------- 1 | { 2 | "orgName": "DAOcreator Test", 3 | "tokenName": "DAOcreator Test", 4 | "tokenSymbol": "TEST", 5 | "unregisterOwner": true, 6 | "useUController": false, 7 | "useDaoCreator": true, 8 | "schemes": { 9 | "ContributionReward": true, 10 | "SchemeRegistrar": true 11 | }, 12 | "VotingMachinesParams": [ 13 | { 14 | "queuedVoteRequiredPercentage": 50, 15 | "queuedVotePeriodLimit": 2592000, 16 | "thresholdConst": 1200, 17 | "proposingRepReward": 50, 18 | "minimumDaoBounty": 150, 19 | "boostedVotePeriodLimit": 345600, 20 | "daoBountyConst": 10, 21 | "activationTime": 0, 22 | "preBoostedVotePeriodLimit": 86400, 23 | "quietEndingPeriod": 172800, 24 | "voteOnBehalf": "0x0000000000000000000000000000000000000000", 25 | "votersReputationLossRatio": 4 26 | }, 27 | { 28 | "queuedVoteRequiredPercentage": 50, 29 | "queuedVotePeriodLimit": 5184000, 30 | "thresholdConst": 1500, 31 | "proposingRepReward": 200, 32 | "minimumDaoBounty": 500, 33 | "boostedVotePeriodLimit": 691200, 34 | "daoBountyConst": 10, 35 | "activationTime": 0, 36 | "preBoostedVotePeriodLimit": 172800, 37 | "quietEndingPeriod": 345600, 38 | "voteOnBehalf": "0x0000000000000000000000000000000000000000", 39 | "votersReputationLossRatio": 4 40 | }, 41 | { 42 | "queuedVoteRequiredPercentage": 50, 43 | "queuedVotePeriodLimit": 2592000, 44 | "thresholdConst": 1200, 45 | "proposingRepReward": 50, 46 | "minimumDaoBounty": 150, 47 | "boostedVotePeriodLimit": 345600, 48 | "daoBountyConst": 10, 49 | "activationTime": 0, 50 | "preBoostedVotePeriodLimit": 86400, 51 | "quietEndingPeriod": 172800, 52 | "voteOnBehalf": "0x0000000000000000000000000000000000000000", 53 | "votersReputationLossRatio": 4 54 | } 55 | ], 56 | "founders": [ 57 | { 58 | "address": "0xB1B7586656116D546033e3bAFF69BFcD6592225E", 59 | "tokens": 123, 60 | "reputation": 123 61 | }, 62 | { 63 | "address": "0x00FCaf8C715F4E8b4710a73fdCF9E729972612e3", 64 | "tokens": 123, 65 | "reputation": 123 66 | }, 67 | { 68 | "address": "0xE031152cC359B64e4e20a5984Af3F27B0E7332eE", 69 | "tokens": 222, 70 | "reputation": 222 71 | } 72 | ], 73 | "ContributionReward": [ 74 | { 75 | "voteParams": 0 76 | } 77 | ], 78 | "SchemeRegistrar": [ 79 | { 80 | "voteRegisterParams": 1, 81 | "voteRemoveParams": 1 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/bad-test.csv: -------------------------------------------------------------------------------- 1 | addres,reputation , tokens 2 | 0xB1B7586656116D546033e3bAFF69BFcD6592225E,1,10 3 | 0xb6d39386f1fa19179dc2ca31684a7a69fabe5551,2,50 4 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/bad-test2.csv: -------------------------------------------------------------------------------- 1 | addres,reputation , tokens 2 | 0xB1B7586656116D546033e3bAFF69BFcD6592225E,1,10 3 | 0xb6d39386f1fa19179dc2ca31684a7a69fabe5551,2,50 4 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/bad-test3.csv: -------------------------------------------------------------------------------- 1 | addres,reputation , tokens 2 | 0xB1B7586656116D546033e3bAFF69BFcD6592225E,1,10 3 | 0xb6d39386f1fa19179dc2ca31684a7a69fabe5551,2,50 4 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/test.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | 0xB1B7586656116D546033e3bAFF69BFcD6592225E,1,10 3 | 0xb6d39386f1fa19179dc2ca31684a7a69fabe5551,2,50 4 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/test2.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | 0x777f5591f0743b08701aa37eceaec82b0153f65b,3,3 3 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/test3.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | 0x123f5591f0743b08701aa37eceaec82b0153f65b,4,5 3 | 0x774f5591f0743b08701aa37eceaec82b0153f65b,5,5 4 | 0x771f5591f0743b08701aa37eceaec82b0153f65b,6,5 5 | 0xad3f5591f0743b08701aa37eceaec82b0153f65b,7,5 6 | 0xxa4f5591f0743b08701aa37eceaec82b0153f65b,8,5 7 | 0x441f5591f0743b08701aa37eceaec82b0153f65b,9,5 8 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/test4.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | b10afbb40e46ffe52b136b8c123ddd00833c65b0,1,10 3 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/testzero.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | 0xB1B7586656116D546033e3bAFF69BFcD6592225E,0,0 3 | 0xb6d39386f1fa19179dc2ca31684a7a69fabe5551,0,0 4 | -------------------------------------------------------------------------------- /packages/lib/test/members-csv/whitespace.csv: -------------------------------------------------------------------------------- 1 | address,reputation,tokens 2 | 0x5Db06acd673531218B 10430bA6dE9b69913Ad545 , 1 ,10 3 | -------------------------------------------------------------------------------- /packages/lib/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2016", "es2017", "dom", "esnext.asynciterable"], 5 | "module": "commonjs", 6 | "moduleResolution": "node", 7 | "declaration": true, 8 | "experimentalDecorators": true, 9 | "emitDecoratorMetadata": true, 10 | "outDir": "dist", 11 | "resolveJsonModule": true, 12 | "sourceMap": true, 13 | "strict": true, 14 | "suppressImplicitAnyIndexErrors": true, 15 | "typeRoots": ["node_modules/@types"], 16 | "skipLibCheck": true, 17 | "allowJs": false, 18 | "baseUrl": "src", 19 | "rootDirs": ["src"], 20 | "forceConsistentCasingInFileNames": true, 21 | "allowSyntheticDefaultImports": true, 22 | "esModuleInterop": true 23 | }, 24 | "include": ["src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/ui_v1/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | ganache-accounts.json 24 | #/src/contracts/interfaces 25 | secret.json 26 | 27 | # vscode chrome debugger cache 28 | .vscode/chrome 29 | 30 | dist 31 | package 32 | -------------------------------------------------------------------------------- /packages/ui_v1/README.md: -------------------------------------------------------------------------------- 1 | # DAOcreator UI (V1) 2 | 3 | Wizard for setting up your own DAOstack DAO. 4 | 5 | ## Contribute 6 | 7 | Welcome Fellow Contributors. Today We DAO. 8 | 9 | ### Installing 10 | 11 | `yarn` 12 | 13 | ### Running 14 | 15 | `yarn start` 16 | 17 | ### Debugging 18 | 19 | VS Code w/ Chrome 20 | 21 | 1. Install Extension "`Debugger for Chrome`" 22 | 2. Launch the app by running `npm run start`. 23 | 3. Press the green play button in the debug menu of VS Code. 24 | -------------------------------------------------------------------------------- /packages/ui_v1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dorgtech/daocreator-ui-v1", 3 | "version": "1.0.2", 4 | "main": "./dist/index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "react-scripts start", 8 | "build": "yarn build:package && yarn build:app", 9 | "eject": "react-scripts eject", 10 | "test": "react-scripts test", 11 | "build:app": "CI=false react-scripts --max_old_space_size=4096 build", 12 | "build:package": "rm -rf ./dist && tsc --build ./tsconfig.release.json", 13 | "package:release": "rm -rf ./package && mkdir ./package && cp -r ./dist/ ./package/dist && cp README.md package.json ./package && cp -r ./src ./package/src", 14 | "release": "yarn run build:package && yarn run package:release && yarn publish ./package --access public" 15 | }, 16 | "dependencies": { 17 | "@date-io/core": "^1.3.6", 18 | "@date-io/date-fns": "^1.3.11", 19 | "@devexpress/dx-chart-core": "2.3.0", 20 | "@devexpress/dx-react-chart": "^2.0.2", 21 | "@devexpress/dx-react-chart-material-ui": "^2.0.2", 22 | "@devexpress/dx-react-core": "^2.0.2", 23 | "@dorgtech/daocreator-lib": "1.0.0", 24 | "@material-ui/core": "^4.3.1", 25 | "@material-ui/icons": "^4.2.1", 26 | "@material-ui/pickers": "3.2.2", 27 | "@material-ui/styles": "^4.3.0", 28 | "date-fns": "2.1.0", 29 | "file-saver": "^2.0.2", 30 | "material-ui-popup-state": "^1.4.0", 31 | "mobx": "^5.11.0", 32 | "mobx-react": "^6.1.1", 33 | "prop-types": "^15.6.0", 34 | "react-blockies": "^1.4.0", 35 | "react-player": "^1.11.2" 36 | }, 37 | "devDependencies": { 38 | "@types/file-saver": "^2.0.1", 39 | "@types/node": "^10.12.18", 40 | "@types/react": "^16.8.15", 41 | "@types/react-dom": "^16.8.4", 42 | "husky": "^1.1.2", 43 | "prettier": "^1.15.2", 44 | "pretty-quick": "^1.8.0", 45 | "react": "^16.11.0", 46 | "react-dom": "^16.11.0", 47 | "react-scripts": "3.2.0", 48 | "typescript": "3.4.5" 49 | }, 50 | "peerDependencies": { 51 | "react": ">16.11.0", 52 | "react-dom": ">16.11.0" 53 | }, 54 | "husky": { 55 | "hooks": { 56 | "pre-commit": "pretty-quick --staged" 57 | } 58 | }, 59 | "browserslist": [ 60 | ">0.2%", 61 | "not dead", 62 | "not ie <= 11", 63 | "not op_mini all" 64 | ] 65 | } 66 | -------------------------------------------------------------------------------- /packages/ui_v1/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dOrgTech/DAOcreator/09db2fdb239c69f8c12ad58fd0a84c3789335484/packages/ui_v1/public/favicon.ico -------------------------------------------------------------------------------- /packages/ui_v1/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 15 | 19 | 20 | 21 | 30 | DAOcreator 31 | 32 | 33 | 34 |
35 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /packages/ui_v1/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "DAOcreator", 3 | "name": "DAOcreator", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/DAOcreator/DeployStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | createStyles, 4 | Theme, 5 | WithStyles, 6 | withStyles, 7 | Card, 8 | CardContent 9 | } from "@material-ui/core"; 10 | import { 11 | DAOcreatorState, 12 | DAOMigrationResult, 13 | toDAOMigrationParams 14 | } from "@dorgtech/daocreator-lib"; 15 | import Migrator from "../common/dao/Migrator"; 16 | 17 | // eslint-disable-next-line 18 | interface Props extends WithStyles { 19 | dao: DAOcreatorState; 20 | onStart: () => void; 21 | onComplete: () => void; 22 | onStop: () => void; 23 | } 24 | 25 | class DeployStep extends React.Component { 26 | render() { 27 | const { dao, onStart, onComplete, onStop, classes } = this.props; 28 | 29 | return ( 30 | 31 | 32 | { 35 | console.log(result); 36 | onComplete(); 37 | }} 38 | onAbort={(error: Error) => { 39 | console.log(error.message); 40 | onStop(); 41 | }} 42 | onStart={onStart} 43 | onStop={onStop} 44 | /> 45 | 46 | 47 | ); 48 | } 49 | } 50 | 51 | // STYLE 52 | const styles = (theme: Theme) => 53 | createStyles({ 54 | root: { 55 | maxWidth: "100%" 56 | } 57 | }); 58 | 59 | export default withStyles(styles)(DeployStep); 60 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/DAOcreator/MembersStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { observer } from "mobx-react"; 3 | import { 4 | WithStyles, 5 | Theme, 6 | createStyles, 7 | withStyles, 8 | Card, 9 | CardContent, 10 | Grid, 11 | Typography 12 | } from "@material-ui/core"; 13 | import { MembersForm } from "@dorgtech/daocreator-lib"; 14 | import MembersEditor from "../common/dao/MembersEditor"; 15 | import MembersAnalytics from "../common/dao/MembersAnalytics"; 16 | 17 | // eslint-disable-next-line 18 | interface Props extends WithStyles { 19 | form: MembersForm; 20 | getDAOTokenSymbol: () => string; 21 | } 22 | 23 | @observer 24 | class MembersStep extends React.Component { 25 | render() { 26 | const { classes, form, getDAOTokenSymbol } = this.props; 27 | 28 | return ( 29 | 30 | 31 | 32 | Add Members 33 | 34 | 35 | 36 | 37 | Here we specify the initial reputation and token distribution in 38 | the DAO. 39 |
40 |
41 | We do this by specifying the addresses together with the amount 42 | of reputation and tokens for each address. 43 |
44 |
45 | 46 | 52 |
53 |
54 |
55 | ); 56 | } 57 | } 58 | 59 | const styles = (theme: Theme) => 60 | createStyles({ 61 | guideText: { 62 | fontSize: 18, 63 | maxWidth: 450, 64 | paddingLeft: 30, 65 | paddingRight: 30, 66 | paddingTop: 50, 67 | paddingBottom: 50, 68 | margin: "auto" 69 | } 70 | }); 71 | 72 | export default withStyles(styles)(MembersStep); 73 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/DAOcreator/NamingStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Card, 4 | CardContent, 5 | createStyles, 6 | Grid, 7 | Theme, 8 | Typography, 9 | withStyles, 10 | WithStyles 11 | } from "@material-ui/core"; 12 | import { DAOConfigForm, DAOForm } from "@dorgtech/daocreator-lib"; 13 | import DAOConfigEditor from "../common/dao/DAOConfigEditor"; 14 | import MigrationParamsImport from "../common/dao/MigrationParamsImport"; 15 | 16 | // eslint-disable-next-line 17 | interface Props extends WithStyles { 18 | form: DAOConfigForm; 19 | daoForm: DAOForm; 20 | toReviewStep: () => void; 21 | } 22 | 23 | class NamingStep extends React.Component { 24 | render() { 25 | const { classes, form, daoForm, toReviewStep } = this.props; 26 | 27 | return ( 28 | 29 |
30 | 31 | 32 | Name the DAO 33 | 34 | 35 | 36 | 37 | Welcome! 38 |
39 | You're about to start the process of creating a DAO 40 | (Decentralized Autonomous Organization). 41 |
42 |
43 | Let's start by giving a name to the DAO and its token. 44 |
45 |
46 |
47 | 48 | 49 |
50 |
51 |
52 |
53 | ); 54 | } 55 | } 56 | 57 | // STYLE 58 | const styles = (theme: Theme) => 59 | createStyles({ 60 | guideText: { 61 | fontSize: 18, 62 | maxWidth: 450, 63 | paddingLeft: 30, 64 | paddingRight: 30, 65 | paddingTop: 50, 66 | paddingBottom: 50, 67 | margin: "auto" 68 | } 69 | }); 70 | 71 | export default withStyles(styles)(NamingStep); 72 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/DAOcreator/ReviewStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Card, 4 | CardContent, 5 | Typography, 6 | Divider, 7 | Grid, 8 | Fab 9 | } from "@material-ui/core"; 10 | import WarningIcon from "@material-ui/icons/WarningTwoTone"; 11 | import EditIcon from "@material-ui/icons/Settings"; 12 | import { DAOForm, SchemeType } from "@dorgtech/daocreator-lib"; 13 | import SchemesEditor from "../common/dao/SchemesEditor"; 14 | import DAOConfigEditor from "../common/dao/DAOConfigEditor"; 15 | import MembersEditor from "../common/dao/MembersEditor"; 16 | import MembersAnalytics from "../common/dao/MembersAnalytics"; 17 | 18 | interface Props { 19 | form: DAOForm; 20 | disableHeader?: boolean; 21 | // TODO: don't use a number here, use an enum instead. This will break easily. 22 | setStep?: (step: number) => void; 23 | } 24 | 25 | export default class ReviewStep extends React.Component { 26 | render() { 27 | const { form, disableHeader, setStep } = this.props; 28 | const { config, schemes, members } = form.$; 29 | const getDAOTokenSymbol = () => config.$.tokenSymbol.value; 30 | const missingSchemeReg = 31 | schemes.$.findIndex( 32 | scheme => scheme.type === SchemeType.SchemeRegistrar 33 | ) === -1; 34 | 35 | const modifyStep = (step: number) => ( 36 | { 39 | if (setStep) setStep(step); 40 | }} 41 | style={{ 42 | height: "20px", 43 | width: "20px", 44 | minHeight: "20px", 45 | marginRight: "5px", 46 | marginTop: "5px" 47 | }} 48 | > 49 | 50 | 51 | ); 52 | 53 | const titleText = (title: string, step: number) => ( 54 | 55 | {setStep ? modifyStep(step) : ""} 56 | 57 | {title} 58 | 59 | 60 | ); 61 | 62 | return ( 63 | 64 | 65 | {!disableHeader ? ( 66 | <> 67 | Everything look good? 68 | 69 | 70 | ) : ( 71 | <> 72 | )} 73 | 74 | 75 | {titleText("Names", 0)} 76 | 77 | 78 | 79 | 80 | 81 | {titleText("Schemes", 1)} 82 | 83 | {missingSchemeReg ? ( 84 | 85 | 86 | 87 | Warning: Your DAO is missing a SchemeRegistrar, and will not 88 | be able to modify itself once deployed. We highly recommend 89 | adding this to your DAO. 90 | 91 | 92 | ) : ( 93 | <> 94 | )} 95 | 96 | 97 | {titleText("Members", 2)} 98 | 99 | 100 | 101 | 106 | 107 | 108 | 109 | 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/DAOcreator/SchemesStep.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { observer } from "mobx-react"; 3 | import { Card, CardContent, Typography } from "@material-ui/core"; 4 | import { SchemesForm } from "@dorgtech/daocreator-lib"; 5 | import SchemesEditor from "../common/dao/SchemesEditor"; 6 | 7 | interface Props { 8 | form: SchemesForm; 9 | } 10 | 11 | @observer 12 | export default class SchemesStep extends React.Component { 13 | render() { 14 | const { form } = this.props; 15 | 16 | return ( 17 | 18 | 19 | 20 | Add Schemes 21 | 22 | 23 | 24 | 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/README.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | ## Common 4 | 5 | Generalized components. 6 | 7 | ## Pages 8 | 9 | Pages that compose the common components. 10 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/EthAddressAvatar/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-blockies"; 2 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/EthAddressAvatar/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { IconButton } from "@material-ui/core"; 3 | import Blockies from "react-blockies"; 4 | 5 | export type Props = { 6 | address: string; 7 | }; 8 | 9 | const EthAddressAvatar: React.SFC = ({ address }) => ( 10 | window.open(`https://etherscan.io/address/${address}`)} 12 | style={{ 13 | padding: 0 14 | }} 15 | tabIndex={-1} 16 | > 17 | 18 | 19 | ); 20 | 21 | export default EthAddressAvatar; 22 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/FormField/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "material-ui-popup-state"; 2 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/PieChart.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Chart, 4 | PieSeries, 5 | Tooltip 6 | } from "@devexpress/dx-react-chart-material-ui"; 7 | import { Animation, EventTracker } from "@devexpress/dx-react-chart"; 8 | 9 | export interface PieChartConfig { 10 | size: number; 11 | dataKey: string; 12 | nameKey: string; 13 | } 14 | 15 | export interface Props { 16 | data: any[]; 17 | config: PieChartConfig; 18 | } 19 | 20 | interface State { 21 | targetItem: any; 22 | } 23 | 24 | class PieChart extends React.Component { 25 | constructor(props: Props) { 26 | super(props); 27 | this.state = { 28 | targetItem: undefined 29 | }; 30 | } 31 | 32 | render() { 33 | const { data, config } = this.props; 34 | const { targetItem } = this.state; 35 | 36 | const TooltipContent = () => ( 37 |
38 | 42 | 46 |
47 | ); 48 | 49 | return ( 50 | 51 | 52 | 53 | 57 | this.setState({ targetItem }) 58 | } 59 | /> 60 | 61 | 62 | ); 63 | } 64 | } 65 | 66 | export default PieChart; 67 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/DAOConfigEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Grid } from "@material-ui/core"; 3 | import { DAOConfigForm } from "@dorgtech/daocreator-lib"; 4 | import FormField from "../FormField"; 5 | 6 | interface Props { 7 | form: DAOConfigForm; 8 | editable: boolean; 9 | } 10 | 11 | export default class DAOConfigEditor extends React.Component { 12 | render() { 13 | const { form, editable } = this.props; 14 | 15 | return ( 16 | <> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/GenesisProtocolAnalytics/AnalysisResultView.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | withStyles, 4 | LinearProgress, 5 | Typography, 6 | Popover, 7 | ButtonBase 8 | } from "@material-ui/core"; 9 | import PopupState, { bindTrigger, bindPopover } from "material-ui-popup-state"; 10 | import { AnalysisResult } from "./utils"; 11 | 12 | const AnalysisResultView = (props: { 13 | title: string; 14 | result: AnalysisResult; 15 | }) => { 16 | const NormalStyle = { 17 | root: { 18 | height: 5, 19 | backgroundColor: "#94d8ff" 20 | }, 21 | bar: { 22 | borderRadius: 20, 23 | backgroundColor: "#00a2ff" 24 | } 25 | }; 26 | const WarningStyle = { 27 | root: { 28 | height: 5, 29 | backgroundColor: "#ffd178" 30 | }, 31 | bar: { 32 | borderRadius: 20, 33 | backgroundColor: "#ffa800" 34 | } 35 | }; 36 | const Normal = withStyles(NormalStyle)(LinearProgress); 37 | const Warning = withStyles(WarningStyle)(LinearProgress); 38 | 39 | const { title, result } = props; 40 | let value = result.t; 41 | 42 | // keep a little showing if there is no bar 43 | if (Math.fround(result.t) === 0 && !result.warning) { 44 | value = 0.05; 45 | } 46 | 47 | value *= 100; 48 | 49 | return ( 50 | 51 | {(popupState: any) => ( 52 | <> 53 | 58 | 59 | {title} 60 | {result.warning ? ( 61 | 66 | ) : ( 67 | 68 | )} 69 | 70 | 71 | 82 | {result.message} 83 | 84 | 85 | )} 86 | 87 | ); 88 | }; 89 | 90 | export default AnalysisResultView; 91 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/GenesisProtocolAnalytics/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "material-ui-popup-state"; 2 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/GenesisProtocolAnalytics/utils.ts: -------------------------------------------------------------------------------- 1 | export interface AnalysisResult { 2 | t: number; 3 | message: string | React.ReactFragment; 4 | warning: boolean; 5 | } 6 | 7 | export interface AnalysisOpts { 8 | min: number; 9 | max: number; 10 | toString: (value: number) => string; 11 | } 12 | 13 | export const analyzeField = ( 14 | value: number, 15 | name: string, 16 | opts: AnalysisOpts 17 | ): AnalysisResult => { 18 | const { min, max } = opts; 19 | let toString = opts.toString; 20 | 21 | // Lerp between min and max based on 22 | let t: number; 23 | 24 | if (Math.fround(min - max) === 0) { 25 | if (value > max) { 26 | t = 1.1; 27 | } else if (value < min) { 28 | t = -0.1; 29 | } else { 30 | t = 1; 31 | } 32 | } else { 33 | t = (value - min) / (max - min); 34 | } 35 | 36 | const warning: boolean = t < 0 || t > 1; 37 | let message: string = ``; 38 | 39 | if (t < 0) { 40 | message += `${name}: LOWER than recommended min of ${toString(min)}`; 41 | t = 0; 42 | } else if (t > 1) { 43 | message += `${name}: LARGER than recommended max of ${toString(max)}`; 44 | t = 1; 45 | } else { 46 | message += `${name}: ${toString(value)}`; 47 | } 48 | 49 | return { 50 | t, 51 | message, 52 | warning 53 | }; 54 | }; 55 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/GenesisProtocolEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { GenesisProtocolForm } from "@dorgtech/daocreator-lib"; 3 | import FormField from "../FormField"; 4 | 5 | interface Props { 6 | form: GenesisProtocolForm; 7 | editable: boolean; 8 | } 9 | 10 | export default class GenesisProtocolEditor extends React.Component { 11 | render() { 12 | const { form, editable } = this.props; 13 | const formState = form.$ as any; 14 | 15 | // TODO: make this the default behaviour of all form components 16 | // All editors should just be this, and the fields themselves should contain 17 | // a type. Then overrides can be made. 18 | return ( 19 | <> 20 | {Object.keys(formState).map((propName: string, index: number) => ( 21 | 26 | ))} 27 | 28 | ); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/GenesisProtocolPresetEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { observer } from "mobx-react"; 3 | import { 4 | Select, 5 | FilledInput, 6 | FormControl, 7 | InputLabel, 8 | Grid, 9 | Fab, 10 | Dialog, 11 | DialogTitle, 12 | DialogContentText, 13 | DialogContent, 14 | DialogActions, 15 | Button, 16 | Typography 17 | } from "@material-ui/core"; 18 | import EditIcon from "@material-ui/icons/Settings"; 19 | import GenesisProtocolEditor from "./GenesisProtocolEditor"; 20 | import { 21 | GenesisProtocolForm, 22 | GenesisProtocolPreset 23 | } from "@dorgtech/daocreator-lib"; 24 | 25 | interface Props { 26 | form: GenesisProtocolForm; 27 | editable: boolean; 28 | } 29 | 30 | interface State { 31 | editing: boolean; 32 | } 33 | 34 | @observer 35 | export default class GenesisProtocolPresetEditor extends React.Component< 36 | Props, 37 | State 38 | > { 39 | constructor(props: Props) { 40 | super(props); 41 | this.state = { 42 | editing: false 43 | }; 44 | } 45 | 46 | render() { 47 | const { form, editable } = this.props; 48 | const { editing } = this.state; 49 | 50 | const onChange = (event: React.ChangeEvent<{ value: any }>) => { 51 | let value = event.target.value; 52 | 53 | if (value === "0") { 54 | value = undefined; 55 | this.setState({ editing: true }); 56 | } 57 | 58 | form.preset = value; 59 | this.forceUpdate(); 60 | }; 61 | 62 | const onEdit = () => { 63 | form.preset = undefined; 64 | this.setState({ 65 | ...this.state, 66 | editing: true 67 | }); 68 | }; 69 | 70 | const onClose = async () => { 71 | const res = await this.props.form.validate(); 72 | 73 | if (res.hasError) { 74 | return; 75 | } 76 | 77 | this.setState({ 78 | ...this.state, 79 | editing: false 80 | }); 81 | }; 82 | 83 | // TODO: base class for all forms (move analytics into step, pass for into here) 84 | return ( 85 | <> 86 | 87 | Genesis Protocol 88 | 94 | 95 | 108 | 109 | 110 | 116 | 117 | 118 | 119 | 120 | 121 | 126 | Genesis Protocol 127 | 128 | 129 |
130 | Genesis protocol is our implementation of holographic consensus 131 | as a smart contract on the ethereum blockchain. In order to 132 | allow various use cases, the genesis protocol has several 133 | configurations parameters: 134 |
135 |
136 | 137 |
138 | 139 | {form.showFormError ? 140 | {form.error} : 141 | <> 142 | } 143 | 144 | 145 |
146 | 147 | ); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/MemberEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Grid } from "@material-ui/core"; 3 | import { MemberForm } from "@dorgtech/daocreator-lib"; 4 | import FormField from "../FormField"; 5 | 6 | interface Props { 7 | form: MemberForm; 8 | editable: boolean; 9 | } 10 | 11 | export default class MemberEditor extends React.Component { 12 | render() { 13 | const { form, editable } = this.props; 14 | 15 | return ( 16 | <> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/MembersAnalytics.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | WithStyles, 4 | Theme, 5 | createStyles, 6 | withStyles, 7 | Grid, 8 | Typography 9 | } from "@material-ui/core"; 10 | import QuestionIcon from "@material-ui/icons/HelpOutline"; 11 | import { Member } from "@dorgtech/daocreator-lib"; 12 | import PieChart from "../PieChart"; 13 | 14 | // eslint-disable-next-line 15 | interface Props extends WithStyles { 16 | data: Member[]; 17 | } 18 | 19 | class MembersAnalytics extends React.Component { 20 | render() { 21 | const { classes, data } = this.props; 22 | 23 | return ( 24 | <> 25 | 26 | 31 | Reputation Distribution 32 | 33 | {data.length > 0 ? ( 34 | 42 | ) : ( 43 | 44 | )} 45 | 46 | 47 | 52 | Tokens Distribution 53 | 54 | {data.length > 0 ? ( 55 | 63 | ) : ( 64 | 65 | )} 66 | 67 | 68 | ); 69 | } 70 | } 71 | 72 | const styles = (theme: Theme) => 73 | createStyles({ 74 | pieChartHeadlines: { 75 | textAlign: "center" 76 | }, 77 | questionIcon: { 78 | width: "240px", 79 | height: "240px", 80 | justifySelf: "center", 81 | alignSelf: "center", 82 | color: "#dadadd" 83 | } 84 | }); 85 | 86 | export default withStyles(styles)(MembersAnalytics); 87 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/MembersSaveLoad.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | FormControl, 4 | Dialog, 5 | DialogTitle, 6 | DialogContent, 7 | Button, 8 | ButtonGroup, 9 | Grid 10 | } from "@material-ui/core"; 11 | import DownloadIcon from "@material-ui/icons/Archive"; 12 | import ImportIcon from "@material-ui/icons/Unarchive"; 13 | import { MembersForm } from "@dorgtech/daocreator-lib"; 14 | import { saveAs } from "file-saver"; 15 | 16 | interface ImportError { 17 | file: string; 18 | error: string; 19 | } 20 | 21 | interface Props { 22 | form: MembersForm; 23 | onImport: () => void; 24 | } 25 | 26 | interface State { 27 | open: boolean; 28 | error: ImportError | undefined; 29 | } 30 | 31 | const initState: State = { 32 | open: false, 33 | error: undefined 34 | }; 35 | 36 | export default class MembersSaveLoad extends React.Component { 37 | constructor(props: Props) { 38 | super(props); 39 | this.state = { 40 | ...initState 41 | }; 42 | } 43 | 44 | render() { 45 | const { form, onImport } = this.props; 46 | const { open, error } = this.state; 47 | 48 | const onOpen = () => 49 | this.setState({ 50 | ...initState, 51 | open: true 52 | }); 53 | 54 | const onClose = () => 55 | this.setState({ 56 | ...initState, 57 | open: false 58 | }); 59 | 60 | const onError = (file: string, error: string) => 61 | this.setState({ 62 | ...this.state, 63 | error: { file, error } 64 | }); 65 | 66 | const onFilePicked = async (event: React.ChangeEvent) => { 67 | if (event.target.files === null) { 68 | return; 69 | } 70 | 71 | const files = Array.from(event.target.files); 72 | const formClone = new MembersForm(form.getDAOTokenSymbol); 73 | formClone.$ = [...form.$]; 74 | 75 | for (const file of files) { 76 | const importedMembers = new MembersForm(form.getDAOTokenSymbol); 77 | 78 | try { 79 | await importedMembers.fromCSV(file); 80 | } catch (e) { 81 | onError(file.name, e.message); 82 | return; 83 | } 84 | 85 | // Try adding these members to the full list 86 | formClone.$ = [...formClone.$, ...importedMembers.$]; 87 | 88 | await formClone.validate(); 89 | if (formClone.hasError && formClone.error) { 90 | onError(file.name, formClone.error); 91 | return; 92 | } 93 | } 94 | 95 | form.$.splice(0, form.$.length); 96 | form.$.push(...formClone.$); 97 | 98 | onImport(); 99 | onClose(); 100 | }; 101 | 102 | const onDownload = async () => { 103 | saveAs(new File([await form.toCSV()], "dao-members.csv")); 104 | }; 105 | 106 | const onDownloadTemplate = async () => { 107 | const emptyForm = new MembersForm(form.getDAOTokenSymbol); 108 | saveAs(new File([await emptyForm.toCSV()], "dao-members.csv")); 109 | }; 110 | 111 | const ImportInfo = () => ( 112 | 113 | Make sure your CSV file has the following columns: 114 | 120 | 121 |
    122 |
  • address
  • 123 |
  • reputation
  • 124 |
  • tokens
  • 125 |
126 |
127 | 128 | Need a template? 129 | 130 | 138 | 139 | 140 |
141 |
142 | ); 143 | 144 | const ImportErrors = (props: { error: ImportError }) => ( 145 | 146 | We encountered an issue during the import process: 147 |
148 |
149 | {props.error.file}: {props.error.error} 150 |
151 |
152 | ); 153 | 154 | const ImportButton = () => ( 155 | 156 | 167 | 168 | ); 169 | 170 | return ( 171 | 172 | 175 | 178 | 179 | {error ? : } 180 | 181 | 182 | 183 | ); 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/MigrationParamsImport.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { 3 | Grid, 4 | Fab, 5 | FormControl, 6 | Dialog, 7 | DialogTitle, 8 | DialogContent, 9 | Button 10 | } from "@material-ui/core"; 11 | import ImportIcon from "@material-ui/icons/Unarchive"; 12 | import { DAOForm } from "@dorgtech/daocreator-lib"; 13 | 14 | interface ImportError { 15 | file: string; 16 | error: string; 17 | } 18 | 19 | interface Props { 20 | form: DAOForm; 21 | onImport: () => void; 22 | } 23 | 24 | interface State { 25 | open: boolean; 26 | error: ImportError | undefined; 27 | } 28 | 29 | const initState: State = { 30 | open: false, 31 | error: undefined 32 | }; 33 | 34 | export default class MigrationParamsImport extends React.Component< 35 | Props, 36 | State 37 | > { 38 | constructor(props: Props) { 39 | super(props); 40 | this.state = { 41 | ...initState 42 | }; 43 | } 44 | 45 | render() { 46 | const { form, onImport } = this.props; 47 | const { open, error } = this.state; 48 | 49 | const onOpen = () => { 50 | this.setState({ 51 | ...initState, 52 | open: true 53 | }); 54 | }; 55 | 56 | const onClose = () => 57 | this.setState({ 58 | ...initState, 59 | open: false 60 | }); 61 | 62 | const onError = (file: string, error: string) => 63 | this.setState({ 64 | ...this.state, 65 | error: { file, error } 66 | }); 67 | 68 | const onFilePicked = async (event: React.ChangeEvent) => { 69 | if (event.target.files === null) { 70 | return; 71 | } 72 | 73 | const files = Array.from(event.target.files); 74 | 75 | if (files.length === 0) { 76 | return; 77 | } 78 | 79 | const file: File = files[0]; 80 | 81 | try { 82 | await form.fromMigrationParamsFile(file); 83 | await form.validate(); 84 | } catch (e) { 85 | onError(file.name, e.message); 86 | return; 87 | } 88 | 89 | onClose(); 90 | onImport(); 91 | }; 92 | 93 | const ImportInfo = () => ( 94 | 95 | Import an existing `dao-params.json` file. 96 | 97 | ); 98 | 99 | const ImportErrors = (props: { error: ImportError }) => ( 100 | 101 | We encountered an issue during the import process: 102 |
103 |
104 | {props.error.file}: {props.error.error} 105 |
106 |
107 | ); 108 | 109 | const ImportButton = () => ( 110 | 111 | 122 | 123 | ); 124 | 125 | return ( 126 | <> 127 | 128 | 129 | 130 | 131 | 132 | 133 | {error ? : } 134 | 135 | 136 | 137 | ); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/Migrator/LogLineTypes.ts: -------------------------------------------------------------------------------- 1 | export enum LogType { 2 | Info, 3 | Error, 4 | TransactionResult, 5 | UserApproval, 6 | MigrationAborted 7 | } 8 | 9 | export interface LogLine { 10 | type: LogType; 11 | toString: () => string; 12 | } 13 | 14 | export class LogInfo implements LogLine { 15 | public type = LogType.Info; 16 | constructor(public info: string) {} 17 | 18 | public toString() { 19 | return this.info; 20 | } 21 | } 22 | 23 | export class LogError implements LogLine { 24 | public type = LogType.Error; 25 | constructor(public error: string) {} 26 | 27 | public toString() { 28 | return `${this.error}`; 29 | } 30 | } 31 | 32 | export class LogTransactionResult implements LogLine { 33 | public type = LogType.TransactionResult; 34 | constructor( 35 | public msg: string, 36 | public txHash: string, 37 | public txCost: number 38 | ) {} 39 | 40 | public toString() { 41 | return `${this.msg} ${this.txHash} ${this.txCost} ETH`; 42 | } 43 | } 44 | 45 | export class LogUserApproval implements LogLine { 46 | public type = LogType.UserApproval; 47 | public response?: boolean; 48 | constructor( 49 | public question: string, 50 | public onResponse: (resp: boolean) => void 51 | ) {} 52 | 53 | public toString() { 54 | return `${this.question} response: ${this.response}`; 55 | } 56 | } 57 | 58 | export class LogMigrationAborted implements LogLine { 59 | public type = LogType.MigrationAborted; 60 | constructor(public error: Error) {} 61 | 62 | public toString() { 63 | return `${this.error}`; 64 | } 65 | } 66 | 67 | export type AnyLogLine = 68 | | LogInfo 69 | | LogError 70 | | LogTransactionResult 71 | | LogUserApproval 72 | | LogMigrationAborted; 73 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/SchemeEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { observer } from "mobx-react"; 3 | import { 4 | Theme, 5 | createStyles, 6 | WithStyles, 7 | withStyles, 8 | Typography, 9 | Card, 10 | CardContent, 11 | Grid, 12 | Switch, 13 | Collapse 14 | } from "@material-ui/core"; 15 | import { SvgIconProps } from "@material-ui/core/SvgIcon"; 16 | import { AnySchemeForm } from "@dorgtech/daocreator-lib"; 17 | import GenesisProtocolPresetEditor from "./GenesisProtocolPresetEditor"; 18 | import GenesisProtocolAnalytics from "./GenesisProtocolAnalytics"; 19 | import FormField from "../FormField"; 20 | 21 | // eslint-disable-next-line 22 | interface Props extends WithStyles { 23 | form: AnySchemeForm; 24 | editable: boolean; 25 | enabled: boolean; 26 | Icon: React.ComponentType; 27 | onToggle: (toggled: boolean) => void; 28 | } 29 | 30 | interface State { 31 | enabled: boolean; 32 | } 33 | 34 | @observer 35 | class SchemeEditor extends React.Component { 36 | constructor(props: Props) { 37 | super(props); 38 | this.state = { enabled: props.enabled }; 39 | } 40 | 41 | render() { 42 | const { classes, form, editable, Icon } = this.props; 43 | const { enabled } = this.state; 44 | const params = form.getParams(); 45 | 46 | const onToggle = (event: object, checked: boolean) => { 47 | this.props.onToggle(checked); 48 | this.setState({ 49 | enabled: checked 50 | }); 51 | }; 52 | 53 | return ( 54 | 55 | 56 | 57 | 63 | 64 | {form.displayName} 65 | 66 | 67 | 72 | 73 | 74 | 80 | 81 | 82 | 83 | 84 | 88 | {form.description} 89 | 90 | 91 | 92 | 93 |
94 | {params.length > 0 ? ( 95 | <> 96 | Parameters 97 | {params.map((param, index) => ( 98 | 103 | ))} 104 | 105 | ) : ( 106 | <> 107 | )} 108 | Voting Configuration 109 | 113 | 114 |
115 |
116 |
117 |
118 |
119 | ); 120 | } 121 | } 122 | 123 | const styles = (theme: Theme) => 124 | createStyles({ 125 | card: { 126 | minWidth: 250, 127 | maxWidth: 420 128 | }, 129 | schemeIcon: { 130 | width: "100%", 131 | height: "100%" 132 | }, 133 | schemeDescription: { 134 | marginBottom: 15 135 | } 136 | }); 137 | 138 | export default withStyles(styles)(SchemeEditor); 139 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/common/dao/SchemesEditor.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { observer } from "mobx-react"; 3 | import { observable, IObservableObject } from "mobx"; 4 | import { 5 | WithStyles, 6 | Theme, 7 | createStyles, 8 | withStyles, 9 | Grid, 10 | Typography 11 | } from "@material-ui/core"; 12 | import { SvgIconProps } from "@material-ui/core/SvgIcon"; 13 | import ContributionRewardIcon from "@material-ui/icons/DonutSmallTwoTone"; 14 | import SchemeRegistrarIcon from "@material-ui/icons/WidgetsTwoTone"; 15 | import GenericSchemeIcon from "@material-ui/icons/LanguageTwoTone"; 16 | import SchemeEditor from "./SchemeEditor"; 17 | import { 18 | SchemesForm, 19 | AnySchemeForm, 20 | GenericSchemeForm, 21 | ContributionRewardForm, 22 | SchemeRegistrarForm, 23 | SchemeType 24 | } from "@dorgtech/daocreator-lib"; 25 | 26 | // eslint-disable-next-line 27 | interface Props extends WithStyles { 28 | form: SchemesForm; 29 | editable: boolean; 30 | } 31 | 32 | interface SchemeFormDrawers { 33 | form: AnySchemeForm; 34 | enabled: boolean; 35 | Icon: React.ComponentType; 36 | } 37 | 38 | type IconType = React.ComponentType; 39 | 40 | @observer 41 | class SchemesEditor extends React.Component { 42 | icons: { [type: number]: IconType } = {}; 43 | fillers: { [type: number]: AnySchemeForm & IObservableObject } = {}; 44 | 45 | constructor(props: Props) { 46 | super(props); 47 | 48 | this.icons[SchemeType.ContributionReward] = ContributionRewardIcon; 49 | this.icons[SchemeType.GenericScheme] = GenericSchemeIcon; 50 | this.icons[SchemeType.SchemeRegistrar] = SchemeRegistrarIcon; 51 | 52 | this.fillers[SchemeType.ContributionReward] = observable( 53 | new ContributionRewardForm() 54 | ); 55 | this.fillers[SchemeType.SchemeRegistrar] = observable( 56 | new SchemeRegistrarForm() 57 | ); 58 | this.fillers[SchemeType.GenericScheme] = observable( 59 | new GenericSchemeForm() 60 | ); 61 | } 62 | 63 | render() { 64 | const { classes, form, editable } = this.props; 65 | const error = form.showFormError; 66 | 67 | let schemes: SchemeFormDrawers[] = []; 68 | 69 | // iterate through each scheme type 70 | for (const type in SchemeType) { 71 | // https://tinyurl.com/y33e9j9x 72 | if (isNaN(Number(type))) { 73 | break; 74 | } 75 | 76 | const schemeType: SchemeType = Number(type); 77 | const index = form.$.findIndex(scheme => scheme.type === schemeType); 78 | const added = index > -1; 79 | 80 | schemes.push({ 81 | form: added ? form.$[index] : this.fillers[schemeType], 82 | enabled: added, 83 | Icon: this.icons[schemeType] 84 | }); 85 | } 86 | 87 | return ( 88 |
89 | 96 | {schemes.map((scheme, index) => { 97 | if (!editable && !scheme.enabled) { 98 | return <>; 99 | } 100 | 101 | return ( 102 | { 108 | if (toggled) { 109 | form.$.push(scheme.form); 110 | } else { 111 | const index = form.$.findIndex( 112 | test => test.type === scheme.form.type 113 | ); 114 | 115 | if (index === -1) { 116 | throw Error( 117 | "Trying to remove scheme that hasn't been added." 118 | ); 119 | } 120 | 121 | form.$.splice(index, 1); 122 | } 123 | }} 124 | key={`scheme-${index}`} 125 | /> 126 | ); 127 | })} 128 | 129 | {error ? {form.error} : <>} 130 |
131 | ); 132 | } 133 | } 134 | 135 | const styles = (theme: Theme) => 136 | createStyles({ 137 | root: { 138 | flexGrow: 1 139 | } 140 | }); 141 | 142 | export default withStyles(styles)(SchemesEditor); 143 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { MuiThemeProvider, createMuiTheme } from "@material-ui/core/styles"; 3 | import CssBaseline from "@material-ui/core/CssBaseline"; 4 | import DAOcreator from "./DAOcreator"; 5 | import defaultTheme, { CustomTheme } from "./theme"; 6 | import { ProviderOrGetter } from "@dorgtech/daocreator-lib"; 7 | 8 | interface Props { 9 | theme?: CustomTheme; 10 | setWeb3Provider?: ProviderOrGetter; 11 | } 12 | 13 | const Index: React.FC = ({ theme, setWeb3Provider }) => { 14 | let useTheme = defaultTheme; 15 | 16 | if (theme) { 17 | useTheme = theme; 18 | } 19 | 20 | return ( 21 | 22 | 23 | 24 | 25 | ); 26 | }; 27 | 28 | export default Index; 29 | -------------------------------------------------------------------------------- /packages/ui_v1/src/components/theme.ts: -------------------------------------------------------------------------------- 1 | export interface CustomTheme { 2 | palette: { 3 | primary: { 4 | main: string; 5 | contrastText: string; 6 | }; 7 | secondary: { 8 | main: string; 9 | contrastText: string; 10 | }; 11 | }; 12 | } 13 | 14 | const defaultTheme: CustomTheme = { 15 | palette: { 16 | primary: { 17 | main: "#2c4b56", 18 | contrastText: "#fafafa" 19 | }, 20 | secondary: { 21 | main: "#ffa800", 22 | contrastText: "#1a1a1a" 23 | } 24 | } 25 | }; 26 | 27 | export default defaultTheme; 28 | -------------------------------------------------------------------------------- /packages/ui_v1/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | 4 | import DAOcreator from "./components"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /packages/ui_v1/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/ui_v1/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2016", "es2017", "dom", "esnext.asynciterable"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "outDir": "dist", 10 | "resolveJsonModule": true, 11 | "sourceMap": true, 12 | "strict": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "typeRoots": ["node_modules/@types"], 15 | "skipLibCheck": true, 16 | "allowJs": false, 17 | "rootDirs": ["src"], 18 | "jsx": "react", 19 | "forceConsistentCasingInFileNames": true, 20 | "allowSyntheticDefaultImports": true, 21 | "esModuleInterop": true, 22 | "isolatedModules": true, 23 | "noEmit": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/ui_v1/tsconfig.release.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es2016", "es2017", "dom", "esnext.asynciterable"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "outDir": "dist", 10 | "resolveJsonModule": true, 11 | "sourceMap": true, 12 | "strict": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "typeRoots": ["node_modules/@types"], 15 | "skipLibCheck": true, 16 | "allowJs": false, 17 | "rootDirs": ["src/components"], 18 | "jsx": "react", 19 | "forceConsistentCasingInFileNames": true, 20 | "allowSyntheticDefaultImports": true, 21 | "esModuleInterop": true, 22 | "declaration": true 23 | }, 24 | "include": ["src/components"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/ui_v2/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | ganache-accounts.json 24 | #/src/contracts/interfaces 25 | secret.json 26 | 27 | # vscode chrome debugger cache 28 | .vscode/chrome 29 | 30 | dist 31 | package 32 | 33 | *.css.d.ts -------------------------------------------------------------------------------- /packages/ui_v2/README.md: -------------------------------------------------------------------------------- 1 | # Cotary DAOcreator UI (V2) 2 | 3 | Wizard for setting up your own DAOstack DAO. 4 | 5 | ## Contribute 6 | 7 | Welcome Fellow Contributors. Today We DAO. 8 | 9 | ### Installing 10 | 11 | `yarn` 12 | 13 | ### Running 14 | 15 | `yarn start` 16 | 17 | ### Debugging 18 | 19 | VS Code w/ Chrome 20 | 21 | 1. Install Extension "`Debugger for Chrome`" 22 | 2. Launch the app by running `npm run start`. 23 | 3. Press the green play button in the debug menu of VS Code. 24 | -------------------------------------------------------------------------------- /packages/ui_v2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dorgtech/daocreator-ui", 3 | "version": "1.0.10", 4 | "main": "./dist/index.js", 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "yarn build:package && yarn build:app", 8 | "eject": "react-scripts eject", 9 | "test": "react-scripts test", 10 | "build:app": "CI=false react-scripts --max_old_space_size=4096 build", 11 | "build:assets": "copyfiles -u 2 ./src/**/*.css ./src/**/*.svg dist", 12 | "build:package": "rm -rf ./dist && tsc --build ./tsconfig.release.json && yarn build:assets", 13 | "package:release": "rm -rf ./package && mkdir ./package && cp -r ./dist/ ./package/dist && cp README.md package.json ./package && cp -r ./src/components ./package/src", 14 | "release": "yarn build:package && yarn package:release && yarn publish ./package --access public" 15 | }, 16 | "dependencies": { 17 | "@date-io/core": "^1.3.6", 18 | "@date-io/date-fns": "^1.3.11", 19 | "@dorgtech/daocreator-lib": "1.0.2", 20 | "@fortawesome/fontawesome-free": "^5.11.2", 21 | "@material-ui/core": "^4.7.2", 22 | "@material-ui/pickers": "3.2.2", 23 | "date-fns": "2.1.0", 24 | "ethereum-blockies-base64": "^1.0.2", 25 | "file-saver": "^2.0.2", 26 | "mdbreact": "4.23.0", 27 | "mobx": "^5.11.0", 28 | "mobx-react": "^6.1.1", 29 | "prop-types": "^15.6.0", 30 | "react-dropzone": "^10.2.1", 31 | "react-player": "^1.11.2" 32 | }, 33 | "devDependencies": { 34 | "@types/file-saver": "^2.0.1", 35 | "@types/node": "^10.12.18", 36 | "@types/react": "^16.8.15", 37 | "@types/react-dom": "^16.8.4", 38 | "copyfiles": "^2.2.0", 39 | "husky": "^1.1.2", 40 | "prettier": "^1.15.2", 41 | "pretty-quick": "^1.8.0", 42 | "react-scripts": "3.2.0", 43 | "typescript": "3.4.5" 44 | }, 45 | "peerDependencies": { 46 | "react": ">16.11.0", 47 | "react-dom": ">16.11.0" 48 | }, 49 | "husky": { 50 | "hooks": { 51 | "pre-commit": "pretty-quick --staged" 52 | } 53 | }, 54 | "browserslist": [ 55 | ">0.2%", 56 | "not dead", 57 | "not ie <= 11", 58 | "not op_mini all" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /packages/ui_v2/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dOrgTech/DAOcreator/09db2fdb239c69f8c12ad58fd0a84c3789335484/packages/ui_v2/public/favicon.ico -------------------------------------------------------------------------------- /packages/ui_v2/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 15 | 16 | 20 | 21 | 22 | 31 | DAOcreator 32 | 33 | 38 | 39 | 40 | 41 |
42 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /packages/ui_v2/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "DAOcreator", 3 | "name": "DAOcreator", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/InstallStep.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, Fragment } from "react"; 2 | import Migrator from "../commonV2/dao/Migrator"; 3 | import { 4 | DAOForm, 5 | } from "@dorgtech/daocreator-lib"; 6 | import { MDBAlert, MDBIcon, MDBContainer, MDBTooltip } from "mdbreact"; 7 | import './styles.css' 8 | 9 | interface Props { 10 | form: DAOForm; 11 | setLaunching: (launching: boolean) => void; 12 | migrationStates: any; 13 | } 14 | 15 | const InstallStep: FC = ({ migrationStates }: Props) => { 16 | const { alchemyAdds } = migrationStates; 17 | return ( 18 | <> 19 | 20 | 21 | 22 | 23 | Attempting to speed up transactions will BREAK deployment! 24 | 25 | {alchemyAdds.map((address: string) => ( 26 | 27 | 28 | Save your new DAO's 29 | 30 |
{ 32 | navigator.clipboard.writeText(address); 33 | }} 34 | style={{ 35 | cursor: "pointer", 36 | display: "inline-block", 37 | color: "blue" 38 | }} 39 | > 40 |  Alchemy URL  41 |
42 |
Click to copy
43 |
44 | to avoid losing it 45 |
46 | ))} 47 |
48 |
49 | 50 | 51 | ); 52 | }; 53 | 54 | export default InstallStep; 55 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/MembersStep.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { MembersForm } from "@dorgtech/daocreator-lib"; 3 | import { MDBRow, MDBCol, MDBBox, MDBContainer } from "mdbreact"; 4 | 5 | import MembersEditor from "../commonV2/dao/Members/MembersEditor"; 6 | 7 | interface Props { 8 | form: MembersForm; 9 | loadedFromModal: boolean; 10 | toggleCollapse: () => void; 11 | } 12 | 13 | const MembersStep: FC = ({ 14 | form, 15 | toggleCollapse, 16 | loadedFromModal 17 | }) => ( 18 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | ); 31 | 32 | const styles = { 33 | setDescriptionButton: { 34 | borderRadius: "0.37rem", 35 | height: "45px", 36 | fontWeight: 300, 37 | backgroundColor: "#1976d2", 38 | color: "white", 39 | width: "145px", 40 | padding: "7px", 41 | marginTop: "20px", 42 | fontSize: "smaller" 43 | }, 44 | padding: { 45 | padding: "4px" 46 | } 47 | }; 48 | 49 | export default MembersStep; 50 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/NamingStep.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useEffect } from "react"; 2 | import { DAOConfigForm } from "@dorgtech/daocreator-lib"; 3 | import { observer } from "mobx-react"; 4 | import DAOConfigEditor from "../commonV2/dao/DAOConfigEditor"; 5 | import { MDBRow, MDBCol } from "mdbreact"; 6 | import "./styles.css"; 7 | 8 | interface Props { 9 | form: DAOConfigForm; 10 | toggleCollapse: () => void; 11 | } 12 | 13 | export type NamingError = { 14 | daoName: boolean; 15 | tokenSymbol: boolean; 16 | }; 17 | 18 | // Please refactor this 19 | const NamingStep: FC = observer(({ form, toggleCollapse }) => { 20 | 21 | useEffect(() => { 22 | form.$.tokenName.value = form.$.daoName.value + " token"; 23 | // eslint-disable-next-line react-hooks/exhaustive-deps 24 | }, [form.$.daoName.$]); 25 | 26 | return ( 27 |
28 |
29 | 33 |
34 | 35 | 36 | 48 | 49 | 50 |
51 | ); 52 | }); 53 | 54 | const styles = { 55 | buttonActivatedStyle: { 56 | borderRadius: "0.37rem", 57 | height: "45px", 58 | fontWeight: 300, 59 | backgroundColor: "#1976d2", 60 | color: "white", 61 | width: "145px", 62 | padding: "7px", 63 | marginBottom: "11px", 64 | fontSize: "smaller" 65 | }, 66 | buttonDeactivatedStyle: { 67 | borderRadius: "0.37rem", 68 | height: "45px", 69 | fontWeight: 300, 70 | backgroundColor: "white", 71 | color: "#1976d2", 72 | width: "145px", 73 | padding: "7px", 74 | marginBottom: "11px", 75 | fontSize: "smaller" 76 | }, 77 | paddingBottom: { 78 | paddingBottom: "0%" 79 | }, 80 | paddingTotal: { 81 | padding: "0px" 82 | } 83 | }; 84 | 85 | export default NamingStep; 86 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/Review.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { MDBRow, MDBCol, MDBIcon } from "mdbreact"; 3 | import LineGraphic from "../commonV2/LineGraphic"; 4 | import { getSimpleOptions, SimpleOption } from "../utils"; 5 | import { DAOForm } from "@dorgtech/daocreator-lib"; 6 | 7 | const FirstStep: FC = form => { 8 | const { daoName, tokenSymbol } = form.$.config.$; 9 | return ( 10 |
11 |

Config

12 | 13 | 14 | 15 | Name: {daoName.value} 16 | 17 | 18 | 19 | 20 | Symbol: {tokenSymbol.value} 21 | 22 | 23 | 24 |
25 | ); 26 | }; 27 | 28 | const SecondStep: FC = form => ( 29 |
30 |

Schemes

31 | {getSimpleOptions(form.$.schemes).map( 32 | ({ text, checked }: SimpleOption, index: number) => ( 33 |
34 |

35 | 40 | {text} 41 |

42 |
43 | ) 44 | )} 45 |
46 | ); 47 | 48 | const ThirdStep: FC = form => { 49 | const { config, members } = form.$; 50 | const { daoName, tokenSymbol } = config.$; 51 | 52 | const reputationConfig = { 53 | showPercentage: false, 54 | height: "0.5rem", 55 | symbol: "REP", 56 | dataKey: "reputation", 57 | nameKey: "address" 58 | }; 59 | const tokenConfig = { 60 | showPercentage: false, 61 | height: "0.5rem", 62 | symbol: tokenSymbol.value, 63 | dataKey: "tokens", 64 | nameKey: "address" 65 | }; 66 | let totalReputationAmount = 0; 67 | let totalTokenAmount = 0; 68 | members.toState().map(member => { 69 | totalReputationAmount += member.reputation; 70 | if (member.tokens) totalTokenAmount += member.tokens; 71 | return member; 72 | }); 73 | const numberOfMembers = members.$.length; 74 | const membersTokenCount = (count: any, member: any) => 75 | +Number(member.$.tokens.value) + count; 76 | const hasTokens = members.$.reduce(membersTokenCount, 0) > 0; 77 | return ( 78 |
79 |

Members

80 |

81 | {numberOfMembers} Member{numberOfMembers > 1 && "s"} 82 |

83 |
84 |

Reputation Distribution

85 | 91 |
92 | {hasTokens && ( 93 |
94 |

{daoName.value} Token Distribution

95 | 101 |
102 | )} 103 |
104 | ); 105 | }; 106 | 107 | const steps = [FirstStep, SecondStep, ThirdStep]; 108 | 109 | interface Props { 110 | recoveredForm: any; 111 | } 112 | 113 | export const Review: FC = ({ recoveredForm }) => ( 114 | <> 115 | {steps.map((ActualStep, index: number) => ( 116 | 117 | ))} 118 | 119 | ); 120 | 121 | const styles = { 122 | first: { 123 | row: { 124 | marginRight: "auto", 125 | marginLeft: "1.5rem", 126 | whiteSpace: "nowrap" 127 | } 128 | }, 129 | second: { 130 | container: { 131 | marginTop: 28 132 | }, 133 | checked: { 134 | marginRight: "10px" 135 | }, 136 | unchecked: { 137 | // x icon is smaller 138 | marginLeft: "3px", 139 | marginRight: "12px" 140 | } 141 | }, 142 | third: { 143 | container: { 144 | marginTop: 28, 145 | paddingRight: "8rem" 146 | }, 147 | reputationDistribution: { 148 | width: "17.5em" 149 | }, 150 | lineGraphic: { 151 | padding: "unset" 152 | }, 153 | hasTokens: { 154 | paddingTop: "20px", 155 | width: "17.5em" 156 | } 157 | } 158 | }; 159 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/SchemesStep.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useState, useEffect } from "react"; 2 | import { 3 | SchemesForm, 4 | ContributionRewardForm, 5 | SchemeRegistrarForm 6 | } from "@dorgtech/daocreator-lib"; 7 | 8 | import SchemeEditor, { DAOSpeed } from "../commonV2/dao/Schemes/SchemeEditor"; 9 | 10 | interface Props { 11 | form: SchemesForm; 12 | toggleCollapse: () => void; 13 | modal: boolean; 14 | setModal: (modal: boolean) => void; 15 | loadedFromModal: boolean; 16 | decisionSpeed: DAOSpeed; 17 | setDecisionSpeed: (speed: DAOSpeed) => void; 18 | } 19 | 20 | const SchemesStep: FC = ({ 21 | form, 22 | toggleCollapse, 23 | modal, 24 | setModal, 25 | loadedFromModal, 26 | decisionSpeed, 27 | setDecisionSpeed 28 | }) => { 29 | const [loading, setLoading] = useState(true); 30 | 31 | useEffect(() => { 32 | if (!loading) return; 33 | 34 | form.$ = [new ContributionRewardForm(), new SchemeRegistrarForm()]; 35 | setLoading(false); 36 | }, [loading, form.$]); 37 | 38 | return ( 39 | 48 | ); 49 | }; 50 | 51 | export default SchemesStep; 52 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/DAOcreatorV2/styles.css: -------------------------------------------------------------------------------- 1 | #setDescription:disabled { 2 | pointer-events: none !important; 3 | width: 134px; 4 | height: 34px; 5 | border: 1px solid #eaedf3; 6 | border-radius: 3px; 7 | font-size: 14px; 8 | color: #78797b !important; 9 | } 10 | 11 | #creator-root { 12 | font-family: "Roboto", sans-serif; 13 | max-width: 734px; 14 | border: 1px solid #eaedf3; 15 | box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.04); 16 | border-radius: 4px; 17 | margin: auto; 18 | background-color: white; 19 | } 20 | 21 | @media only screen and (max-width: 500px) { 22 | #menu { 23 | margin: 14px 0px 0px 30px !important; 24 | } 25 | #title { 26 | flex: 0 0 50% !important; 27 | max-width: 50% !important; 28 | padding-right: 12px !important; 29 | padding-left: 12px !important; 30 | } 31 | 32 | .close { 33 | top: 13px !important; 34 | position: absolute !important; 35 | right: 8px !important; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/README.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | ## Common 4 | 5 | Generalized components. 6 | 7 | ## Pages 8 | 9 | Pages that compose the common components. 10 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/assets/icons/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/assets/icons/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/assets/logos/dao-logo-gray.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/DAOstackLogo.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | const logo = require("../assets/logos/dao-logo-gray.svg"); 3 | 4 | const DAOstackLogo = () => { 5 | return ( 6 |
7 | dao-logo.svg 8 | Powered by DAOstack 9 |
10 | ); 11 | }; 12 | 13 | const styles = { 14 | logo: { 15 | marginRight: 20, 16 | width: 30 17 | }, 18 | text: { 19 | color: "#2e88ee", 20 | fontSize: 20 21 | } 22 | }; 23 | 24 | export default DAOstackLogo; 25 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/EthAddressAvatar/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "react-blockies"; 2 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/EthAddressAvatar/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import makeBlockie from "ethereum-blockies-base64"; 3 | 4 | export type Props = { 5 | address: string; 6 | height?: string; 7 | paddingLeft?: string; 8 | }; 9 | 10 | const EthAddressAvatar: FC = ({ 11 | address, 12 | height = "30px", 13 | paddingLeft = "10px" 14 | }) => ( 15 | identicon window.open(`https://etherscan.io/address/${address}`)} 21 | style={{ 22 | paddingLeft: paddingLeft, 23 | cursor: "pointer" 24 | }} 25 | tabIndex={-1} 26 | height={height} 27 | /> 28 | ); 29 | 30 | export default EthAddressAvatar; 31 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/FormField/styles.css: -------------------------------------------------------------------------------- 1 | ::placeholder { 2 | /* Chrome, Firefox, Opera, Safari 10.1+ */ 3 | color: #9ea0a5; 4 | opacity: 1; /* Firefox */ 5 | } 6 | 7 | .col-6 { 8 | flex: 0 0 50%; 9 | max-width: 50%; 10 | padding-right: 12px !important; 11 | padding-left: 12px !important; 12 | } 13 | 14 | input:hover { 15 | border-color: #1665d8 !important; 16 | } 17 | 18 | input:active { 19 | border-color: #1665d8 !important; 20 | } 21 | 22 | .days { 23 | margin-left: -50px; 24 | } 25 | 26 | .hours { 27 | margin-left: -38px; 28 | } 29 | 30 | #durationInputsCol { 31 | margin-left: -43px; 32 | } 33 | 34 | #durationLabel { 35 | margin-top: 6px; 36 | } 37 | 38 | @media only screen and (max-width: 500px) { 39 | #img { 40 | margin: 0; 41 | } 42 | 43 | .col-6 { 44 | padding-right: 6px !important; 45 | padding-left: 6px !important; 46 | flex: 0 0 100% !important; 47 | width: 100%; 48 | max-width: 100% !important; 49 | } 50 | 51 | .col-9 { 52 | padding-right: 0; 53 | padding-left: 0; 54 | margin-top: 0; 55 | max-width: 100% !important; 56 | flex: 0 0 100% !important; 57 | } 58 | 59 | #icon { 60 | margin: auto !important; 61 | padding-left: 4px; 62 | } 63 | 64 | .col-1 { 65 | margin: auto; 66 | } 67 | 68 | label { 69 | font-size: 14px; 70 | } 71 | 72 | .days { 73 | margin-left: -50px; 74 | } 75 | 76 | .hours { 77 | margin-left: -28px; 78 | } 79 | 80 | p { 81 | font-size: 12px; 82 | } 83 | 84 | #durationCol { 85 | padding-top: 14px; 86 | padding-bottom: 10px; 87 | width: 355px; 88 | } 89 | 90 | #durationInputsRow { 91 | margin-left: 0px!important; 92 | margin-right: 0px!important; 93 | } 94 | 95 | #durationInputsCol { 96 | margin: inherit!important; 97 | } 98 | 99 | #durationLabel { 100 | flex: 0 0 100%; 101 | max-width: 100%; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/LineGraphic.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { 3 | MDBContainer, 4 | MDBProgress, 5 | MDBTooltip, 6 | MDBBox, 7 | MDBRow 8 | } from "mdbreact"; 9 | import EthAddressAvatar from "./EthAddressAvatar"; 10 | 11 | interface Data { 12 | [name: string]: string | number; 13 | } 14 | 15 | interface LineConfig { 16 | showPercentage: boolean; 17 | height: string; 18 | symbol?: string; 19 | dataKey: string; 20 | nameKey: string; 21 | } 22 | 23 | interface Props { 24 | data: Data[]; 25 | total: number; 26 | config: LineConfig; 27 | style?: any; 28 | } 29 | 30 | const LineGraphic: FC = ({ data, total, config, style }) => { 31 | const { showPercentage, height, symbol, dataKey, nameKey } = config; 32 | 33 | const colours = ["success", "info", "warning", "danger"]; 34 | if (total === 0) return null; 35 | 36 | const cleanData = data.filter((element: Data) => { 37 | const value: number = element[dataKey] as number; 38 | if (value > 0) return element; 39 | return null; 40 | }); 41 | 42 | return ( 43 | 44 | {cleanData.map((element: Data, index: number) => { 45 | const value: number = element[dataKey] as number; 46 | const percentage = `${(value / total) * 100}`.toString().substr(0, 4); 47 | const name = element[nameKey] as string; 48 | 49 | let className = ""; 50 | if (index === 0 && index === cleanData.length - 1) 51 | className = "rounded-pill"; 52 | else if (index === 0) className = "rounded-left"; 53 | else if (index === cleanData.length - 1) className = "rounded-right"; 54 | 55 | return ( 56 | 62 |
68 | 76 | {showPercentage && `${percentage}%`} 77 | 78 |
79 | 80 | 81 | 82 |
83 | {`${name.substr(0, 6)}...${name.substring(name.length - 4)}`} 84 |
85 |
86 | 87 |
88 | {`${value} ${symbol}`} ({`${percentage}%`}) 89 |
90 |
91 |
92 |
93 | ); 94 | })} 95 |
96 | ); 97 | }; 98 | 99 | export default LineGraphic; 100 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/Stepper/Preview.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | 3 | import { MembersForm, SchemesForm, DAOConfigForm } from "@dorgtech/daocreator-lib"; 4 | 5 | import LineGraphic from "../LineGraphic"; 6 | import { MDBIcon, MDBRow, MDBCol } from "mdbreact"; 7 | import { SimpleOption, getSimpleOptions } from "../../utils"; 8 | import './styles.css' 9 | 10 | export const ConfigPreview: FC<{ form: DAOConfigForm }> = ({ form }) => ( 11 | 12 | 13 | 14 | Name: {form.$.daoName.value} 15 | 16 | 17 | 18 | 19 | Symbol: {form.$.tokenSymbol.value} 20 | 21 | 22 | 23 | ); 24 | 25 | export const SchemesPreview: FC<{ form: SchemesForm }> = ({ form }) => { 26 | const simpleOptions: SimpleOption[] = getSimpleOptions(form); 27 | 28 | return ( 29 |
30 |

31 | Recommended 32 |

33 | {simpleOptions.map(({ text, checked }: SimpleOption, index: number) => ( 34 |
35 |

36 | 45 | {text} 46 |

47 |
48 | ))} 49 |
50 | ); 51 | }; 52 | 53 | export const MembersPreview: FC<{ form: MembersForm }> = ({ form }) => { 54 | const reputationConfig = { 55 | showPercentage: false, 56 | height: "0.5rem", 57 | symbol: "REP", 58 | dataKey: "reputation", 59 | nameKey: "address" 60 | }; 61 | const tokenConfig = { 62 | showPercentage: false, 63 | height: "0.5rem", 64 | symbol: form.getDAOTokenSymbol(), 65 | dataKey: "tokens", 66 | nameKey: "address" 67 | }; 68 | let totalReputationAmount = 0; 69 | let totalTokenAmount = 0; 70 | form.toState().map(({ reputation, tokens }: any) => { 71 | totalReputationAmount += reputation; 72 | totalTokenAmount += tokens; 73 | return null; 74 | }); 75 | const numberOfMembers = form.$.length; 76 | return ( 77 |
78 |

79 | {numberOfMembers} Member{numberOfMembers > 1 && "s"} 80 |

81 |
82 |

Reputation Distribution

83 | 89 |
90 | {totalTokenAmount > 0 && ( 91 |
92 |

{form.getDAOTokenSymbol()} Token Distribution

93 | 99 |
100 | )} 101 |
102 | ); 103 | }; 104 | 105 | const styles = { 106 | configPreview: { 107 | marginTop: 33, 108 | marginRight: "auto", 109 | marginLeft: "1.5rem", 110 | whiteSpace: "nowrap" 111 | }, 112 | schemePreview: { 113 | marginTop: 33, 114 | }, 115 | membersPreview: { 116 | marginTop: 33, 117 | paddingRight: "8rem" 118 | }, 119 | lineGraphic: { 120 | padding: "unset" 121 | } 122 | }; 123 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/Stepper/UtilityButton.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import './styles.css'; 3 | 4 | interface Props { 5 | title: string; 6 | openModal: (i: boolean | string) => void; 7 | id?: string | undefined 8 | } 9 | export function UtilityButton(props: Props) { 10 | const { title, openModal, id } = props; 11 | const handledCallback = () => { 12 | if (title === "Import CSV") { 13 | openModal(title); 14 | } else { 15 | openModal(true); 16 | } 17 | }; 18 | return ( 19 | 22 | ); 23 | } 24 | 25 | const styles = { 26 | button: { 27 | width: "174px", 28 | height: "42px", 29 | padding: "4px", 30 | marginRight: "36px", 31 | marginTop: "20px", 32 | border: "1px solid gray", 33 | boxShadow: "none", 34 | borderRadius: "4px", 35 | fontFamily: '"Roboto", sans-serif', 36 | fontWeight: 300, 37 | fontSize: "15px" 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/Stepper/styles.css: -------------------------------------------------------------------------------- 1 | .daocreator-root .stepper-vertical li:not(:last-child):after { 2 | position: absolute; 3 | top: 3.9rem; 4 | left: 46px; 5 | width: 1px; 6 | height: calc(100% - 0px); 7 | content: ""; 8 | background-color: #ededef; 9 | } 10 | 11 | .daocreator-root ul.stepper li a .circle { 12 | display: inline-block; 13 | width: 32px; 14 | margin-right: 0.5rem; 15 | line-height: 1.7rem; 16 | color: #fff; 17 | text-align: center; 18 | background: rgba(0, 0, 0, 0.38); 19 | border-radius: 50%; 20 | padding-top: 2px; 21 | } 22 | 23 | .daocreator-root ul.stepper li.completed a .circle { 24 | border: #1665d8; 25 | background-color: #1665d8 !important; 26 | } 27 | 28 | .daocreator-root ul.stepper li.active a .label, 29 | ul.stepper li.completed a .label { 30 | font-weight: 600; 31 | color: #1665d8; 32 | } 33 | 34 | .editStep { 35 | margin-top: 10.5px; 36 | } 37 | 38 | @media only screen and (max-width: 500px) { 39 | #step { 40 | padding: 12px !important; 41 | } 42 | 43 | .stepper-vertical li:not(:last-child):after { 44 | top: 2.8rem !important; 45 | left: 27px !important; 46 | } 47 | #label { 48 | margin: 3px !important; 49 | } 50 | 51 | #row { 52 | padding: 14px 14px !important; 53 | margin: 0px 2% 0px 14.5% !important; 54 | } 55 | 56 | #pencil { 57 | margin-right: 4px !important; 58 | padding: inherit !important; 59 | } 60 | 61 | #modal { 62 | width: 100px !important; 63 | height: 40px !important; 64 | padding: 4px; 65 | margin-right: 9px !important; 66 | margin-top: 7px !important; 67 | font-size: 13px !important; 68 | } 69 | 70 | #importCSV { 71 | width: 100px !important; 72 | height: 40px !important; 73 | padding: 4px; 74 | margin-right: 9px !important; 75 | margin-top: 7px !important; 76 | font-size: 13px !important; 77 | } 78 | 79 | #importButton { 80 | margin-right: 0px; 81 | } 82 | 83 | #preview { 84 | margin-left: 60px; 85 | max-width: 50%; 86 | margin-top: 0px !important; 87 | } 88 | 89 | #membersCount { 90 | width: 100px; 91 | } 92 | 93 | #importButton { 94 | padding-top: 0% !important; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/DAOConfigEditor.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { observer } from "mobx-react"; 3 | import { MDBRow } from "mdbreact"; 4 | 5 | import { DAOConfigForm } from "@dorgtech/daocreator-lib"; 6 | import FormField from "../FormField"; 7 | 8 | interface Props { 9 | form: DAOConfigForm; 10 | editable: boolean; 11 | } 12 | 13 | const DAOConfigEditor: FC = ({ 14 | form, 15 | editable, 16 | }) => ( 17 | 18 | 24 | 30 | 31 | ); 32 | 33 | export default observer(DAOConfigEditor); 34 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Members/MemberEditor.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { MDBRow, MDBCol } from "mdbreact"; 3 | 4 | import FormField from "../../FormField"; 5 | import { MemberForm } from "@dorgtech/daocreator-lib"; 6 | import './styles.css'; 7 | 8 | export const MemberEditor = ({ memberForm, onSubmit }: { memberForm: MemberForm; onSubmit: (event: any) => void }) => { 9 | return ( 10 | { 13 | if (event.key === "Enter") onSubmit(event); 14 | }} 15 | > 16 | 17 | 18 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | const styles = { 27 | setDescriptionButton: { 28 | borderRadius: "0.37rem", 29 | fontWeight: 300, 30 | height: "39px", 31 | padding: "8px", 32 | fontFamily: "inherit", 33 | fontSize: "14px", 34 | width: "inherit", 35 | marginTop: "28px" 36 | }, 37 | rowPrincipal: { 38 | margin: 0, 39 | width: "100%", 40 | paddingBottom: "25px" 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Members/MembersAnalytics.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useEffect, useState } from "react"; 2 | import { MDBRow, MDBCol } from "mdbreact"; 3 | 4 | import LineGraphic from "../../LineGraphic"; 5 | 6 | // Right now TS can't cast [key: string]: string | number but it can cast [key: string]: any despite an interface only having strings and numbers 7 | // https://stackoverflow.com/questions/37006008/typescript-index-signature-is-missing-in-type 8 | interface Data { 9 | // [name: string]: string | number; 10 | [name: string]: any; 11 | } 12 | 13 | interface LineConfig { 14 | showPercentage: boolean; 15 | height: string; 16 | symbol?: string; 17 | dataKey: string; 18 | nameKey: string; 19 | } 20 | 21 | interface Props { 22 | data: Data[]; // TODO Potentially update data type to flattened form type, 23 | tokenSymbol: string; 24 | } 25 | 26 | export const MembersAnalytics: FC = ({ data, tokenSymbol }) => { 27 | const tokenConfig = { 28 | showPercentage: false, 29 | height: "0.5rem", 30 | symbol: tokenSymbol, 31 | dataKey: "tokens", 32 | nameKey: "address" 33 | }; 34 | 35 | const reputationConfig = { 36 | showPercentage: false, 37 | height: "0.5rem", 38 | symbol: "REP", 39 | dataKey: "reputation", 40 | nameKey: "address" 41 | }; 42 | 43 | const [totalTokenAmount, setTotalTokenAmount] = useState(0); 44 | const [totalReputationAmount, setTotalReputationAmount] = useState(0); 45 | 46 | useEffect(() => { 47 | let count = 0; 48 | data.map((element: Data) => { 49 | count += element[tokenConfig.dataKey] as number; 50 | return element; 51 | }); 52 | setTotalTokenAmount(count); 53 | }, [data, tokenConfig.dataKey]); 54 | 55 | useEffect(() => { 56 | let count = 0; 57 | data.map((element: Data) => { 58 | count += element[reputationConfig.dataKey] as number; 59 | return element; 60 | }); 61 | setTotalReputationAmount(count); 62 | }, [data, reputationConfig.dataKey]); 63 | 64 | interface BoxProps { 65 | name: string; 66 | total: number; 67 | config: LineConfig; 68 | } 69 | 70 | const Box: FC = ({ name, total, config }) => 71 | total === 0 ? null : ( 72 | 73 | 74 |
{name}
75 |
76 | 77 | 78 | 79 |
80 | ); 81 | 82 | const AnalyticsBoxes: FC = () => { 83 | const reputationBox = ( 84 | 89 | ); 90 | const tokenBox = ( 91 | 96 | ); 97 | 98 | if (totalReputationAmount === 0 && totalTokenAmount === 0) return null; 99 | 100 | return ( 101 |
102 | {reputationBox} 103 | {totalReputationAmount !== 0 && totalTokenAmount !== 0 &&
} 104 | {tokenBox} 105 |
106 | ); 107 | }; 108 | 109 | return ; 110 | }; 111 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Members/MembersTable.tsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment, FC } from "react"; 2 | import { MemberForm } from "@dorgtech/daocreator-lib"; 3 | import { 4 | MDBRow, 5 | MDBContainer, 6 | MDBTooltip, 7 | MDBBtn, 8 | MDBIcon, 9 | MDBCol 10 | } from "mdbreact"; 11 | 12 | import EthAddressAvatar from "../../EthAddressAvatar"; 13 | import FormField from "../../FormField"; 14 | import { truncateString } from "../../../utils"; 15 | 16 | const pencilIcon = require("../../../assets/icons/pencil.svg"); 17 | 18 | interface Props { 19 | membersForm: any; 20 | editing: number; 21 | editedMemberForm: MemberForm; 22 | onEdit: any; 23 | onDelete: any; 24 | selectEdit: any; 25 | cancelEdit: any; 26 | tokenDistribution: boolean; 27 | getDAOTokenSymbol: () => string; 28 | } 29 | 30 | interface RowProps { 31 | memberForm: MemberForm; 32 | index: number; 33 | } 34 | 35 | export const MembersTable: FC = ({ 36 | membersForm, 37 | editing, 38 | editedMemberForm, 39 | onEdit, 40 | onDelete, 41 | selectEdit, 42 | cancelEdit, 43 | tokenDistribution, 44 | getDAOTokenSymbol 45 | }) => { 46 | const Row: FC = ({ memberForm, index }) => { 47 | const lineEdit = editing === index; 48 | 49 | return ( 50 | 53 | 54 | 55 | 56 | 57 |
58 | 59 |
{ 61 | navigator.clipboard.writeText(memberForm.values.address); 62 | }} 63 | style={ 64 | (styles.noPadding, 65 | { cursor: "pointer", display: "inline-block", color: "blue" }) 66 | } 67 | > 68 | {truncateString(memberForm.values.address, 6, 4)} 69 |
70 |
Click to copy
71 |
72 | 74 | window.open( 75 | `https://etherscan.io/address/${memberForm.values.address}` 76 | ) 77 | } 78 | floating 79 | size="lg" 80 | color="transparent" 81 | style={styles.link} 82 | > 83 |
84 |
85 | 86 | {lineEdit ? ( 87 |
{ 90 | if (event.key === "Enter") onEdit(index); 91 | }} 92 | > 93 | 99 |
100 | ) : ( 101 |
102 | {memberForm.values.reputation} 103 |
104 | )} 105 |
106 | {tokenDistribution && ( 107 | 108 | {lineEdit ? ( 109 |
{ 112 | if (event.key === "Enter") onEdit(index); 113 | }} 114 | > 115 | 121 |
122 | ) : ( 123 |
{memberForm.values.tokens}
124 | )} 125 |
126 | )} 127 | 128 |
{ 130 | lineEdit ? onEdit(index) : selectEdit(index); 131 | }} 132 | style={styles.editCol} 133 | id="editCol" 134 | > 135 | {lineEdit ? ( 136 | 137 | ) : ( 138 | menu icon 139 | )} 140 |
141 |
142 | 143 |
{ 145 | lineEdit ? cancelEdit() : onDelete(index); 146 | }} 147 | style={styles.editCol} 148 | id="editCol" 149 | > 150 | {lineEdit ? ( 151 | 152 | ) : ( 153 | 154 | )} 155 |
156 |
157 |
158 | ); 159 | }; 160 | 161 | if (membersForm.$.length === 0) return ; 162 | 163 | return ( 164 | 165 |
166 | 167 | 168 | MEMBERS 169 | 170 | 171 | REPUTATION 172 | 173 | 174 | {tokenDistribution && ( 175 | 176 | {getDAOTokenSymbol()} TOKEN 177 | 178 | )} 179 | 180 | 181 | 182 | {membersForm.$.map((memberForm: MemberForm, index: number) => ( 183 | 184 | ))} 185 |
186 |
187 | ); 188 | }; 189 | 190 | const styles = { 191 | tableWidth: { 192 | width: "-webkit-fill-available", 193 | marginLeft: "-10.5px", 194 | marginRight: "-11.5px", 195 | borderBottom: "0.5px solid lightgray", 196 | borderTop: "0.5px lightgray", 197 | padding: "5px" 198 | }, 199 | titles: { 200 | fontSize: "13px", 201 | color: "gray", 202 | padding: "10px 0" 203 | }, 204 | borderCell: { 205 | padding: "5px 0", 206 | paddingTop: "7px", 207 | paddingRight: '1px', 208 | paddingLeft: '1px' 209 | }, 210 | addressCell: { 211 | marginLeft: "-5px", 212 | padding: "5px 0" 213 | }, 214 | avatarCell: { 215 | width: "20px", 216 | padding: "5px 0", 217 | paddingTop: "7px" 218 | }, 219 | noPadding: { 220 | padding: 0 221 | }, 222 | link: { 223 | backgroundColor: "transparent !important", 224 | color: "lightgray", 225 | boxShadow: "none", 226 | fontSize: "normal", 227 | border: "none", 228 | outline: "none", 229 | padding: 0, 230 | margin: "2px", 231 | marginLeft: "14px" 232 | }, 233 | editCol: { 234 | paddingTop: "5px", 235 | cursor: "pointer", 236 | } 237 | }; 238 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Members/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./MembersEditor"; 2 | export * from "./MemberEditor"; 3 | export * from "./MembersAnalytics"; 4 | export * from "./MembersTable"; 5 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Members/styles.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 500px) { 2 | #addMemberButton { 3 | width: 100px !important; 4 | height: 40px !important; 5 | padding: 4px; 6 | margin-right: 9px !important; 7 | margin-top: 7px !important; 8 | font-size: 13px !important; 9 | } 10 | 11 | #addMember { 12 | flex: 0 0 50%; 13 | max-width: 100%; 14 | margin: auto; 15 | } 16 | 17 | #tokenName { 18 | padding: 0px 0px 0px 100px !important; 19 | } 20 | 21 | #reputationTitle { 22 | max-width: 0px !important; 23 | } 24 | 25 | #reputationValue { 26 | max-width: 33% !important; 27 | margin-left: 60px; 28 | } 29 | 30 | #addressAvatar { 31 | display: none; 32 | } 33 | 34 | #addressHex { 35 | margin-left: 0px !important; 36 | } 37 | 38 | #tokenValueCol { 39 | max-width: 15%; 40 | } 41 | 42 | #tokenValue { 43 | margin-left: 15px; 44 | } 45 | 46 | #editCol { 47 | padding: 0px 0px 20px !important; 48 | } 49 | } 50 | 51 | #tokenName { 52 | font-size: 13px; 53 | color: gray; 54 | padding: 10px 0; 55 | } 56 | 57 | #reputationTitle { 58 | font-size: 13px; 59 | color: gray; 60 | padding: 10px 0; 61 | } 62 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Migrator/LogLineTypes.ts: -------------------------------------------------------------------------------- 1 | export enum LogType { 2 | Info, 3 | Error, 4 | TransactionResult, 5 | UserApproval, 6 | MigrationAborted 7 | } 8 | 9 | export interface LogLine { 10 | type: LogType; 11 | toString: () => string; 12 | } 13 | 14 | export class LogInfo implements LogLine { 15 | public type = LogType.Info; 16 | constructor(public info: string) {} 17 | 18 | public toString() { 19 | return this.info; 20 | } 21 | } 22 | 23 | export class LogError implements LogLine { 24 | public type = LogType.Error; 25 | constructor(public error: string) {} 26 | 27 | public toString() { 28 | return `${this.error}`; 29 | } 30 | } 31 | 32 | export class LogTransactionResult implements LogLine { 33 | public type = LogType.TransactionResult; 34 | constructor( 35 | public msg: string, 36 | public txHash: string, 37 | public txCost: number 38 | ) {} 39 | 40 | public toString() { 41 | return `${this.msg} ${this.txHash} ${this.txCost} ETH`; 42 | } 43 | } 44 | 45 | export class LogUserApproval implements LogLine { 46 | public type = LogType.UserApproval; 47 | public response?: boolean; 48 | constructor( 49 | public question: string, 50 | public onResponse: (resp: boolean) => void 51 | ) {} 52 | 53 | public toString() { 54 | return `${this.question} response: ${this.response}`; 55 | } 56 | } 57 | 58 | export class LogMigrationAborted implements LogLine { 59 | public type = LogType.MigrationAborted; 60 | constructor(public error: Error) {} 61 | 62 | public toString() { 63 | return `${this.error}`; 64 | } 65 | } 66 | 67 | export type AnyLogLine = 68 | | LogInfo 69 | | LogError 70 | | LogTransactionResult 71 | | LogUserApproval 72 | | LogMigrationAborted; 73 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Migrator/OrganizationLine.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, useState, useEffect } from "react"; 2 | import { MDBRow, MDBCol, MDBIcon } from "mdbreact"; 3 | import './styles.css' 4 | 5 | interface Props { 6 | type: number; 7 | active: boolean; 8 | done: boolean; 9 | failed: boolean; 10 | logLines: string[]; 11 | } 12 | 13 | enum STEP { 14 | Waiting, 15 | Start, 16 | Confirmed, 17 | Failed 18 | } 19 | 20 | export const OrganizationLine: FC = ({ 21 | type, 22 | active, 23 | done, 24 | failed, 25 | logLines 26 | }) => { 27 | const [step, setStep] = useState(STEP.Waiting); 28 | const [lastLog, setLastLog] = useState( 29 | type === 0 ? "Start Installation" : "Waiting" 30 | ); 31 | 32 | useEffect(() => { 33 | if (done) { 34 | if (step === STEP.Confirmed) return; 35 | setStep(STEP.Confirmed); 36 | return; 37 | } 38 | 39 | if (failed) { 40 | if (step === STEP.Failed) return; 41 | setStep(STEP.Failed); 42 | return; 43 | } 44 | 45 | if (!active) { 46 | if (step === STEP.Waiting) return; 47 | setStep(STEP.Waiting); 48 | return; 49 | } 50 | 51 | if (step === STEP.Start) return; 52 | setStep(STEP.Start); 53 | }, [active, done, step, failed]); 54 | 55 | useEffect(() => { 56 | if (done || (!active && !failed)) return; 57 | if (logLines.length > 0) setLastLog(logLines[logLines.length - 1]); 58 | }, [logLines, active, done, failed]); 59 | 60 | const StepName: FC = () => { 61 | const stepName = 62 | type === 0 ? "Create Organization" : "Configure Organization"; 63 | 64 | return step !== STEP.Waiting ? ( 65 |
{stepName}
66 | ) : ( 67 |
{stepName}
68 | ); 69 | }; 70 | 71 | const Output: FC = () => { 72 | let text = undefined; 73 | 74 | switch (step) { 75 | case STEP.Waiting: 76 | text = type === 0 ? "Start Installation" : "Waiting"; 77 | break; 78 | 79 | case STEP.Start: 80 | text = lastLog; 81 | break; 82 | 83 | case STEP.Confirmed: 84 | text = "Confirmed"; 85 | break; 86 | 87 | case STEP.Failed: 88 | text = lastLog; 89 | break; 90 | 91 | default: 92 | console.log("Unimplemented step"); 93 | } 94 | 95 | return
{text}
; // Should link to txHash 96 | }; 97 | 98 | return ( 99 | 100 | 101 | {/* TODO 2x is a little big and default is small */} 102 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
115 | {step === STEP.Start && ( 116 |
120 | )} 121 | {step === STEP.Confirmed && ( 122 | 123 | )} 124 | {step === STEP.Failed && ( 125 | 126 | )} 127 |
128 | 129 | ); 130 | }; 131 | 132 | export default OrganizationLine; 133 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Migrator/index.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC, Fragment, useEffect } from "react"; 2 | import { MDBContainer, MDBRow, MDBBtn, MDBBtnGroup } from "mdbreact"; 3 | import OrganizationLine from "./OrganizationLine"; 4 | 5 | interface IProps { 6 | migrationStates: any; 7 | } 8 | 9 | // Migrator Steps 10 | enum STEP { 11 | Waiting, 12 | Creating, 13 | Configuring, 14 | Completed 15 | } 16 | 17 | // Migrator Steps 18 | enum FAILED { 19 | Create, 20 | Config 21 | } 22 | 23 | const Migrator: FC = ({ migrationStates }: IProps) => { 24 | const { 25 | installStep, 26 | minimalLogLines, 27 | approval, 28 | aborting, 29 | setAborting, 30 | failed, 31 | setFailed 32 | } = migrationStates; 33 | useEffect(() => { 34 | if (!aborting) return; 35 | 36 | setAborting(false); 37 | if (installStep === STEP.Creating) setFailed(FAILED.Create); 38 | else if (installStep === STEP.Configuring) setFailed(FAILED.Config); 39 | }, [aborting, installStep, setAborting, setFailed]); 40 | 41 | return ( 42 | 43 | {approval && approval.msg && ( 44 | 45 | 46 |
{approval.msg}
47 |
48 | 49 | 50 | approval.response(true)}>Yes 51 | approval.response(false)}>No 52 | 53 | 54 |
55 | )} 56 | 57 | {/* Create Organization */} 58 | 67 | 68 | {/* Configure Organization */} 69 | 76 |
77 | ); 78 | }; 79 | 80 | export default Migrator; 81 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Migrator/styles.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 500px) { 2 | #iconCol { 3 | margin: initial !important; 4 | } 5 | 6 | .col-4 { 7 | font-size: 14px; 8 | } 9 | #outputCol { 10 | margin-top: -32px !important; 11 | font-size: 14px; 12 | } 13 | 14 | .my-1{ 15 | margin-bottom :.85rem!important 16 | } 17 | 18 | #installButton { 19 | border-radius: 0.37rem; 20 | height: 45px; 21 | font-weight: 300; 22 | color: white; 23 | width: 145px; 24 | padding: 7px; 25 | margin-top: 20px; 26 | font-size: smaller; 27 | text-align: center; 28 | padding: initial; 29 | } 30 | } -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Schemes/Toggle.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { MDBBtn, MDBRow, MDBCol, MDBTooltip, MDBIcon } from "mdbreact"; 3 | 4 | interface Props { 5 | id: string; 6 | text: string; 7 | tooltip: string; 8 | toggle: () => void; 9 | disabled?: boolean; 10 | checked: boolean; 11 | style?: any; 12 | } 13 | 14 | const Toggle: FC = ({ 15 | id, 16 | text, 17 | tooltip, 18 | toggle, 19 | disabled = false, 20 | checked, 21 | style 22 | }) => ( 23 | 24 | 25 | 26 | {text} 27 | 28 | 29 | 30 | 31 | 32 | {tooltip} 33 | 34 | 35 | 36 |
37 | 45 | 46 |
47 |
48 |
49 | ); 50 | 51 | const styles = { 52 | paddingRow: { 53 | paddingLeft: "10px", 54 | paddingTop: "6px" 55 | }, 56 | info: { 57 | backgroundColor: "transparent !important", 58 | color: "lightgray", 59 | boxShadow: "none", 60 | fontSize: "large", 61 | border: "none", 62 | outline: "none" 63 | }, 64 | noPadding: { 65 | padding: 0 66 | }, 67 | marginText: { 68 | marginTop: "6px", 69 | color: "black", 70 | fontSize: "16px" 71 | } 72 | }; 73 | 74 | export default Toggle; 75 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Schemes/index.tsx: -------------------------------------------------------------------------------- 1 | export * from "./AdvancedEditor"; 2 | export * from "./SchemeEditor"; 3 | export * from "./Toggle"; 4 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/Schemes/styles.css: -------------------------------------------------------------------------------- 1 | @media only screen and (max-width: 500px) { 2 | #col { 3 | flex: 100%; 4 | } 5 | 6 | .col-11 { 7 | flex: 0 0 86.666667%; 8 | } 9 | 10 | #toggle { 11 | margin: auto; 12 | } 13 | 14 | #toggleScheme { 15 | padding-left: 1.25rem !important; 16 | } 17 | 18 | #resetButton { 19 | margin-left: 70px; 20 | } 21 | 22 | #saveConfigurationButton { 23 | width: 184px !important; 24 | margin-right: 30px; 25 | } 26 | 27 | #tabButton { 28 | overflow: hidden; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/commonV2/dao/VotingMachineEditor.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { AnyField, GenesisProtocolForm } from "@dorgtech/daocreator-lib"; 3 | import FormField from "../FormField"; 4 | import { MDBRow } from "mdbreact"; 5 | 6 | interface Props { 7 | votingMachine: GenesisProtocolForm; 8 | editable: boolean; 9 | } 10 | 11 | const VotingMachineEditor: FC = ({ votingMachine, editable }) => { 12 | const iterableFields: string[] = Object.keys(votingMachine.$); 13 | 14 | return ( 15 | <> 16 | {iterableFields.map((key: string, index: number) => { 17 | const field: AnyField = votingMachine.$[key]; 18 | const prevField: AnyField = votingMachine.$[iterableFields[index - 1]]; 19 | 20 | if (index <= 3) { 21 | return ( 22 | 28 | ); 29 | } else if (index % 2 !== 0) { 30 | return ( 31 | 32 | 37 | 42 | 43 | ); 44 | } 45 | return null; 46 | })} 47 | 48 | ); 49 | }; 50 | 51 | export default VotingMachineEditor; 52 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { ProviderOrGetter } from "@dorgtech/daocreator-lib"; 3 | 4 | import DAOcreatorV2 from "./DAOcreatorV2/index"; 5 | 6 | interface Props { 7 | setWeb3Provider?: ProviderOrGetter; 8 | noDAOstackLogo?: Boolean; 9 | } 10 | 11 | const Index: React.FC = ({ setWeb3Provider, noDAOstackLogo }) => { 12 | return ( 13 |
14 | 15 |
16 | ); 17 | }; 18 | 19 | export default Index; 20 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/utils/hooks/forceUpdate.hook.ts: -------------------------------------------------------------------------------- 1 | import { useState, useCallback } from "react"; 2 | 3 | export function useForceUpdate() { 4 | const [, setTick] = useState(0); 5 | const update = useCallback(() => { 6 | setTick(tick => tick + 1); 7 | }, []); 8 | return update; 9 | } 10 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/utils/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./forceUpdate.hook"; 2 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./stringUtils"; 2 | export * from "./schemesUtils"; 3 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/utils/schemesUtils.ts: -------------------------------------------------------------------------------- 1 | import { SchemesForm } from "@dorgtech/daocreator-lib"; 2 | 3 | export interface SimpleOption { 4 | text: string; 5 | checked: boolean; 6 | } 7 | 8 | export const getSimpleOptions = (form: SchemesForm) => { 9 | if (form.$.length === 0) return []; 10 | 11 | const { 12 | proposingRepReward, 13 | votersReputationLossRatio, 14 | minimumDaoBounty, 15 | daoBountyConst 16 | } = form.$[0].$.votingMachine.values; 17 | 18 | const simpleOptions: SimpleOption[] = [ 19 | { text: "Reward successful proposer", checked: Number(proposingRepReward) > 0 }, 20 | { 21 | text: "Reward correct voters and penalize incorrect voters", 22 | checked: Number(votersReputationLossRatio) > 0 23 | }, 24 | { 25 | text: "Auto-incentivize proposal curation", 26 | checked: Number(minimumDaoBounty) > 0.000001 && Number(daoBountyConst) >= 1 // TODO Update after daostack lets us use 0 27 | } 28 | ]; 29 | 30 | return simpleOptions; 31 | }; 32 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/utils/stringUtils.ts: -------------------------------------------------------------------------------- 1 | export function truncateString( 2 | str: string, 3 | firstCharCount = str.length, 4 | endCharCount = 0, 5 | dotCount = 3 6 | ) { 7 | let convertedStr = ""; 8 | convertedStr += str.substring(0, firstCharCount); 9 | convertedStr += ".".repeat(dotCount); 10 | convertedStr += str.substring(str.length - endCharCount, str.length); 11 | return convertedStr; 12 | } 13 | -------------------------------------------------------------------------------- /packages/ui_v2/src/components/web3/core.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * The following is covered under the lib 3 | */ 4 | 5 | // import Web3 from "web3"; 6 | // let web3: Web3 | undefined = undefined; // Will hold the web3 instance 7 | 8 | // export async function enableEthereum() { 9 | // async function getAccount() { 10 | // const account = await (window as any).ethereum.enable(); 11 | // web3 = new Web3((window as any).ethereum); 12 | // const defaultAccount = account[0]; 13 | // web3.eth.defaultAccount = defaultAccount; 14 | // return defaultAccount; 15 | // } 16 | 17 | // if (!web3) { 18 | // try { 19 | // // Request account access if needed 20 | // return getAccount(); 21 | // } catch (error) { 22 | // console.log(error); 23 | // return undefined; 24 | // } 25 | // } else { 26 | // return getAccount(); 27 | // } 28 | // } 29 | 30 | export const handleNetworkReload = async () => { 31 | try { 32 | // TODO Handle network change (Only Mainnet and Rinkeby are supported) 33 | (window as any).ethereum.autoRefreshOnNetworkChange = false; 34 | 35 | // Should be implemented by MetaMask soon-tm 36 | (window as any).ethereum.on("chainChanged", (chainId: number) => { 37 | // handle the new network 38 | console.log("Current chain: " + chainId); 39 | return null; 40 | }); 41 | 42 | (window as any).ethereum.on("networkChanged", (networkId: string) => { 43 | // networkId goes from "loading" to the network id (different to chain id) 44 | console.log("Current chain: " + networkId); 45 | return null; 46 | }); 47 | } catch (e) { 48 | console.log(e); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /packages/ui_v2/src/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import * as ReactDOM from "react-dom"; 3 | 4 | import DAOcreator from "./components"; 5 | 6 | ReactDOM.render(, document.getElementById("root") as HTMLElement); 7 | -------------------------------------------------------------------------------- /packages/ui_v2/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/ui_v2/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["es2016", "es2017", "dom", "esnext.asynciterable"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "outDir": "dist", 10 | "resolveJsonModule": true, 11 | "sourceMap": true, 12 | "strict": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "typeRoots": ["node_modules/@types"], 15 | "skipLibCheck": true, 16 | "allowJs": false, 17 | "rootDirs": ["src"], 18 | "jsx": "react", 19 | "forceConsistentCasingInFileNames": true, 20 | "allowSyntheticDefaultImports": true, 21 | "esModuleInterop": true, 22 | "isolatedModules": true, 23 | "noEmit": true 24 | }, 25 | "include": ["src"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/ui_v2/tsconfig.release.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["es2016", "es2017", "dom", "esnext.asynciterable"], 5 | "module": "esnext", 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "outDir": "dist", 10 | "resolveJsonModule": true, 11 | "sourceMap": true, 12 | "strict": true, 13 | "suppressImplicitAnyIndexErrors": true, 14 | "typeRoots": ["node_modules/@types"], 15 | "skipLibCheck": true, 16 | "allowJs": false, 17 | "rootDirs": ["src/components"], 18 | "jsx": "react", 19 | "forceConsistentCasingInFileNames": true, 20 | "allowSyntheticDefaultImports": true, 21 | "esModuleInterop": true, 22 | "declaration": true 23 | }, 24 | "include": ["src/components"] 25 | } 26 | --------------------------------------------------------------------------------