├── .eslintrc.js ├── .github └── stale.yml ├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── package-lock.json ├── package.json ├── src ├── AccountData.js ├── ContractData.js ├── ContractForm.js ├── LoadingContainer.js ├── index.js └── new-context-api │ ├── AccountData.js │ ├── ContractData.js │ └── ContractForm.js ├── test-app-legacy-context ├── .gitignore ├── app │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── MyComponent.js │ │ ├── MyContainer.js │ │ ├── drizzleOptions.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.png │ │ └── serviceWorker.js │ └── yarn.lock ├── contracts │ ├── ComplexStorage.sol │ ├── Migrations.sol │ ├── SimpleStorage.sol │ └── TutorialToken.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test │ ├── TestSimpleStorage.sol │ └── simplestorage.js └── truffle-config.js ├── test-app ├── .gitignore ├── app │ ├── .env │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ ├── favicon.ico │ │ ├── index.html │ │ └── manifest.json │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── MyComponent.js │ │ ├── drizzleOptions.js │ │ ├── index.css │ │ ├── index.js │ │ ├── logo.png │ │ └── serviceWorker.js │ └── yarn.lock ├── contracts │ ├── ComplexStorage.sol │ ├── Migrations.sol │ ├── SimpleStorage.sol │ └── TutorialToken.sol ├── migrations │ ├── 1_initial_migration.js │ └── 2_deploy_contracts.js ├── package-lock.json ├── package.json ├── test │ ├── TestSimpleStorage.sol │ └── simplestorage.js └── truffle-config.js ├── webpack.config.js └── webpack.prod.js /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ["prettier", "eslint:recommended", "plugin:react/recommended"], 3 | plugins: ["prettier"], 4 | parser: "babel-eslint", 5 | rules: { 6 | "prettier/prettier": [1, { trailingComma: "all" }], 7 | }, 8 | env: { 9 | es6: true, 10 | browser: true, 11 | node: true, 12 | }, 13 | }; -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: > 18 | This issue has been closed, but can be re-opened if further comments 19 | indicate that the problem persists. Feel free to tag maintainers if there 20 | is no reply to further comments. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules 3 | .vscode -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | `drizzle-react-components` follows the same contribution guide as `drizzle`. Check it out [here](https://github.com/trufflesuite/drizzle/blob/develop/CONTRIBUTING.md). 4 | 5 | This guide will cover the `drizzle-react-components` specific content. 6 | 7 | ## Development 8 | 9 | ### Development Requirements 10 | 11 | In order to develop Drizzle React Components (DRC), you'll need: 12 | 13 | - [Git](https://git-scm.com/) 14 | - [Node.js](https://nodejs.org) 15 | 16 | ### Getting Started 17 | 18 | First clone this repository and install NPM dependencies: 19 | 20 | $ git clone git@github.com:trufflesuite/drizzle-react-components.git 21 | $ cd drizzle-react-components 22 | $ npm install 23 | 24 | If all is good, then run the build command: 25 | 26 | $ npm run build 27 | 28 | Your local DRC copy is contained in the `dist/` directory. 29 | 30 | To use this in a project, use `npm link`: 31 | 32 | $ cd dist 33 | $ npm link // may require sudo 34 | $ cd my-project-root 35 | $ npm link drizzle-react-components 36 | 37 | You're ready to use your local development version of DRC in your project. 38 | 39 | ## Tips for Getting your PR Merged 40 | 41 | These tips will make it easier to review and eventually merge your PRs. 42 | 43 | 1. When submitting a PR, make sure to reference the issue number so we can better trace what issue the PR is solving. 44 | 45 | 1. Keep your PRs small and atomic. Only resolve the issue you are targetting. Don't mix refactors with features/bugfixes, it bloats the diff and makes it hard to see what code is related to the actual feature/bugfix. 46 | 47 | 1. If it's a new feature, add an example implementation to the `test-app` and `test-app-legacy-context` and update `README.md`. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **DEPRECATION NOTICE** This repository has been deprecated in favor of: https://github.com/trufflesuite/drizzle 2 | 3 | # drizzle-react-components 4 | 5 | A set of useful components for common UI elements. 6 | 7 | ## Components 8 | 9 | We provide components that support the React 16.3+ context API and also the legacy context API. The legacy context components will be deprecated in 2.0 with breaking changes to the `drizzle-react-components` API. We recommend usage of the new context components where possible. 10 | 11 | For 1.x.x this is how you import the different components: 12 | 13 | ### React 16.3+ Context Components 14 | 15 | ``` 16 | import { newContextComponents } from "drizzle-react-components"; 17 | const { AccountData, ContractData, ContractForm } = newContextComponents; 18 | ``` 19 | 20 | `LoadingContainer` is not provided with the new context components currently. Also note that you must pass in `drizzle` and `drizzleState` for each of these components. 21 | 22 | ### Legacy Context Components 23 | 24 | ``` 25 | import { 26 | AccountData, 27 | ContractData, 28 | ContractForm, 29 | LoadingContainer 30 | } from "drizzle-react-components"; 31 | ``` 32 | 33 | Refer to the included [test apps](#test-apps) for usage examples. 34 | 35 | ### LoadingContainer (Legacy only) 36 | 37 | This component wraps your entire app (but within the DrizzleProvider) and will show a loading screen until Drizzle, and therefore web3 and your contracts, are initialized. 38 | 39 | `loadingComp` (component) The component displayed while Drizzle initializes. 40 | 41 | `errorComp` (component) The component displayed if Drizzle initialization fails. 42 | 43 | ### AccountData 44 | 45 | `accountIndex` (number, required) Index of account from which to retrieve balance. 46 | 47 | `units` (string) Unit to display either value in. Default is `wei`. See full list of units [here in the web3 documentation](https://web3js.readthedocs.io/en/1.0/web3-utils.html#fromwei). 48 | 49 | `precision` (number) The number of digits after the decimal point to display. 50 | 51 | ### ContractData 52 | 53 | `contract` (string, required) Name of the contract to call. 54 | 55 | `method` (string, required) Method of the contract to call. 56 | 57 | `methodArgs` (array) Arguments for the contract method call. EX: The address for an ERC20 balanceOf() function. The last argument can optionally be an options object with the typical form, `gas` and `gasPrice` keys. 58 | 59 | `hideIndicator` (boolean) If true, hides the loading indicator during contract state updates. Useful for things like ERC20 token symbols which do not change. 60 | 61 | `toUtf8` (boolean) Converts the return value to a UTF-8 string before display. 62 | 63 | `toAscii` (boolean) Converts the return value to an Ascii string before display. 64 | 65 | `render` (function with one argument) Render property, takes the value in the argument and returns render output. 66 | 67 | ### ContractForm 68 | 69 | `contract` (string, required) Name of the contract whose method will be the basis the form. 70 | 71 | `method` (string, required) Method whose inputs will be used to create corresponding form fields. 72 | 73 | `sendArgs` (object) An object specifying options for the transaction to be sent; namely: `from`, `gasPrice`, `gas` and `value`. Further explanataion of these parameters can be found [here in the web3 documentation](https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#id19). 74 | 75 | `labels` (array) Custom labels; will follow ABI input ordering. Useful for friendlier names. For example "\_to" becoming "Recipient Address". 76 | 77 | `render` (function) Render prop for rendering custom components. It receives a single object with the fields: `inputs`, `inputTypes`, `state`, `handleInputChange`, `handleSubmit`, as arguments and returns render output. 78 | 79 | ## Test Apps 80 | 81 | Refer to the test apps to learn more about how to use DRC. 82 | 83 | A test app targeting the React 16.3+ context API has been included at `./test-app`. And one targeting the legacy context API can be found at `test-app-legacy-context`. 84 | 85 | ### Installation 86 | 87 | 1. `cd ./test-app` 88 | 1. Install dependencies: `npm install` 89 | 1. Start your development blockchain: `truffle develop` 90 | 1. (In Truffle develop console) Compile contracts: `compile` 91 | 1. (In Truffle develop console) Migrate contracts: `migrate` 92 | 1. In another terminal window: `cd ./app` 93 | 1. Install dependencies: `npm install` 94 | 1. Start dev server: `npm start` 95 | 96 | NOTE: Make sure to `migrate --reset` your contracts and reset your Metamask account when switching between test apps, otherwise errors may occur. 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drizzle-react-components", 3 | "version": "1.4.0", 4 | "description": "Put some Drizzle on your React components.", 5 | "main": "dist/drizzle-react-components.js", 6 | "scripts": { 7 | "build": "webpack --config webpack.config.js", 8 | "publish": "webpack --config webpack.prod.js", 9 | "lint": "eslint src" 10 | }, 11 | "keywords": [ 12 | "ethereum", 13 | "react" 14 | ], 15 | "author": { 16 | "name": "Josh Quintal", 17 | "email": "josh@trufflesuite.com", 18 | "url": "http://truffleframework.com/" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/trufflesuite/drizzle-react-components" 23 | }, 24 | "license": "ISC", 25 | "dependencies": { 26 | "prop-types": "^15.7.2", 27 | "react": "^15.4.2" 28 | }, 29 | "devDependencies": { 30 | "babel-core": "^6.26.3", 31 | "babel-eslint": "^10.0.1", 32 | "babel-loader": "^7.1.5", 33 | "babel-plugin-transform-class-properties": "^6.24.1", 34 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 35 | "babel-preset-react": "^6.24.1", 36 | "drizzle": "^1.4.0", 37 | "drizzle-react": "^1.3.0", 38 | "eslint": "^5.16.0", 39 | "eslint-config-prettier": "^4.3.0", 40 | "eslint-config-react-app": "^3.0.8", 41 | "eslint-plugin-flowtype": "^3.9.1", 42 | "eslint-plugin-import": "^2.17.3", 43 | "eslint-plugin-jsx-a11y": "^6.2.1", 44 | "eslint-plugin-prettier": "^3.1.0", 45 | "eslint-plugin-react": "^7.13.0", 46 | "husky": "^1.3.1", 47 | "lint-staged": "^8.2.0", 48 | "prettier": "^1.18.0", 49 | "react-redux": "^5.1.1", 50 | "uglifyjs-webpack-plugin": "^1.3.0", 51 | "webpack": "^3.12.0" 52 | }, 53 | "lint-staged": { 54 | "*.js": [ 55 | "eslint --fix", 56 | "git add" 57 | ] 58 | }, 59 | "husky": { 60 | "hooks": { 61 | "pre-commit": "lint-staged" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/AccountData.js: -------------------------------------------------------------------------------- 1 | import { drizzleConnect } from "drizzle-react"; 2 | import React, { Component } from "react"; 3 | import PropTypes from "prop-types"; 4 | 5 | class AccountData extends Component { 6 | constructor(props) { 7 | super(props); 8 | 9 | this.precisionRound = this.precisionRound.bind(this); 10 | } 11 | 12 | precisionRound(number, precision) { 13 | var factor = Math.pow(10, precision); 14 | return Math.round(number * factor) / factor; 15 | } 16 | 17 | render() { 18 | // No accounts found. 19 | if (Object.keys(this.props.accounts).length === 0) { 20 | return Initializing...; 21 | } 22 | 23 | // Get account address and balance. 24 | const address = this.props.accounts[this.props.accountIndex]; 25 | var balance = this.props.accountBalances[address]; 26 | const units = this.props.units 27 | ? this.props.units.charAt(0).toUpperCase() + this.props.units.slice(1) 28 | : "Wei"; 29 | 30 | // Convert to given units. 31 | if (this.props.units && typeof balance !== "undefined") { 32 | balance = this.context.drizzle.web3.utils.fromWei( 33 | balance, 34 | this.props.units, 35 | ); 36 | } 37 | 38 | // Adjust to given precision. 39 | if (this.props.precision) { 40 | balance = this.precisionRound(balance, this.props.precision); 41 | } 42 | 43 | if (this.props.render) { 44 | return this.props.render({ 45 | address, 46 | balance, 47 | units, 48 | }); 49 | } 50 | 51 | return ( 52 |
53 |

{address}

54 |

55 | {balance} {units} 56 |

57 |
58 | ); 59 | } 60 | } 61 | 62 | AccountData.contextTypes = { 63 | drizzle: PropTypes.object, 64 | }; 65 | 66 | AccountData.propTypes = { 67 | accounts: PropTypes.arrayOf(PropTypes.string), 68 | accountBalances: PropTypes.arrayOf(PropTypes.string), 69 | accountIndex: PropTypes.number.isRequired, 70 | units: PropTypes.string, 71 | precision: PropTypes.number, 72 | render: PropTypes.func, 73 | }; 74 | 75 | /* 76 | * Export connected component. 77 | */ 78 | 79 | const mapStateToProps = state => { 80 | return { 81 | accounts: state.accounts, 82 | accountBalances: state.accountBalances, 83 | }; 84 | }; 85 | 86 | export default drizzleConnect(AccountData, mapStateToProps); 87 | -------------------------------------------------------------------------------- /src/ContractData.js: -------------------------------------------------------------------------------- 1 | import { drizzleConnect } from "drizzle-react"; 2 | import React, { Component } from "react"; 3 | import PropTypes from "prop-types"; 4 | 5 | class ContractData extends Component { 6 | constructor(props, context) { 7 | super(props); 8 | 9 | // Fetch initial value from chain and return cache key for reactive updates. 10 | var methodArgs = this.props.methodArgs ? this.props.methodArgs : []; 11 | 12 | this.contracts = context.drizzle.contracts; 13 | this.state = { 14 | dataKey: this.contracts[this.props.contract].methods[ 15 | this.props.method 16 | ].cacheCall(...methodArgs), 17 | }; 18 | } 19 | 20 | // Will not fix legacy component 21 | // eslint-disable-next-line react/no-deprecated 22 | componentWillReceiveProps(nextProps) { 23 | const { methodArgs, contract, method } = this.props; 24 | 25 | const didContractChange = contract !== nextProps.contract; 26 | const didMethodChange = method !== nextProps.method; 27 | const didArgsChange = 28 | JSON.stringify(methodArgs) !== JSON.stringify(nextProps.methodArgs); 29 | 30 | if (didContractChange || didMethodChange || didArgsChange) { 31 | this.setState({ 32 | dataKey: this.contracts[nextProps.contract].methods[ 33 | nextProps.method 34 | ].cacheCall(...nextProps.methodArgs), 35 | }); 36 | } 37 | } 38 | 39 | render() { 40 | // Contract is not yet intialized. 41 | if (!this.props.contracts[this.props.contract].initialized) { 42 | return Initializing...; 43 | } 44 | 45 | // If the cache key we received earlier isn't in the store yet; the initial value is still being fetched. 46 | if ( 47 | !( 48 | this.state.dataKey in 49 | this.props.contracts[this.props.contract][this.props.method] 50 | ) 51 | ) { 52 | return Fetching...; 53 | } 54 | 55 | // Show a loading spinner for future updates. 56 | var pendingSpinner = this.props.contracts[this.props.contract].synced 57 | ? "" 58 | : " 🔄"; 59 | 60 | // Optionally hide loading spinner (EX: ERC20 token symbol). 61 | if (this.props.hideIndicator) { 62 | pendingSpinner = ""; 63 | } 64 | 65 | var displayData = this.props.contracts[this.props.contract][ 66 | this.props.method 67 | ][this.state.dataKey].value; 68 | 69 | // Optionally convert to UTF8 70 | if (this.props.toUtf8) { 71 | displayData = this.context.drizzle.web3.utils.hexToUtf8(displayData); 72 | } 73 | 74 | // Optionally convert to Ascii 75 | if (this.props.toAscii) { 76 | displayData = this.context.drizzle.web3.utils.hexToAscii(displayData); 77 | } 78 | 79 | // If a render prop is given, have displayData rendered from that component 80 | if (this.props.render) { 81 | return this.props.render(displayData); 82 | } 83 | 84 | // If return value is an array 85 | if (Array.isArray(displayData)) { 86 | const displayListItems = displayData.map((datum, index) => { 87 | return ( 88 |
  • 89 | {`${datum}`} 90 | {pendingSpinner} 91 |
  • 92 | ); 93 | }); 94 | 95 | return ; 96 | } 97 | 98 | // If retun value is an object 99 | if (typeof displayData === "object") { 100 | var i = 0; 101 | const displayObjectProps = []; 102 | 103 | Object.keys(displayData).forEach(key => { 104 | if (i != key) { 105 | displayObjectProps.push( 106 |
  • 107 | {key} 108 | {pendingSpinner} 109 |
    110 | {`${displayData[key]}`} 111 |
  • , 112 | ); 113 | } 114 | 115 | i++; 116 | }); 117 | 118 | return ; 119 | } 120 | 121 | return ( 122 | 123 | {`${displayData}`} 124 | {pendingSpinner} 125 | 126 | ); 127 | } 128 | } 129 | 130 | ContractData.contextTypes = { 131 | drizzle: PropTypes.object, 132 | }; 133 | 134 | ContractData.propTypes = { 135 | contracts: PropTypes.object.isRequired, 136 | contract: PropTypes.string.isRequired, 137 | method: PropTypes.string.isRequired, 138 | methodArgs: PropTypes.array, 139 | hideIndicator: PropTypes.bool, 140 | toUtf8: PropTypes.bool, 141 | toAscii: PropTypes.bool, 142 | render: PropTypes.func, 143 | }; 144 | 145 | /* 146 | * Export connected component. 147 | */ 148 | 149 | const mapStateToProps = state => { 150 | return { 151 | contracts: state.contracts, 152 | }; 153 | }; 154 | 155 | export default drizzleConnect(ContractData, mapStateToProps); 156 | -------------------------------------------------------------------------------- /src/ContractForm.js: -------------------------------------------------------------------------------- 1 | import { drizzleConnect } from "drizzle-react"; 2 | import React, { Component } from "react"; 3 | import PropTypes from "prop-types"; 4 | 5 | const translateType = type => { 6 | switch (true) { 7 | case /^uint/.test(type): 8 | return "number"; 9 | case /^string/.test(type) || /^bytes/.test(type): 10 | return "text"; 11 | case /^bool/.test(type): 12 | return "checkbox"; 13 | default: 14 | return "text"; 15 | } 16 | }; 17 | 18 | class ContractForm extends Component { 19 | constructor(props, context) { 20 | super(props); 21 | 22 | this.handleInputChange = this.handleInputChange.bind(this); 23 | this.handleSubmit = this.handleSubmit.bind(this); 24 | 25 | this.contracts = context.drizzle.contracts; 26 | this.utils = context.drizzle.web3.utils; 27 | 28 | // Get the contract ABI 29 | const abi = this.contracts[this.props.contract].abi; 30 | 31 | this.inputs = []; 32 | var initialState = {}; 33 | 34 | // Iterate over abi for correct function. 35 | for (var i = 0; i < abi.length; i++) { 36 | if (abi[i].name === this.props.method) { 37 | this.inputs = abi[i].inputs; 38 | 39 | for (var j = 0; j < this.inputs.length; j++) { 40 | initialState[this.inputs[j].name] = ""; 41 | } 42 | 43 | break; 44 | } 45 | } 46 | 47 | this.state = initialState; 48 | } 49 | 50 | handleSubmit(event) { 51 | event.preventDefault(); 52 | 53 | const convertedInputs = this.inputs.map(input => { 54 | if (input.type === "bytes32") { 55 | return this.utils.toHex(this.state[input.name]); 56 | } 57 | return this.state[input.name]; 58 | }); 59 | 60 | if (this.props.sendArgs) { 61 | return this.contracts[this.props.contract].methods[ 62 | this.props.method 63 | ].cacheSend(...convertedInputs, this.props.sendArgs); 64 | } 65 | 66 | return this.contracts[this.props.contract].methods[ 67 | this.props.method 68 | ].cacheSend(...convertedInputs); 69 | } 70 | 71 | handleInputChange(event) { 72 | const value = 73 | event.target.type === 'checkbox' 74 | ? event.target.checked 75 | : event.target.value; 76 | this.setState({ [event.target.name]: value }); 77 | } 78 | 79 | render() { 80 | if (this.props.render) { 81 | return this.props.render({ 82 | inputs: this.inputs, 83 | inputTypes: this.inputs.map(input => translateType(input.type)), 84 | state: this.state, 85 | handleInputChange: this.handleInputChange, 86 | handleSubmit: this.handleSubmit, 87 | }); 88 | } 89 | 90 | return ( 91 |
    95 | {this.inputs.map((input, index) => { 96 | var inputType = translateType(input.type); 97 | var inputLabel = this.props.labels 98 | ? this.props.labels[index] 99 | : input.name; 100 | // check if input type is struct and if so loop out struct fields as well 101 | return ( 102 | 110 | ); 111 | })} 112 | 120 |
    121 | ); 122 | } 123 | } 124 | 125 | ContractForm.contextTypes = { 126 | drizzle: PropTypes.object, 127 | }; 128 | 129 | ContractForm.propTypes = { 130 | contract: PropTypes.string.isRequired, 131 | method: PropTypes.string.isRequired, 132 | sendArgs: PropTypes.object, 133 | labels: PropTypes.arrayOf(PropTypes.string), 134 | render: PropTypes.func, 135 | }; 136 | 137 | /* 138 | * Export connected component. 139 | */ 140 | 141 | const mapStateToProps = state => { 142 | return { 143 | contracts: state.contracts, 144 | }; 145 | }; 146 | 147 | export default drizzleConnect(ContractForm, mapStateToProps); 148 | -------------------------------------------------------------------------------- /src/LoadingContainer.js: -------------------------------------------------------------------------------- 1 | import { drizzleConnect } from "drizzle-react"; 2 | import React, { Children, Component } from "react"; 3 | import PropTypes from "prop-types"; 4 | 5 | /* 6 | * Create component. 7 | */ 8 | 9 | class LoadingContainer extends Component { 10 | render() { 11 | if (this.props.web3.status === "failed") { 12 | if (this.props.errorComp) { 13 | return this.props.errorComp; 14 | } 15 | 16 | return ( 17 |
    18 |
    19 |
    20 |

    ⚠️

    21 |

    22 | This browser has no connection to the Ethereum network. Please 23 | use the Chrome/FireFox extension MetaMask, or dedicated Ethereum 24 | browsers Mist or Parity. 25 |

    26 |
    27 |
    28 |
    29 | ); 30 | } 31 | 32 | if ( 33 | this.props.web3.status === "initialized" && 34 | Object.keys(this.props.accounts).length === 0 35 | ) { 36 | return ( 37 |
    38 |
    39 |
    40 |

    🦊

    41 |

    42 | {"We can't find any Ethereum accounts!"} Please 43 | check and make sure Metamask or your browser are pointed at the 44 | correct network and your account is unlocked. 45 |

    46 |
    47 |
    48 |
    49 | ); 50 | } 51 | 52 | if (this.props.drizzleStatus.initialized) { 53 | return Children.only(this.props.children); 54 | } 55 | 56 | if (this.props.loadingComp) { 57 | return this.props.loadingComp; 58 | } 59 | 60 | return ( 61 |
    62 |
    63 |
    64 |

    ⚙️

    65 |

    Loading dapp...

    66 |
    67 |
    68 |
    69 | ); 70 | } 71 | } 72 | 73 | LoadingContainer.contextTypes = { 74 | drizzle: PropTypes.object, 75 | }; 76 | 77 | LoadingContainer.propTypes = { 78 | children: PropTypes.node, 79 | accounts: PropTypes.object.isRequired, 80 | drizzleStatus: PropTypes.object.isRequired, 81 | web3: PropTypes.object.isRequired, 82 | loadingComp: PropTypes.node, 83 | errorComp: PropTypes.node, 84 | }; 85 | 86 | /* 87 | * Export connected component. 88 | */ 89 | 90 | const mapStateToProps = state => { 91 | return { 92 | accounts: state.accounts, 93 | drizzleStatus: state.drizzleStatus, 94 | web3: state.web3, 95 | }; 96 | }; 97 | 98 | export default drizzleConnect(LoadingContainer, mapStateToProps); 99 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import AccountData from "./AccountData.js"; 2 | import ContractData from "./ContractData.js"; 3 | import ContractForm from "./ContractForm.js"; 4 | import LoadingContainer from "./LoadingContainer.js"; 5 | import AccountDataNew from "./new-context-api/AccountData"; 6 | import ContractDataNew from "./new-context-api/ContractData"; 7 | import ContractFormNew from "./new-context-api/ContractForm"; 8 | 9 | const newContextComponents = { 10 | AccountData: AccountDataNew, 11 | ContractData: ContractDataNew, 12 | ContractForm: ContractFormNew, 13 | }; 14 | 15 | export { 16 | AccountData, 17 | ContractData, 18 | ContractForm, 19 | LoadingContainer, 20 | newContextComponents, 21 | }; 22 | -------------------------------------------------------------------------------- /src/new-context-api/AccountData.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | class AccountData extends Component { 5 | constructor(props) { 6 | super(props); 7 | 8 | this.precisionRound = this.precisionRound.bind(this); 9 | } 10 | 11 | precisionRound(number, precision) { 12 | var factor = Math.pow(10, precision); 13 | return Math.round(number * factor) / factor; 14 | } 15 | 16 | render() { 17 | // No accounts found. 18 | if (Object.keys(this.props.drizzleState.accounts).length === 0) { 19 | return Initializing...; 20 | } 21 | 22 | // Get account address and balance. 23 | const address = this.props.drizzleState.accounts[this.props.accountIndex]; 24 | var balance = this.props.drizzleState.accountBalances[address]; 25 | const units = this.props.units 26 | ? this.props.units.charAt(0).toUpperCase() + this.props.units.slice(1) 27 | : "Wei"; 28 | 29 | // Convert to given units. 30 | if (this.props.units && typeof balance !== "undefined") { 31 | balance = this.props.drizzle.web3.utils.fromWei( 32 | balance, 33 | this.props.units, 34 | ); 35 | } 36 | 37 | // Adjust to given precision. 38 | if (this.props.precision) { 39 | balance = this.precisionRound(balance, this.props.precision); 40 | } 41 | 42 | if (this.props.render) { 43 | return this.props.render({ 44 | address, 45 | balance, 46 | units, 47 | }); 48 | } 49 | 50 | return ( 51 |
    52 |

    {address}

    53 |

    54 | {balance} {units} 55 |

    56 |
    57 | ); 58 | } 59 | } 60 | 61 | AccountData.propTypes = { 62 | drizzle: PropTypes.object.isRequired, 63 | drizzleState: PropTypes.object.isRequired, 64 | accountIndex: PropTypes.number.isRequired, 65 | units: PropTypes.string, 66 | precision: PropTypes.number, 67 | render: PropTypes.func, 68 | }; 69 | 70 | export default AccountData; 71 | -------------------------------------------------------------------------------- /src/new-context-api/ContractData.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | class ContractData extends Component { 5 | constructor(props) { 6 | super(props); 7 | 8 | // Fetch initial value from chain and return cache key for reactive updates. 9 | var methodArgs = this.props.methodArgs ? this.props.methodArgs : []; 10 | 11 | this.contracts = props.drizzle.contracts; 12 | this.state = { 13 | dataKey: this.contracts[this.props.contract].methods[ 14 | this.props.method 15 | ].cacheCall(...methodArgs), 16 | }; 17 | } 18 | 19 | // TODO refactor this 20 | UNSAFE_componentWillReceiveProps(nextProps) { 21 | const { methodArgs, contract, method } = this.props; 22 | 23 | const didContractChange = contract !== nextProps.contract; 24 | const didMethodChange = method !== nextProps.method; 25 | const didArgsChange = 26 | JSON.stringify(methodArgs) !== JSON.stringify(nextProps.methodArgs); 27 | 28 | if (didContractChange || didMethodChange || didArgsChange) { 29 | this.setState({ 30 | dataKey: this.contracts[nextProps.contract].methods[ 31 | nextProps.method 32 | ].cacheCall(...nextProps.methodArgs), 33 | }); 34 | } 35 | } 36 | 37 | render() { 38 | const { drizzle, drizzleState } = this.props; 39 | 40 | // Contract is not yet intialized. 41 | if (!drizzleState.contracts[this.props.contract].initialized) { 42 | return Initializing...; 43 | } 44 | 45 | // If the cache key we received earlier isn't in the store yet; the initial value is still being fetched. 46 | if ( 47 | !( 48 | this.state.dataKey in 49 | drizzleState.contracts[this.props.contract][this.props.method] 50 | ) 51 | ) { 52 | return Fetching...; 53 | } 54 | 55 | // Show a loading spinner for future updates. 56 | var pendingSpinner = drizzleState.contracts[this.props.contract].synced 57 | ? "" 58 | : " 🔄"; 59 | 60 | // Optionally hide loading spinner (EX: ERC20 token symbol). 61 | if (this.props.hideIndicator) { 62 | pendingSpinner = ""; 63 | } 64 | 65 | var displayData = 66 | drizzleState.contracts[this.props.contract][this.props.method][ 67 | this.state.dataKey 68 | ].value; 69 | 70 | // Optionally convert to UTF8 71 | if (this.props.toUtf8) { 72 | displayData = drizzle.web3.utils.hexToUtf8(displayData); 73 | } 74 | 75 | // Optionally convert to Ascii 76 | if (this.props.toAscii) { 77 | displayData = drizzle.web3.utils.hexToAscii(displayData); 78 | } 79 | 80 | // If a render prop is given, have displayData rendered from that component 81 | if (this.props.render) { 82 | return this.props.render(displayData); 83 | } 84 | 85 | // If return value is an array 86 | if (Array.isArray(displayData)) { 87 | const displayListItems = displayData.map((datum, index) => { 88 | return ( 89 |
  • 90 | {`${datum}`} 91 | {pendingSpinner} 92 |
  • 93 | ); 94 | }); 95 | 96 | return ; 97 | } 98 | 99 | // If retun value is an object 100 | if (typeof displayData === "object") { 101 | var i = 0; 102 | const displayObjectProps = []; 103 | 104 | Object.keys(displayData).forEach(key => { 105 | if (i != key) { 106 | displayObjectProps.push( 107 |
  • 108 | {key} 109 | {pendingSpinner} 110 |
    111 | {`${displayData[key]}`} 112 |
  • , 113 | ); 114 | } 115 | 116 | i++; 117 | }); 118 | 119 | return ; 120 | } 121 | 122 | return ( 123 | 124 | {`${displayData}`} 125 | {pendingSpinner} 126 | 127 | ); 128 | } 129 | } 130 | 131 | ContractData.propTypes = { 132 | drizzle: PropTypes.object.isRequired, 133 | drizzleState: PropTypes.object.isRequired, 134 | contract: PropTypes.string.isRequired, 135 | method: PropTypes.string.isRequired, 136 | methodArgs: PropTypes.array, 137 | hideIndicator: PropTypes.bool, 138 | toUtf8: PropTypes.bool, 139 | toAscii: PropTypes.bool, 140 | render: PropTypes.func, 141 | }; 142 | 143 | export default ContractData; 144 | -------------------------------------------------------------------------------- /src/new-context-api/ContractForm.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import PropTypes from "prop-types"; 3 | 4 | const translateType = type => { 5 | switch (true) { 6 | case /^uint/.test(type): 7 | return "number"; 8 | case /^string/.test(type) || /^bytes/.test(type): 9 | return "text"; 10 | case /^bool/.test(type): 11 | return "checkbox"; 12 | default: 13 | return "text"; 14 | } 15 | }; 16 | 17 | class ContractForm extends Component { 18 | constructor(props) { 19 | super(props); 20 | 21 | this.handleInputChange = this.handleInputChange.bind(this); 22 | this.handleSubmit = this.handleSubmit.bind(this); 23 | 24 | this.contracts = props.drizzle.contracts; 25 | this.utils = props.drizzle.web3.utils; 26 | 27 | // Get the contract ABI 28 | const abi = this.contracts[this.props.contract].abi; 29 | 30 | this.inputs = []; 31 | var initialState = {}; 32 | 33 | // Iterate over abi for correct function. 34 | for (var i = 0; i < abi.length; i++) { 35 | if (abi[i].name === this.props.method) { 36 | this.inputs = abi[i].inputs; 37 | 38 | for (var j = 0; j < this.inputs.length; j++) { 39 | initialState[this.inputs[j].name] = ""; 40 | } 41 | 42 | break; 43 | } 44 | } 45 | 46 | this.state = initialState; 47 | } 48 | 49 | handleSubmit(event) { 50 | event.preventDefault(); 51 | 52 | const convertedInputs = this.inputs.map(input => { 53 | if (input.type === "bytes32") { 54 | return this.utils.toHex(this.state[input.name]); 55 | } 56 | return this.state[input.name]; 57 | }); 58 | 59 | if (this.props.sendArgs) { 60 | return this.contracts[this.props.contract].methods[ 61 | this.props.method 62 | ].cacheSend(...convertedInputs, this.props.sendArgs); 63 | } 64 | 65 | return this.contracts[this.props.contract].methods[ 66 | this.props.method 67 | ].cacheSend(...convertedInputs); 68 | } 69 | 70 | handleInputChange(event) { 71 | const value = 72 | event.target.type === "checkbox" 73 | ? event.target.checked 74 | : event.target.value; 75 | this.setState({ [event.target.name]: value }); 76 | } 77 | 78 | render() { 79 | if (this.props.render) { 80 | return this.props.render({ 81 | inputs: this.inputs, 82 | inputTypes: this.inputs.map(input => translateType(input.type)), 83 | state: this.state, 84 | handleInputChange: this.handleInputChange, 85 | handleSubmit: this.handleSubmit, 86 | }); 87 | } 88 | 89 | return ( 90 |
    94 | {this.inputs.map((input, index) => { 95 | var inputType = translateType(input.type); 96 | var inputLabel = this.props.labels 97 | ? this.props.labels[index] 98 | : input.name; 99 | // check if input type is struct and if so loop out struct fields as well 100 | return ( 101 | 109 | ); 110 | })} 111 | 119 |
    120 | ); 121 | } 122 | } 123 | 124 | ContractForm.propTypes = { 125 | drizzle: PropTypes.object.isRequired, 126 | contract: PropTypes.string.isRequired, 127 | method: PropTypes.string.isRequired, 128 | sendArgs: PropTypes.object, 129 | labels: PropTypes.arrayOf(PropTypes.string), 130 | render: PropTypes.func, 131 | }; 132 | 133 | export default ContractForm; 134 | -------------------------------------------------------------------------------- /test-app-legacy-context/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | app/src/contracts 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/.env: -------------------------------------------------------------------------------- 1 | # Stop create-react-app from complaining about wrong package versions installed higher up in tree that belong to DRC 2 | # e.g. babel-loader, webpack 3 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /test-app-legacy-context/app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
    10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
    13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
    18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
    23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
    26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "drizzle": "^1.4.0", 7 | "drizzle-react": "^1.3.0", 8 | "drizzle-react-components": "1.4.0", 9 | "react": "^16.8.6", 10 | "react-dom": "^16.8.6", 11 | "react-scripts": "2.1.3" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test", 17 | "eject": "react-scripts eject" 18 | }, 19 | "eslintConfig": { 20 | "extends": "react-app" 21 | }, 22 | "browserslist": [ 23 | ">0.2%", 24 | "not dead", 25 | "not ie <= 11", 26 | "not op_mini all" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trufflesuite/drizzle-react-components-legacy/b0023662ea426ee9b021478634866a137c7a78c8/test-app-legacy-context/app/public/favicon.ico -------------------------------------------------------------------------------- /test-app-legacy-context/app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
    30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | margin: 2rem; 4 | } 5 | 6 | .section { 7 | text-align: left; 8 | max-width: 720px; 9 | margin: 4rem auto auto; 10 | } 11 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { DrizzleProvider } from "drizzle-react"; 3 | import { LoadingContainer } from "drizzle-react-components"; 4 | 5 | import "./App.css"; 6 | 7 | import drizzleOptions from "./drizzleOptions"; 8 | import MyContainer from "./MyContainer"; 9 | 10 | class App extends Component { 11 | render() { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | ); 19 | } 20 | } 21 | 22 | export default App; 23 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/MyComponent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | AccountData, 4 | ContractData, 5 | ContractForm 6 | } from "drizzle-react-components"; 7 | 8 | import logo from "./logo.png"; 9 | 10 | const myRender = data => ( 11 | <> 12 | Value={data} 13 | 14 | ); 15 | 16 | export default ({ accounts }) => ( 17 |
    18 |
    19 | drizzle-logo 20 |

    Drizzle Examples

    21 |

    Examples of how to get started with Drizzle in various situations.

    22 |
    23 | 24 |
    25 |

    Active Account

    26 | 27 | 28 |

    Active Account with Custom Rendered Component

    29 | ( 34 |
    35 |
    My Address: {address}
    36 |
    My Ether: {balance} {units}
    37 |
    38 | )} 39 | /> 40 |
    41 | 42 |
    43 |

    SimpleStorage

    44 |

    45 | This shows a simple ContractData component with no arguments, along with 46 | a form to set its value. 47 |

    48 |

    49 | Stored Value: 50 | 51 |

    52 | 53 |

    54 | Stored Boolean Value: 55 | 56 |

    57 | 58 |
    59 | 60 |
    61 |

    SimpleStorage with Custom Rendering

    62 |

    63 | This is the same contract as above, but here we customize the 64 | ContractForm's rendered component's style. 65 |

    66 | ( 70 |
    71 | {inputs.map((input, index) => ( 72 | 81 | ))} 82 | 90 |
    91 | )} 92 | /> 93 |
    94 | 95 |
    96 |

    TutorialToken

    97 |

    98 | Here we have a form with custom, friendly labels. Also note the token 99 | symbol will not display a loading indicator. We've suppressed it with 100 | the hideIndicator prop because we know this variable is 101 | constant. 102 |

    103 |

    104 | Total Supply: 105 | {" "} 110 | 111 |

    112 |

    113 | My Balance: 114 | 119 |

    120 |

    Send Tokens

    121 | 126 |
    127 |
    128 |

    ComplexStorage

    129 |

    130 | This contract shows data types with additional considerations. Note in 131 | the code the strings below are converted from bytes to UTF-8 strings and 132 | the device data struct is iterated as a list. 133 |

    134 |

    135 | String 1: 136 | 137 |

    138 |

    139 | String 2: 140 | 141 |

    142 | Single Device Data: 143 | 144 | Array of UInts: 145 | {" "} 146 |
    147 |
    148 |

    ComplexStorage with Custom Rendering

    149 |

    150 | This is the same data as above, but enhanced with a custom render 151 | function. 152 |

    153 |

    154 | String 1: 155 | ( 160 | <> 161 | This is the value: {data} 162 | 163 | )} 164 | /> 165 |

    166 |

    167 | String 2: 168 | 174 |

    175 | Single Device Data: 176 | { 180 | var i = 0; 181 | const displayObjectProps = []; 182 | 183 | Object.keys(displayData).forEach(key => { 184 | if (i != key) { 185 | displayObjectProps.push( 186 |
  • 187 | Element {i} has key: {key} 188 |
    189 | and value: {`${displayData[key]}`} 190 |
  • 191 | ); 192 | } 193 | 194 | i++; 195 | }); 196 | return
      {displayObjectProps}
    ; 197 | }} 198 | /> 199 | Array of UInts: 200 | ( 204 |
      205 | {displayData.map(v => ( 206 |
    1. 207 | value: {v} 208 |
    2. 209 | ))} 210 |
    211 | )} 212 | /> 213 |
    214 |
    215 | ); 216 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/MyContainer.js: -------------------------------------------------------------------------------- 1 | import MyComponent from "./MyComponent"; 2 | import { drizzleConnect } from "drizzle-react"; 3 | 4 | const mapStateToProps = state => { 5 | return { 6 | accounts: state.accounts, 7 | SimpleStorage: state.contracts.SimpleStorage, 8 | TutorialToken: state.contracts.TutorialToken, 9 | drizzleStatus: state.drizzleStatus, 10 | }; 11 | }; 12 | 13 | const MyContainer = drizzleConnect(MyComponent, mapStateToProps); 14 | 15 | export default MyContainer; 16 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/drizzleOptions.js: -------------------------------------------------------------------------------- 1 | import SimpleStorage from "./contracts/SimpleStorage.json"; 2 | import ComplexStorage from "./contracts/ComplexStorage.json"; 3 | import TutorialToken from "./contracts/TutorialToken.json"; 4 | 5 | const options = { 6 | web3: { 7 | block: false, 8 | fallback: { 9 | type: "ws", 10 | url: "ws://127.0.0.1:9545", 11 | }, 12 | }, 13 | contracts: [SimpleStorage, ComplexStorage, TutorialToken], 14 | events: { 15 | SimpleStorage: ["StorageSet"], 16 | }, 17 | polls: { 18 | accounts: 1500, 19 | }, 20 | }; 21 | 22 | export default options; 23 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trufflesuite/drizzle-react-components-legacy/b0023662ea426ee9b021478634866a137c7a78c8/test-app-legacy-context/app/src/logo.png -------------------------------------------------------------------------------- /test-app-legacy-context/app/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /test-app-legacy-context/contracts/ComplexStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract ComplexStorage { 4 | uint public storeduint1 = 15; 5 | uint public constant constuint = 16; 6 | uint128 public investmentsLimit = 17055; 7 | uint32 public investmentsDeadlineTimeStamp = uint32(now); 8 | 9 | bytes16 public string1 = "test1"; 10 | bytes32 public string2 = "test1236"; 11 | string public string3 = "lets string something"; 12 | 13 | mapping (address => uint) uints1; 14 | mapping (address => DeviceData) structs1; 15 | 16 | uint[] public uintarray; 17 | DeviceData[] public deviceDataArray; 18 | DeviceData public singleDD; 19 | 20 | struct DeviceData { 21 | string deviceBrand; 22 | string deviceYear; 23 | string batteryWearLevel; 24 | } 25 | 26 | constructor() public { 27 | address address1 = 0xbCcc714d56bc0da0fd33d96d2a87b680dD6D0DF6; 28 | address address2 = 0xaee905FdD3ED851e48d22059575b9F4245A82B04; 29 | 30 | uints1[address1] = 88; 31 | uints1[address2] = 99; 32 | 33 | structs1[address1] = DeviceData("deviceBrand", "deviceYear", "wearLevel"); 34 | structs1[address2] = DeviceData("deviceBrand2", "deviceYear2", "wearLevel2"); 35 | singleDD = DeviceData("deviceBrand3", "deviceYear3", "wearLevel3"); 36 | 37 | uintarray.push(8000); 38 | uintarray.push(9000); 39 | 40 | deviceDataArray.push(structs1[address1]); 41 | deviceDataArray.push(structs1[address2]); 42 | } 43 | 44 | function getUintarray() public view returns (uint[] memory) { 45 | return uintarray; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test-app-legacy-context/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-app-legacy-context/contracts/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract SimpleStorage { 4 | event StorageSet(string _message); 5 | 6 | uint public storedData; 7 | bool public storedBool; 8 | 9 | function set(uint x) public { 10 | storedData = x; 11 | 12 | emit StorageSet("Data stored successfully!"); 13 | } 14 | 15 | function setBool(bool x) public { 16 | storedBool = x; 17 | 18 | emit StorageSet("Boolean stored successfully!"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test-app-legacy-context/contracts/TutorialToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 4 | 5 | contract TutorialToken is ERC20 { 6 | string public name = "TutorialToken"; 7 | string public symbol = "TT"; 8 | uint public decimals = 2; 9 | uint public INITIAL_SUPPLY = 12000; 10 | 11 | constructor() public { 12 | _mint(msg.sender, INITIAL_SUPPLY); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test-app-legacy-context/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /test-app-legacy-context/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const SimpleStorage = artifacts.require("SimpleStorage"); 2 | const TutorialToken = artifacts.require("TutorialToken"); 3 | const ComplexStorage = artifacts.require("ComplexStorage"); 4 | 5 | module.exports = function(deployer) { 6 | deployer.deploy(SimpleStorage); 7 | deployer.deploy(TutorialToken); 8 | deployer.deploy(ComplexStorage); 9 | }; 10 | -------------------------------------------------------------------------------- /test-app-legacy-context/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drizzle-box", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "openzeppelin-solidity": { 8 | "version": "2.3.0", 9 | "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-2.3.0.tgz", 10 | "integrity": "sha512-QYeiPLvB1oSbDt6lDQvvpx7k8ODczvE474hb2kLXZBPKMsxKT1WxTCHBYrCU7kS7hfAku4DcJ0jqOyL+jvjwQw==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test-app-legacy-context/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drizzle-box", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/truffle-box/drizzle-box.git" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/truffle-box/drizzle-box/issues" 21 | }, 22 | "homepage": "https://github.com/truffle-box/drizzle-box#readme", 23 | "dependencies": { 24 | "openzeppelin-solidity": "^2.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test-app-legacy-context/test/TestSimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/SimpleStorage.sol"; 6 | 7 | contract TestSimpleStorage { 8 | function testItStoresAValue() public { 9 | SimpleStorage simpleStorage = SimpleStorage(DeployedAddresses.SimpleStorage()); 10 | 11 | simpleStorage.set(89); 12 | 13 | uint expected = 89; 14 | 15 | Assert.equal(simpleStorage.storedData(), expected, "It should store the value 89."); 16 | } 17 | } -------------------------------------------------------------------------------- /test-app-legacy-context/test/simplestorage.js: -------------------------------------------------------------------------------- 1 | const SimpleStorage = artifacts.require("SimpleStorage"); 2 | 3 | contract("SimpleStorage", accounts => { 4 | it("...should store the value 89.", async () => { 5 | const simpleStorageInstance = await SimpleStorage.deployed(); 6 | 7 | // Set value of 89 8 | await simpleStorageInstance.set(89, { from: accounts[0] }); 9 | 10 | // Get stored value 11 | const storedData = await simpleStorageInstance.storedData.call(); 12 | 13 | assert.equal(storedData, 89, "The value 89 was not stored."); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test-app-legacy-context/truffle-config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | // See 5 | // to customize your Truffle configuration! 6 | contracts_build_directory: path.join(__dirname, "app/src/contracts"), 7 | }; 8 | -------------------------------------------------------------------------------- /test-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | app/src/contracts 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /test-app/app/.env: -------------------------------------------------------------------------------- 1 | # Stop create-react-app from complaining about wrong package versions installed higher up in tree that belong to DRC 2 | # e.g. babel-loader, webpack 3 | SKIP_PREFLIGHT_CHECK=true -------------------------------------------------------------------------------- /test-app/app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /test-app/app/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
    10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
    13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
    18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
    23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
    26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /test-app/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "drizzle": "^1.4.0", 7 | "drizzle-react": "^1.3.0", 8 | "drizzle-react-components": "^1.4.0", 9 | "react": "^16.8.6", 10 | "react-dom": "^16.8.6", 11 | "react-scripts": "2.1.3" 12 | }, 13 | "scripts": { 14 | "start": "react-scripts start", 15 | "build": "react-scripts build", 16 | "test": "react-scripts test", 17 | "eject": "react-scripts eject" 18 | }, 19 | "eslintConfig": { 20 | "extends": "react-app" 21 | }, 22 | "browserslist": [ 23 | ">0.2%", 24 | "not dead", 25 | "not ie <= 11", 26 | "not op_mini all" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /test-app/app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trufflesuite/drizzle-react-components-legacy/b0023662ea426ee9b021478634866a137c7a78c8/test-app/app/public/favicon.ico -------------------------------------------------------------------------------- /test-app/app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 |
    30 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /test-app/app/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /test-app/app/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | margin: 2rem; 4 | } 5 | 6 | .section { 7 | text-align: left; 8 | max-width: 720px; 9 | margin: 4rem auto auto; 10 | } 11 | -------------------------------------------------------------------------------- /test-app/app/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from "react"; 2 | import { Drizzle } from 'drizzle'; 3 | import { DrizzleContext } from "drizzle-react"; 4 | 5 | import "./App.css"; 6 | 7 | import drizzleOptions from "./drizzleOptions"; 8 | import MyComponent from "./MyComponent"; 9 | 10 | const drizzle = new Drizzle(drizzleOptions); 11 | 12 | class App extends Component { 13 | render() { 14 | return ( 15 | 16 | 17 | 18 | ); 19 | } 20 | } 21 | 22 | export default App; 23 | 24 | -------------------------------------------------------------------------------- /test-app/app/src/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | it('renders without crashing', () => { 6 | const div = document.createElement('div'); 7 | ReactDOM.render(, div); 8 | ReactDOM.unmountComponentAtNode(div); 9 | }); 10 | -------------------------------------------------------------------------------- /test-app/app/src/MyComponent.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { newContextComponents } from "drizzle-react-components"; 3 | import { DrizzleContext } from "drizzle-react"; 4 | import logo from "./logo.png"; 5 | 6 | const { AccountData, ContractData, ContractForm } = newContextComponents; 7 | 8 | const myRender = data => ( 9 | <> 10 | Value={data} 11 | 12 | ); 13 | 14 | export default () => ( 15 | 16 | {drizzleContext => { 17 | const { drizzle, drizzleState, initialized } = drizzleContext; 18 | if (!initialized) { 19 | return "Loading..."; 20 | } 21 | 22 | const { accounts } = drizzleState; 23 | return ( 24 |
    25 |
    26 | drizzle-logo 27 |

    Drizzle Examples

    28 |

    29 | Examples of how to get started with Drizzle in various situations. 30 |

    31 |
    32 | 33 |
    34 |

    Active Account

    35 | 42 | 43 |

    Active Account with Custom Rendered Component

    44 | ( 51 |
    52 |
    My Address: {address}
    53 |
    My Ether: {balance} {units}
    54 |
    55 | )} 56 | /> 57 |
    58 | 59 |
    60 |

    SimpleStorage

    61 |

    62 | This shows a simple ContractData component with no arguments, 63 | along with a form to set its value. 64 |

    65 |

    66 | Stored Value: 67 | 73 |

    74 | 80 |

    81 | Stored Boolean Value: 82 | 88 |

    89 | 95 | 96 |

    SimpleStorage with Custom Rendering

    97 |

    98 | This is the same contract as above, but here we customize the ContractForm's rendered component's style. 99 |

    100 | ( 106 |
    107 | {inputs.map((input, index) => ( 108 | 117 | ))} 118 | 126 |
    127 | 128 | )} 129 | /> 130 |
    131 | 132 |
    133 |

    TutorialToken

    134 |

    135 | Here we have a form with custom, friendly labels. Also note the 136 | token symbol will not display a loading indicator. We've 137 | suppressed it with the hideIndicator prop because we 138 | know this variable is constant. 139 |

    140 |

    141 | Total Supply: 142 | {" "} 149 | 156 |

    157 |

    158 | My Balance: 159 | 166 |

    167 |

    Send Tokens

    168 | 175 |
    176 | 177 |
    178 |

    ComplexStorage

    179 |

    180 | This contract shows data types with additional considerations. 181 | Note in the code the strings below are converted from bytes to 182 | UTF-8 strings and the device data struct is iterated as a list. 183 |

    184 |

    185 | String 1: 186 | 193 |

    194 |

    195 | String 2: 196 | 203 |

    204 | Single Device Data: 205 | 211 | Array of UInts: 212 | 218 |
    219 |
    220 |

    ComplexStorage with Custom Rendering

    221 |

    222 | This is the same data as above, but enhanced with a custom render 223 | function. 224 |

    225 |

    226 | String 1: 227 | ( 234 | <> 235 | This is the value: {data} 236 | 237 | )} 238 | /> 239 |

    240 |

    241 | String 2: 242 | 250 |

    251 | Single Device Data: 252 | { 258 | var i = 0; 259 | const displayObjectProps = []; 260 | 261 | Object.keys(displayData).forEach(key => { 262 | if (i != key) { 263 | displayObjectProps.push( 264 |
  • 265 | Element {i} has key: {key} 266 |
    267 | and value: {`${displayData[key]}`} 268 |
  • 269 | ); 270 | } 271 | 272 | i++; 273 | }); 274 | return
      {displayObjectProps}
    ; 275 | }} 276 | /> 277 | Array of UInts: 278 | ( 284 |
      285 | {displayData.map(v => ( 286 |
    1. 287 | value: {v} 288 |
    2. 289 | ))} 290 |
    291 | )} 292 | /> 293 |
    294 |
    295 | ); 296 | }} 297 |
    298 | ); 299 | -------------------------------------------------------------------------------- /test-app/app/src/drizzleOptions.js: -------------------------------------------------------------------------------- 1 | import SimpleStorage from "./contracts/SimpleStorage.json"; 2 | import ComplexStorage from "./contracts/ComplexStorage.json"; 3 | import TutorialToken from "./contracts/TutorialToken.json"; 4 | 5 | const options = { 6 | web3: { 7 | block: false, 8 | fallback: { 9 | type: "ws", 10 | url: "ws://127.0.0.1:9545", 11 | }, 12 | }, 13 | contracts: [SimpleStorage, ComplexStorage, TutorialToken], 14 | events: { 15 | SimpleStorage: ["StorageSet"], 16 | }, 17 | polls: { 18 | accounts: 1500, 19 | }, 20 | }; 21 | 22 | export default options; 23 | -------------------------------------------------------------------------------- /test-app/app/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 6 | sans-serif; 7 | -webkit-font-smoothing: antialiased; 8 | -moz-osx-font-smoothing: grayscale; 9 | } 10 | 11 | code { 12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 13 | monospace; 14 | } 15 | -------------------------------------------------------------------------------- /test-app/app/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import * as serviceWorker from './serviceWorker'; 6 | 7 | ReactDOM.render(, document.getElementById('root')); 8 | 9 | // If you want your app to work offline and load faster, you can change 10 | // unregister() to register() below. Note this comes with some pitfalls. 11 | // Learn more about service workers: http://bit.ly/CRA-PWA 12 | serviceWorker.unregister(); 13 | -------------------------------------------------------------------------------- /test-app/app/src/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trufflesuite/drizzle-react-components-legacy/b0023662ea426ee9b021478634866a137c7a78c8/test-app/app/src/logo.png -------------------------------------------------------------------------------- /test-app/app/src/serviceWorker.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read http://bit.ly/CRA-PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.1/8 is considered localhost for IPv4. 18 | window.location.hostname.match( 19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 20 | ) 21 | ); 22 | 23 | export function register(config) { 24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 25 | // The URL constructor is available in all browsers that support SW. 26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 27 | if (publicUrl.origin !== window.location.origin) { 28 | // Our service worker won't work if PUBLIC_URL is on a different origin 29 | // from what our page is served on. This might happen if a CDN is used to 30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 31 | return; 32 | } 33 | 34 | window.addEventListener('load', () => { 35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 36 | 37 | if (isLocalhost) { 38 | // This is running on localhost. Let's check if a service worker still exists or not. 39 | checkValidServiceWorker(swUrl, config); 40 | 41 | // Add some additional logging to localhost, pointing developers to the 42 | // service worker/PWA documentation. 43 | navigator.serviceWorker.ready.then(() => { 44 | console.log( 45 | 'This web app is being served cache-first by a service ' + 46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA' 47 | ); 48 | }); 49 | } else { 50 | // Is not localhost. Just register service worker 51 | registerValidSW(swUrl, config); 52 | } 53 | }); 54 | } 55 | } 56 | 57 | function registerValidSW(swUrl, config) { 58 | navigator.serviceWorker 59 | .register(swUrl) 60 | .then(registration => { 61 | registration.onupdatefound = () => { 62 | const installingWorker = registration.installing; 63 | if (installingWorker == null) { 64 | return; 65 | } 66 | installingWorker.onstatechange = () => { 67 | if (installingWorker.state === 'installed') { 68 | if (navigator.serviceWorker.controller) { 69 | // At this point, the updated precached content has been fetched, 70 | // but the previous service worker will still serve the older 71 | // content until all client tabs are closed. 72 | console.log( 73 | 'New content is available and will be used when all ' + 74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.' 75 | ); 76 | 77 | // Execute callback 78 | if (config && config.onUpdate) { 79 | config.onUpdate(registration); 80 | } 81 | } else { 82 | // At this point, everything has been precached. 83 | // It's the perfect time to display a 84 | // "Content is cached for offline use." message. 85 | console.log('Content is cached for offline use.'); 86 | 87 | // Execute callback 88 | if (config && config.onSuccess) { 89 | config.onSuccess(registration); 90 | } 91 | } 92 | } 93 | }; 94 | }; 95 | }) 96 | .catch(error => { 97 | console.error('Error during service worker registration:', error); 98 | }); 99 | } 100 | 101 | function checkValidServiceWorker(swUrl, config) { 102 | // Check if the service worker can be found. If it can't reload the page. 103 | fetch(swUrl) 104 | .then(response => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then(registration => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log( 124 | 'No internet connection found. App is running in offline mode.' 125 | ); 126 | }); 127 | } 128 | 129 | export function unregister() { 130 | if ('serviceWorker' in navigator) { 131 | navigator.serviceWorker.ready.then(registration => { 132 | registration.unregister(); 133 | }); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /test-app/contracts/ComplexStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract ComplexStorage { 4 | uint public storeduint1 = 15; 5 | uint public constant constuint = 16; 6 | uint128 public investmentsLimit = 17055; 7 | uint32 public investmentsDeadlineTimeStamp = uint32(now); 8 | 9 | bytes16 public string1 = "test1"; 10 | bytes32 public string2 = "test1236"; 11 | string public string3 = "lets string something"; 12 | 13 | mapping (address => uint) uints1; 14 | mapping (address => DeviceData) structs1; 15 | 16 | uint[] public uintarray; 17 | DeviceData[] public deviceDataArray; 18 | DeviceData public singleDD; 19 | 20 | struct DeviceData { 21 | string deviceBrand; 22 | string deviceYear; 23 | string batteryWearLevel; 24 | } 25 | 26 | constructor() public { 27 | address address1 = 0xbCcc714d56bc0da0fd33d96d2a87b680dD6D0DF6; 28 | address address2 = 0xaee905FdD3ED851e48d22059575b9F4245A82B04; 29 | 30 | uints1[address1] = 88; 31 | uints1[address2] = 99; 32 | 33 | structs1[address1] = DeviceData("deviceBrand", "deviceYear", "wearLevel"); 34 | structs1[address2] = DeviceData("deviceBrand2", "deviceYear2", "wearLevel2"); 35 | singleDD = DeviceData("deviceBrand3", "deviceYear3", "wearLevel3"); 36 | 37 | uintarray.push(8000); 38 | uintarray.push(9000); 39 | 40 | deviceDataArray.push(structs1[address1]); 41 | deviceDataArray.push(structs1[address2]); 42 | } 43 | 44 | function getUintarray() public view returns (uint[] memory) { 45 | return uintarray; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test-app/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test-app/contracts/SimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract SimpleStorage { 4 | event StorageSet(string _message); 5 | 6 | uint public storedData; 7 | bool public storedBool; 8 | 9 | function set(uint x) public { 10 | storedData = x; 11 | 12 | emit StorageSet("Data stored successfully!"); 13 | } 14 | 15 | function setBool(bool x) public { 16 | storedBool = x; 17 | 18 | emit StorageSet("Boolean stored successfully!"); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test-app/contracts/TutorialToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 4 | 5 | contract TutorialToken is ERC20 { 6 | string public name = "TutorialToken"; 7 | string public symbol = "TT"; 8 | uint public decimals = 2; 9 | uint public INITIAL_SUPPLY = 12000; 10 | 11 | constructor() public { 12 | _mint(msg.sender, INITIAL_SUPPLY); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test-app/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | var Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /test-app/migrations/2_deploy_contracts.js: -------------------------------------------------------------------------------- 1 | const SimpleStorage = artifacts.require("SimpleStorage"); 2 | const TutorialToken = artifacts.require("TutorialToken"); 3 | const ComplexStorage = artifacts.require("ComplexStorage"); 4 | 5 | module.exports = function(deployer) { 6 | deployer.deploy(SimpleStorage); 7 | deployer.deploy(TutorialToken); 8 | deployer.deploy(ComplexStorage); 9 | }; 10 | -------------------------------------------------------------------------------- /test-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drizzle-box", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "openzeppelin-solidity": { 8 | "version": "2.3.0", 9 | "resolved": "https://registry.npmjs.org/openzeppelin-solidity/-/openzeppelin-solidity-2.3.0.tgz", 10 | "integrity": "sha512-QYeiPLvB1oSbDt6lDQvvpx7k8ODczvE474hb2kLXZBPKMsxKT1WxTCHBYrCU7kS7hfAku4DcJ0jqOyL+jvjwQw==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drizzle-box", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "truffle test" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/truffle-box/drizzle-box.git" 15 | }, 16 | "keywords": [], 17 | "author": "", 18 | "license": "ISC", 19 | "bugs": { 20 | "url": "https://github.com/truffle-box/drizzle-box/issues" 21 | }, 22 | "homepage": "https://github.com/truffle-box/drizzle-box#readme", 23 | "dependencies": { 24 | "openzeppelin-solidity": "^2.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test-app/test/TestSimpleStorage.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "truffle/Assert.sol"; 4 | import "truffle/DeployedAddresses.sol"; 5 | import "../contracts/SimpleStorage.sol"; 6 | 7 | contract TestSimpleStorage { 8 | function testItStoresAValue() public { 9 | SimpleStorage simpleStorage = SimpleStorage(DeployedAddresses.SimpleStorage()); 10 | 11 | simpleStorage.set(89); 12 | 13 | uint expected = 89; 14 | 15 | Assert.equal(simpleStorage.storedData(), expected, "It should store the value 89."); 16 | } 17 | } -------------------------------------------------------------------------------- /test-app/test/simplestorage.js: -------------------------------------------------------------------------------- 1 | const SimpleStorage = artifacts.require("SimpleStorage"); 2 | 3 | contract("SimpleStorage", accounts => { 4 | it("...should store the value 89.", async () => { 5 | const simpleStorageInstance = await SimpleStorage.deployed(); 6 | 7 | // Set value of 89 8 | await simpleStorageInstance.set(89, { from: accounts[0] }); 9 | 10 | // Get stored value 11 | const storedData = await simpleStorageInstance.storedData.call(); 12 | 13 | assert.equal(storedData, 89, "The value 89 was not stored."); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /test-app/truffle-config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | // See 5 | // to customize your Truffle configuration! 6 | contracts_build_directory: path.join(__dirname, "app/src/contracts"), 7 | }; 8 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | process.env.BABEL_ENV = 'production'; 4 | 5 | module.exports = { 6 | entry: './src/index.js', 7 | output: { 8 | filename: 'drizzle-react-components.js', 9 | library: 'drizzle-react-components', 10 | libraryTarget: 'umd', 11 | path: path.resolve(__dirname, 'dist') 12 | }, 13 | module: { 14 | loaders: [{ 15 | test: /\.(js)$/, 16 | include: path.resolve(__dirname, 'src'), 17 | loader: 'babel-loader', 18 | options: { 19 | presets: ['react'], 20 | plugins: [require('babel-plugin-transform-class-properties'), require('babel-plugin-transform-object-rest-spread')] 21 | } 22 | }] 23 | }, 24 | externals: [ 25 | 'drizzle', 26 | 'drizzle-react', 27 | 'prop-types', 28 | 'react', 29 | 'redux' 30 | ] 31 | }; 32 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 3 | 4 | process.env.BABEL_ENV = 'production'; 5 | 6 | module.exports = { 7 | entry: './src/index.js', 8 | output: { 9 | filename: 'drizzle-react-components.js', 10 | library: 'drizzle-react-components', 11 | libraryTarget: 'umd', 12 | path: path.resolve(__dirname, 'dist') 13 | }, 14 | module: { 15 | loaders: [{ 16 | test: /\.(js)$/, 17 | include: path.resolve(__dirname, 'src'), 18 | loader: 'babel-loader', 19 | options: { 20 | presets: ['react'], 21 | plugins: [require('babel-plugin-transform-class-properties'), require('babel-plugin-transform-object-rest-spread')] 22 | } 23 | }] 24 | }, 25 | plugins: [ 26 | new UglifyJSPlugin({ 27 | sourceMap: true 28 | }) 29 | ], 30 | externals: [ 31 | 'drizzle', 32 | 'drizzle-react', 33 | 'prop-types', 34 | 'react', 35 | 'redux' 36 | ] 37 | }; 38 | --------------------------------------------------------------------------------