diff --git a/test-dapp/app/components/accountBalance.js b/test-dapp/app/components/accountBalance.js index 8541c2e..c572497 100644 --- a/test-dapp/app/components/accountBalance.js +++ b/test-dapp/app/components/accountBalance.js @@ -22,16 +22,6 @@ class AccountBalance extends React.Component { updateBalances(ev){ if(ev) ev.preventDefault(); - web3.eth.getBalance(this.props.address) - .then(eth => { - this.setState({eth}); - }); - - this.props.RND.methods.balanceOf(this.props.address) - .call() - .then(rnd => { - this.setState({rnd}); - }); } sendEther(ev){ @@ -56,8 +46,8 @@ class AccountBalance extends React.Component { } render(){ - const rnd = web3.utils.fromWei(this.state.rnd, "ether"); - const eth = web3.utils.fromWei(this.state.eth, "ether"); + const rnd = 1; + const eth =2; return

{this.props.name}

diff --git a/test-dapp/app/components/body.js b/test-dapp/app/components/body.js index 530d8a2..a5068ec 100644 --- a/test-dapp/app/components/body.js +++ b/test-dapp/app/components/body.js @@ -1,4 +1,5 @@ import React, {Component, Fragment} from 'react'; +import CallGasRelayed from './callgasrelayed'; import Divider from '@material-ui/core/Divider'; import EmbarkJS from 'Embark/EmbarkJS'; import IdentityFactory from 'Embark/contracts/IdentityFactory'; @@ -18,7 +19,8 @@ class Body extends Component { super(props); this.state = { tab: 0, - identityAddress: null + identityAddress: null, + nonce: '0' }; } @@ -39,13 +41,18 @@ class Body extends Component { this.setState({tab}); }; + updateNonce = (newNonce) => { + this.setState({nonce: newNonce}); + } + newIdentity = (cb) => { let toSend = IdentityFactory.methods['createIdentity()'](); toSend.estimateGas() .then(estimatedGas => { - return toSend.send({gas: estimatedGas + 100000}); + return toSend.send({gas: estimatedGas + 1000000}); }) .then((receipt) => { + console.log(receipt); const instance = receipt.events.IdentityCreated.returnValues.instance; this.setState({identityAddress: instance}); cb(); @@ -53,7 +60,7 @@ class Body extends Component { } render(){ - const {tab, identityAddress} = this.state; + const {tab, identityAddress, nonce} = this.state; return @@ -61,22 +68,24 @@ class Body extends Component { - {tab === 0 && One} - {tab === 1 && Item Two} - {tab === 2 && Item Three} + {tab === 0 && } + {tab === 1 && Item Two} + {tab === 2 && Item Three} - + + + ; } } -function TabContainer(props) { +function Container(props) { return {props.children} ; } -TabContainer.propTypes = { +Container.propTypes = { children: PropTypes.node.isRequired }; diff --git a/test-dapp/app/components/callgasrelayed.js b/test-dapp/app/components/callgasrelayed.js index 4740d74..aaf9a23 100644 --- a/test-dapp/app/components/callgasrelayed.js +++ b/test-dapp/app/components/callgasrelayed.js @@ -1,269 +1,392 @@ -import {Alert, Button, Col, ControlLabel, Form, FormControl, Grid, HelpBlock, InputGroup, Row} from 'react-bootstrap'; -import AccountBalance from './accountBalance'; -import React from 'react'; -import Web3 from 'web3'; +import React, {Component} from 'react'; +import Button from '@material-ui/core/Button'; +import Card from '@material-ui/core/Card'; +import CardActions from '@material-ui/core/CardActions'; +import CardContent from '@material-ui/core/CardContent'; +import CardHeader from '@material-ui/core/CardHeader'; +import EmbarkJS from 'Embark/EmbarkJS'; +import ErrorIcon from '@material-ui/icons/Error'; +import Grid from '@material-ui/core/Grid'; +import IdentityGasRelay from 'Embark/contracts/IdentityGasRelay'; +import PropTypes from 'prop-types'; +import STT from 'Embark/contracts/STT'; +import SnackbarContent from '@material-ui/core/SnackbarContent'; +import TestContract from 'Embark/contracts/TestContract'; +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import classNames from 'classnames'; +import config from '../config'; +import web3 from 'Embark/web3'; +import {withStyles} from '@material-ui/core/styles'; +const styles = theme => ({ + root: { + width: '100%', + backgroundColor: theme.palette.background.paper + }, + card: { + marginBottom: theme.spacing.unit * 3 + } + }); -class CallGasRelayed extends React.Component { +window.TestContract = TestContract; +class CallGasRelayed extends Component { - constructor(props) { - super(props); - - this.state = { - account: '', - address: this.props.IdentityGasRelay.options.address, - topic: '0x4964656e', - to: '0x0000000000000000000000000000000000000000', - value: 0, - data: '0x00', - nonce: 0, - gasPrice: 0, - gasLimit: 0, - gasToken: "0x0000000000000000000000000000000000000000", - signature: '', - symKey: '0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b', - kid: null, - skid: null, - msgSent: '', - payload: '', - messages: [], - web3W: null, - errorMessage: '' - }; + constructor(props){ + super(props); + this.state = { + topic: '0x4964656e', + to: '0x0000000000000000000000000000000000000000', + value: 0, + data: '0x00', + gasPrice: 0, + gasLimit: 0, + gasToken: "0x0000000000000000000000000000000000000000", + signature: '', + kid: null, + skid: null, + msgSent: '', + payload: '', + message: '', + web3W: null, + transactionError: '', + messagingError: '', + submitting: false + }; } componentDidMount(){ - __embarkContext.execWhenReady(async () => { + EmbarkJS.onReady(() => { + web3.shh.addSymKey(config.relaySymKey) + .then((skid) => { + this.setState({skid}); - let web3W = new Web3('ws://localhost:8546'); + const subsOptions = { + topic: [this.state.topic], + symKeyID: skid + }; - let accounts = await this.props.web3.eth.getAccounts(); - this.setState({ - account: accounts[0] + EmbarkJS.Messages.listenTo(subsOptions, (error, message) => { + if(error){ + console.error(error); + } else { + console.groupCollapsed("Message Sent"); + console.log(message); + console.groupEnd(); + } + this.setState({submitting: false}); + }); + + EmbarkJS.Messages.listenTo({usePrivateKey: true}, (error, message) => { + if(error){ + console.error(error); + } else { + this.setState({message: JSON.stringify(message.data, null, " ")}); + } + }); + }); }); - - let _skid = await web3W.shh.addSymKey(this.state.symKey); - let _kid = await web3W.shh.newKeyPair(); - - this.setState({ - kid: _kid, - skid: _skid, - whisper: web3W - }); - - web3W.shh.subscribe('messages', { - "privateKeyID": _kid, - "ttl": 20, - "minPow": 0.8, - "powTime": 1000 - }, (error, message, subscription) => { - if(error) { - console.log(error); - this.setState({errorMessage: error.message}); - } else { - this.state.messages.push(this.props.web3.utils.hexToAscii(message.payload)); - this.setState({messages: this.state.messages}); - } - }); - }); } - handleChange(e, name){ - const newState = {}; - newState[name] = e.target.value; - this.setState(newState); + handleChange = name => event => { + this.setState({ + [name]: event.target.value + }); + }; + + sign = (event) => { + if(event) event.preventDefault(); + + this.setState({ + msgSent: false, + payload: '', + message: '', + transactionError: '' + }); + + IdentityGasRelay.options.address = this.props.identityAddress; + + try { + IdentityGasRelay.methods.callGasRelayHash( + this.state.to, + this.state.value, + web3.utils.soliditySha3({t: 'bytes', v: this.state.data}), + this.props.nonce, + this.state.gasPrice, + this.state.gasLimit, + this.state.gasToken + ) + .call() + .then(message => { + return web3.eth.sign(message, web3.eth.defaultAccount); + }) + .then(signature => { + this.setState({signature}); + }); + } catch(error){ + this.setState({transactionError: error.message}); + } } - sendMessage(e){ - e.preventDefault(); - - this.setState({ - messages: [], - errorMessage: '' - }); - - try { - let jsonAbi = this.props.IdentityGasRelay._jsonInterface.filter(x => x.name == "callGasRelayed")[0]; - let funCall = this.props.web3.eth.abi.encodeFunctionCall(jsonAbi, [ + sendMessage = event => { + event.preventDefault(); + + this.setState({ + message: '', + messagingError: '', + submitting: true + }); + + try { + let jsonAbi = IdentityGasRelay._jsonInterface.filter(x => x.name == "callGasRelayed")[0]; + let funCall = web3.eth.abi.encodeFunctionCall(jsonAbi, [ this.state.to, this.state.value, this.state.data, - this.state.nonce, + this.props.nonce, this.state.gasPrice, this.state.gasLimit, this.state.gasToken, this.state.signature - ]); - let msgObj = { - symKeyID: this.state.skid, - sig: this.state.kid, - ttl: 1000, - powTarget: 1, - powTime: 20, - topic: this.state.topic, - payload: this.props.web3.utils.toHex({ - 'address': this.state.address, - 'encodedFunctionCall': funCall - }) - }; - - console.log(msgObj); - - this.props.web3.shh.post(msgObj) - .then((err, result) => { - console.log(result); - console.log(err); - this.setState({msgSent: result, payload: msgObj.payload}); - }); - } catch(error){ - console.error(error); - this.setState({errorMessage: error.message}); - } + ]); + const sendOptions = { + ttl: 1000, + powTarget: 1, + powTime: 20, + topic: this.state.topic, + symKeyID: this.state.skid, + data: { + 'address': this.props.identityAddress, + 'encodedFunctionCall': funCall + } + }; + EmbarkJS.Messages.sendMessage(sendOptions); + + } catch(error){ + this.setState({messagingError: error.message, submitting: false}); + } } + testContractDataSend = () => { + let jsonAbi = TestContract._jsonInterface.filter(x => x.name == "test")[0]; + let funCall = web3.eth.abi.encodeFunctionCall(jsonAbi, []); + this.setState({data: funCall, to: TestContract.options.address}); + } - async sign(ev){ - ev.preventDefault(); - - this.setState({ - msgSent: false, - payload: '', - messages: [], - errorMessage: '' - }); - - try { - let message = await this.props.IdentityGasRelay.methods.callGasRelayHash( - this.state.to, - this.state.value, - this.props.web3.utils.soliditySha3({t: 'bytes', v: this.state.data}), - this.state.nonce, - this.state.gasPrice, - this.state.gasLimit, - this.state.gasToken - ).call(); - - let accounts = await this.props.web3.eth.getAccounts(); - let _signature = await this.props.web3.eth.sign(message, accounts[0]); - - this.setState({signature: _signature}); - } catch(error){ - console.error(error); - this.setState({errorMessage: error.message}); - } + testContractDataCall = () => { + TestContract.methods.val().call().then(value => this.setState({message: "TestContract.val(): " + value})); } render(){ - return ( - { - this.state.errorMessage != '' && {this.state.errorMessage} - } -
- - - - - - - - - - - - - - Identity Address - - 0x - this.handleChange(ev, 'address')} /> - - - - - - To - - 0x - this.handleChange(ev, 'to')} /> - - - - Value - this.handleChange(ev, 'value')} /> - - - Data - - 0x - this.handleChange(ev, 'data')} /> - - - - - - Nonce - this.handleChange(ev, 'nonce')} /> - - - Gas Price in Tokens - this.handleChange(ev, 'gasPrice')} /> - - - Gas Limit in Ether - this.handleChange(ev, 'gasLimit')} /> - - - Gas Token - - 0x - this.handleChange(ev, 'gasToken')} /> - - RND: {this.props.RND.options.address} - ETH: 0x0000000000000000000000000000000000000000 - - - - - - - - Signature: {this.state.signature} - - - - - Symmetric Key - - 0x - - - - - Topic - - 0x - this.handleChange(ev, 'topic')} /> - - - - - - - - - {this.state.msgSent} - - - - -

Whisper Messages

- { - this.state.messages.map((msg, i) =>

{msg}

) - } -
-
-
- ); - } - } + const {classes} = this.props; + return
+ { this.state.transactionError && } + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + -export default CallGasRelayed; + +
+ + { this.state.messagingError && } + + + + + + + + + + + + + + + Message Received: + +
{this.state.message}
+
+
+
; + } +} + +CallGasRelayed.propTypes = { + classes: PropTypes.object.isRequired, + nonce: PropTypes.string.isRequired, + identityAddress: PropTypes.string +}; + +const variantIcon = { + error: ErrorIcon +}; + +const styles1 = theme => ({ +error: { + backgroundColor: theme.palette.error.dark +}, +icon: { + fontSize: 20 +}, +iconVariant: { + opacity: 0.9, + marginRight: theme.spacing.unit +}, +message: { + display: 'flex', + alignItems: 'center' +} +}); + +function MySnackbarContent(props) { + const {classes, className, message, variant, ...other} = props; + const Icon = variantIcon[variant]; + + return ( + + + {message} + + } + {...other} + /> + ); +} + +MySnackbarContent.propTypes = { + classes: PropTypes.object.isRequired, + className: PropTypes.string, + message: PropTypes.node, + onClose: PropTypes.func, + variant: PropTypes.oneOf(['success', 'warning', 'error', 'info']).isRequired +}; + +const MySnackbarContentWrapper = withStyles(styles1)(MySnackbarContent); + +export default withStyles(styles)(CallGasRelayed); diff --git a/test-dapp/app/components/status.js b/test-dapp/app/components/status.js index ee92a90..a28ba8e 100644 --- a/test-dapp/app/components/status.js +++ b/test-dapp/app/components/status.js @@ -4,12 +4,14 @@ import BalanceIcon from '@material-ui/icons/AccountBalance'; import Button from '@material-ui/core/Button'; import CircularProgress from '@material-ui/core/CircularProgress'; import EmbarkJS from 'Embark/EmbarkJS'; +import Identity from 'Embark/contracts/Identity'; import KeyIcon from '@material-ui/icons/VpnKey'; import LinearProgress from '@material-ui/core/LinearProgress'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemText from '@material-ui/core/ListItemText'; +import NumberIcon from '@material-ui/icons/ConfirmationNumber'; import PropTypes from 'prop-types'; import RefreshIcon from '@material-ui/icons/Refresh'; import STT from 'Embark/contracts/STT'; @@ -17,7 +19,7 @@ import Typography from '@material-ui/core/Typography'; import config from '../config'; import web3 from 'Embark/web3'; import {withStyles} from '@material-ui/core/styles'; - +window.Id = Identity; const styles = theme => ({ button: { marginRight: theme.spacing.unit * 2 @@ -71,18 +73,21 @@ class Status extends Component { relayerAddress: config.relayAccount }); - this.updateBalances(); - web3.eth.subscribe('newBlockHeaders') - .on("data", (blockHeader) => { - if(blockHeader.number){ - this.setState({block: blockHeader.number}); - this.updateBalances(); - } - }); + setInterval(() => { + this.getBlock(); + }, 5000); + }); + } + + getBlock = () => { + web3.eth.getBlock('latest') + .then((block) => { + this.setState({block: block.number}); + this.readChain(); }); } - updateBalances = () => { + readChain = () => { if(this.props.identityAddress){ web3.eth.getBalance(this.props.identityAddress) .then(identityEthBalance => { @@ -94,6 +99,13 @@ class Status extends Component { .then(identitySTTBalance => { this.setState({identitySTTBalance: web3.utils.fromWei(identitySTTBalance, 'ether')}); }); + + Identity.options.address = this.props.identityAddress; + Identity.methods.nonce() + .call() + .then((nonce) => { + this.props.nonceUpdateFunction(nonce); + }); } web3.eth.getBalance(this.state.relayerAddress) @@ -115,7 +127,7 @@ class Status extends Component { submitState.generateSTT = true; this.setState({submitState}); - let toSend = STT.methods.generateTokens(this.props.identityAddress, web3.utils.toWei(5000, 'ether')); + let toSend = STT.methods.generateTokens(this.props.identityAddress, web3.utils.toWei('5000', 'ether')); toSend.estimateGas() .then(estimatedGas => { return toSend.send({gas: estimatedGas + 10000}); @@ -150,7 +162,7 @@ class Status extends Component { submitState.etherSend = true; this.setState({submitState}); - web3.eth.sendTransaction({from: web3.eth.defaultAccount, to: this.state.relayerAddress, value: web3.utils.toWei(1, "ether")}) + web3.eth.sendTransaction({from: web3.eth.defaultAccount, to: this.state.relayerAddress, value: web3.utils.toWei('1', "ether")}) .then((receipt) => { console.log(receipt); submitState = this.state.submitState; @@ -160,7 +172,7 @@ class Status extends Component { } render(){ - const {classes, identityAddress} = this.props; + const {classes, identityAddress, nonce} = this.props; const {identityEthBalance, relayerAddress, relayerEthBalance, identitySTTBalance, relayerSTTBalance, submitState, block} = this.state; return
@@ -190,6 +202,15 @@ class Status extends Component { secondary="Address" /> + + + + + + @@ -252,7 +273,9 @@ class Status extends Component { Status.propTypes = { classes: PropTypes.object.isRequired, identityAddress: PropTypes.string, - identityCreationFunction: PropTypes.func.isRequired + nonce: PropTypes.string.isRequired, + identityCreationFunction: PropTypes.func.isRequired, + nonceUpdateFunction: PropTypes.func.isRequired }; export default withStyles(styles)(Status); diff --git a/test-dapp/app/config.js b/test-dapp/app/config.js index 5ef8232..5d57236 100644 --- a/test-dapp/app/config.js +++ b/test-dapp/app/config.js @@ -1,5 +1,6 @@ const config = { - "relayAccount": "0x3c72082cbd10a874d673f25e0d48b72d294b5368" + "relayAccount": "0x91b3c570ace45716010e162cbbc1b27cd1a10b65", + "relaySymKey": "0xd0d905c1c62b810b787141430417caf2b3f54cffadb395b7bb39fdeb8f17266b" }; export default config;