From 2aa7ea91a4026241df07582fc919b5267037b9c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=B3=D0=BE=D1=80=D1=8C=20=D0=A1=D0=BE=D0=B1=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=D0=B2?= Date: Sat, 22 Jun 2019 20:11:28 +0300 Subject: [PATCH] Added initial frontend --- frontend/README.md | 6 + frontend/index.html | 90 +++++++++ frontend/index.js | 387 +++++++++++++++++++++++++++++++++++++ frontend/package.json | 31 +++ frontend/webpack.config.js | 35 ++++ 5 files changed, 549 insertions(+) create mode 100644 frontend/README.md create mode 100644 frontend/index.html create mode 100644 frontend/index.js create mode 100644 frontend/package.json create mode 100644 frontend/webpack.config.js diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..89d71e5 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,6 @@ +# Usage +1. run ```npm i``` + +2. run ```npm run build``` + +3. run ```npm run start``` \ No newline at end of file diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..8153483 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,90 @@ + + + + + + Lazy snark dashboard + + + + + + +
+
+

+

+ Lazy snark dashboard +

+

+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+
+ + + \ No newline at end of file diff --git a/frontend/index.js b/frontend/index.js new file mode 100644 index 0000000..a9d51a3 --- /dev/null +++ b/frontend/index.js @@ -0,0 +1,387 @@ +//CONNECT FLUENCE +$(document).ready(function() { + + // CONNECT WEB3 + if (typeof web3 !== 'undefined') { + // Use Mist/MetaMask's provider + let web3js = new Web3(web3.currentProvider); + } else { + console.log('No web3? You should consider trying MetaMask!'); + // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail) + let web3js = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); + } + + //console.log(web3js); + + var controllerAddress = '0x2c13c996bad85b707ee7cf40b4e45d00abdf7d7b'; + let ControllerAbi = '[\n' + + '\t{\n' + + '\t\t"constant": false,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "id",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "challenge",\n' + + '\t\t"outputs": [],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "nonpayable",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": false,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "id",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "finzalize",\n' + + '\t\t"outputs": [],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "nonpayable",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": false,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"name": "data",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"name": "proof",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "submit",\n' + + '\t\t"outputs": [],\n' + + '\t\t"payable": true,\n' + + '\t\t"stateMutability": "payable",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"anonymous": false,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"indexed": true,\n' + + '\t\t\t\t"name": "sender",\n' + + '\t\t\t\t"type": "address"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"indexed": false,\n' + + '\t\t\t\t"name": "index",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"components": [\n' + + '\t\t\t\t\t\t\t{\n' + + '\t\t\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t\t\t}\n' + + '\t\t\t\t\t\t],\n' + + '\t\t\t\t\t\t"name": "data",\n' + + '\t\t\t\t\t\t"type": "tuple"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"components": [\n' + + '\t\t\t\t\t\t\t{\n' + + '\t\t\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t\t\t}\n' + + '\t\t\t\t\t\t],\n' + + '\t\t\t\t\t\t"name": "proof",\n' + + '\t\t\t\t\t\t"type": "tuple"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "submitter",\n' + + '\t\t\t\t\t\t"type": "address"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "timestamp",\n' + + '\t\t\t\t\t\t"type": "uint96"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "status",\n' + + '\t\t\t\t\t\t"type": "uint8"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"indexed": false,\n' + + '\t\t\t\t"name": "task",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "Submitted",\n' + + '\t\t"type": "event"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"anonymous": false,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"indexed": true,\n' + + '\t\t\t\t"name": "challenger",\n' + + '\t\t\t\t"type": "address"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"indexed": false,\n' + + '\t\t\t\t"name": "index",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "Challenged",\n' + + '\t\t"type": "event"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": true,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "id",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "getDataById",\n' + + '\t\t"outputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"components": [\n' + + '\t\t\t\t\t\t\t{\n' + + '\t\t\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t\t\t}\n' + + '\t\t\t\t\t\t],\n' + + '\t\t\t\t\t\t"name": "data",\n' + + '\t\t\t\t\t\t"type": "tuple"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"components": [\n' + + '\t\t\t\t\t\t\t{\n' + + '\t\t\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t\t\t}\n' + + '\t\t\t\t\t\t],\n' + + '\t\t\t\t\t\t"name": "proof",\n' + + '\t\t\t\t\t\t"type": "tuple"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "submitter",\n' + + '\t\t\t\t\t\t"type": "address"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "timestamp",\n' + + '\t\t\t\t\t\t"type": "uint96"\n' + + '\t\t\t\t\t},\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "status",\n' + + '\t\t\t\t\t\t"type": "uint8"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"name": "task",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "view",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": true,\n' + + '\t\t"inputs": [],\n' + + '\t\t"name": "last5Timestamps",\n' + + '\t\t"outputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "result",\n' + + '\t\t\t\t"type": "uint256[5]"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "view",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": true,\n' + + '\t\t"inputs": [],\n' + + '\t\t"name": "stake",\n' + + '\t\t"outputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "view",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": true,\n' + + '\t\t"inputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "",\n' + + '\t\t\t\t"type": "uint256"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"name": "tasks",\n' + + '\t\t"outputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"name": "data",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"components": [\n' + + '\t\t\t\t\t{\n' + + '\t\t\t\t\t\t"name": "x",\n' + + '\t\t\t\t\t\t"type": "uint256"\n' + + '\t\t\t\t\t}\n' + + '\t\t\t\t],\n' + + '\t\t\t\t"name": "proof",\n' + + '\t\t\t\t"type": "tuple"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "submitter",\n' + + '\t\t\t\t"type": "address"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "timestamp",\n' + + '\t\t\t\t"type": "uint96"\n' + + '\t\t\t},\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "status",\n' + + '\t\t\t\t"type": "uint8"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "view",\n' + + '\t\t"type": "function"\n' + + '\t},\n' + + '\t{\n' + + '\t\t"constant": true,\n' + + '\t\t"inputs": [],\n' + + '\t\t"name": "verifier",\n' + + '\t\t"outputs": [\n' + + '\t\t\t{\n' + + '\t\t\t\t"name": "",\n' + + '\t\t\t\t"type": "address"\n' + + '\t\t\t}\n' + + '\t\t],\n' + + '\t\t"payable": false,\n' + + '\t\t"stateMutability": "view",\n' + + '\t\t"type": "function"\n' + + '\t}\n' + + ']'; + ControllerAbi = JSON.parse(ControllerAbi); + //console.log(ControllerAbi); + let ControllerContract = web3.eth.contract(ControllerAbi); + //console.log(ControllerContract); + let contractInstance = ControllerContract.at(controllerAddress); + //console.log(contractInstance); +/* + // save fluence to global variable, so it can be accessed from Developer Console + window.fluence = fluence; + + // convert result to a string + window.getResultAsString = function (result) { + return result.result().then((r) => r.asString()) + }; + + window.logResultAsString = function (result) { + return getResultAsString(result).then((r) => console.log(r)) + }; +*/ +console.log(contractInstance); +contractInstance.last5Timestamps(function (err, result) { + console.log(result); + for (let i = 0; i < 5; i++) { + $('#state-id-' + i).text(result[i]); + } +}); + + + /*window.onload = function () { + + // address to Fluence contract in Ethereum blockchain. Interaction with blockchain created by MetaMask or with local Ethereum node + let contractAddress = "0xeFF91455de6D4CF57C141bD8bF819E5f873c1A01"; + + // set ethUrl to `undefined` to use MetaMask instead of Ethereum node + let ethUrl = "http://geth.fluence.one:8545/"; + + // application to interact with that stored in Fluence contract + let appId = "218"; + + // create a session between client and backend application, and then join the game + fluence.connect(contractAddress, appId, ethUrl).then((s) => { + console.log("Session created"); + window.session = s; + }).then(() => join()); + + + // send request to list last txses + + for (let i = 0; i < 5; i++) { + let id = document.getElementById('state-id-' + i).textContent; + contractInstance.giveDataFromId(id, function (err, result) { + + let fluenceResponse = session.request(`{ "player_id": ${id}, "action": "GetBalance"}`); + $('#state-status-fluence-' + i).text(fluenceResponse); + if (fluenceResponse == true) { + $('challenge-' + i).prop('disabled', true); + } else { + $('challenge-' + i).text('Challenge on Ethereum!') + } + }); + } + + };*/ + + + $('button').click(function () { + //console.log($(this)[0].id.slice(-1)); + if ($(this)[0].textContent === 'Challenge on Fluence!') { + let id = $(this)[0].id.slice(-1); + //console.log(id); + //console.log(contractInstance); + contractInstance.getDataById(id, function (err, result) { + //console.log(err); + console.log(result); + // let fluenceResponse = session.request(JSON.stringify(request)); + // $('#state-status-fluence-' + i).text(result); + // if (fluenceResponse === true) { + // $('challenge-' + i).prop('disabled', true); + // } else { + // $('#challenge-' + i).text('Challenge on Ethereum!') + // } + }); + // } else { + // challengeEthereum(id); + } + }); +}); + +function challengeEthereum(jobId) { + contractInstance.challenge.sendTransaction(jobId, function (err, txHash) { + $('challenge-' + jobId).text('See tx on Etherscan!').attr("href", "https://ropsten.etherscan.io/tx/" + txHash); + }); +} + + +import * as fluence from "fluence"; diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..337fe53 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,31 @@ +{ + "name": "frontend-challenger", + "version": "1.0.0", + "description": "", + "private": true, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "webpack-dev-server", + "build": "webpack" + }, + "files": [ + "index.html" + ], + "keywords": [], + "author": "", + "devDependencies": { + "copy-webpack-plugin": "^5.0.2", + "css-loader": "^2.1.1", + "html-webpack-plugin": "^3.2.0", + "style-loader": "0.23.1", + "webpack": "^4.29.6", + "webpack-cli": "^3.3.0", + "webpack-dev-server": "^3.2.1", + "web3": "1.0.0-beta.55" + }, + "dependencies": { + "Package": "0.0.1", + "fluence": "0.1.26" + } +} + diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js new file mode 100644 index 0000000..136e96c --- /dev/null +++ b/frontend/webpack.config.js @@ -0,0 +1,35 @@ +const path = require('path'); +const webpack = require('webpack'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = { + // use index.js as entrypoint + entry: { + app: ['./index.js'] + }, + devServer: { + contentBase: './bundle', + hot: true + }, + mode: "development", + module: { + rules: [ + { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + } + ] + }, + // build all code in `bundle.js` in `bundle` directory + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'bundle') + }, + plugins: [ + // create `index.html` with imported `bundle.js` + new CopyWebpackPlugin([{ + from: './*.html' + }]), + new webpack.HotModuleReplacementPlugin() + ] +};