* init reorg

* updated readme

* fix CI

* remove outdated ipfs-node example

* add Readme

* update readme, add config file

Co-authored-by: folex <0xdxdy@gmail.com>
This commit is contained in:
boneyard93501
2021-07-16 02:04:18 -05:00
committed by GitHub
parent c98c838a2d
commit 6381411ed9
271 changed files with 581 additions and 3013 deletions

View File

@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.eslintcache

View File

@ -0,0 +1,8 @@
module.exports = {
semi: true,
trailingComma: "all",
singleQuote: true,
printWidth: 120,
tabWidth: 4,
useTabs: false
};

View File

@ -0,0 +1,15 @@
## How to run
To run app in the development mode use:
npm start
To run tests in the interactive watch mode use:
npm test
To make a production build use:
npm run build

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
{
"name": "fluent-pad",
"version": "0.1.0",
"private": true,
"dependencies": {
"@fluencelabs/fluence": "^0.9.17",
"@fluencelabs/fluence-network-environment": "^1.0.8",
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.2.2",
"@testing-library/user-event": "^12.5.0",
"@types/jest": "^26.0.19",
"@types/node": "^12.19.9",
"@types/react": "^16.14.2",
"@types/react-dom": "^16.9.10",
"node-sass": "^4.14.1",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "4.0.1",
"typescript": "^4.1.3",
"web-vitals": "^0.2.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12
},
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1,45 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/tonsky/FiraCode@4/distr/fira_code.css">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@ -0,0 +1,199 @@
$bg-color1: white;
$bg-color2: #f4f4f4;
$font-color1: black;
$color-disabled: lightgray;
$color1: black;
$color2: rgb(214, 214, 214);
$accent-color: rgb(225, 30, 90);
$header-height: 60px;
$border-radius: 10px;
@mixin font($size) {
font-family: 'Montserrat', sans-serif;
font-size: $size;
}
$shadow: 0px 5px 20px rgba(0, 0, 0, 0.1);
body {
background-color: $bg-color2;
font-family: 'Montserrat', sans-serif;
}
.header-wrapper {
padding: 0 20px;
height: $header-height;
background-color: $bg-color1;
color: $font-color1;
box-shadow: $shadow;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: 1200px;
height: 100%;
margin-left: auto;
margin-right: auto;
@media (max-width: 1280px) {
width: calc(100vw - 80px);
margin-left: 20px;
margin-right: 45px;
}
}
.content {
width: 1700px;
margin-left: auto;
margin-right: auto;
padding-top: 50px;
@media (max-width: 1280px) {
width: calc(100vw - 80px);
margin-left: 35px;
margin-right: 45px;
}
}
.text-input {
width: 100%;
height: 40px;
padding: 0 15px;
box-sizing: border-box;
margin-top: 5px;
border: none;
font-style: normal;
@include font(15px);
color: $color1;
box-shadow: $shadow;
&::placeholder {
color: $color2;
}
&:hover,
&:focus {
outline: 1px solid white;
border: 1px solid $accent-color;
}
}
.button {
display: inline;
width: 100px;
height: 40px;
box-sizing: border-box;
background-color: white;
margin-top: 10px;
margin-right: 10px;
border: none;
font-style: normal;
@include font(15px);
color: $color1;
box-shadow: $shadow;
&::placeholder {
color: $color2;
}
&:hover,
&:focus {
outline: 1px solid white;
border: 1px solid $accent-color;
}
&:disabled {
color: gray;
}
}
.form-caption {
color: $accent-color;
text-align: center;
font-style: normal;
font-weight: bold;
@include font(20px);
margin-bottom: 20px;
}
.header-item {
@include font(14px);
text-transform: uppercase;
& button {
@include font(14px);
text-transform: uppercase;
background: none;
border-top: none;
border-right: none;
border-left: none;
border-bottom: 1px solid $accent-color;
text-decoration: none;
outline: none;
&:hover,
&:focus {
color: $accent-color;
border-bottom: 2px solid $accent-color;
}
}
}
.red {
color: red;
}
.green {
color: green;
}
.accent {
color: $accent-color;
}
.bold {
font-weight: bold;
}
.table-wrapper {
width: 100%;
min-height: 800px;
margin-top: 50px;
padding: 10px;
box-sizing: border-box;
background-color: white;
box-shadow: $shadow;
}
th {
@include font(18px);
min-width: 100px;
border-bottom: 20px solid transparent;
}
td {
@include font(14px);
border-left: 15px solid transparent;
border-right: 15px solid transparent;
}

View File

@ -0,0 +1,141 @@
import { createClient, FluenceClient, subscribeToEvent } from '@fluencelabs/fluence';
import React, { useEffect, useState } from 'react';
import {
createFilter,
getFilterChanges,
getFilterChangesWithoutNulls,
getTxInfo,
relayNode,
removeFilter,
TxInfo,
} from 'src/fluence';
import './App.scss';
const intervalMs = 4000;
const App = () => {
const [client, setClient] = useState<FluenceClient | null>(null);
const [ethNodeUrl, setEthNodeUrl] = useState('');
const [filterId, setFilterId] = useState<string | null>(null);
const [timer, setTimer] = useState<any>();
const [data, setData] = useState<TxInfo[]>([]);
const updateData = async (filterId) => {
if (!filterId || !client) {
return;
}
try {
const data = await getFilterChangesWithoutNulls(client, ethNodeUrl, filterId, '50');
console.log(data);
setData((prev) => {
return [...data, ...prev];
});
} catch (err) {
console.log('updateData failed', err);
}
};
useEffect(() => {
const fn = async () => {
try {
const client = await createClient(relayNode);
setClient(client);
} catch (err) {
console.log('Client initialization failed', err);
}
};
fn();
}, []);
const start = async () => {
if (!client) {
return;
}
try {
const filterId = await createFilter(client, ethNodeUrl);
setFilterId(filterId);
const timer = setInterval(updateData, intervalMs, filterId);
setTimer(timer);
} catch (err) {
console.log('createFilter failed', err);
}
};
const stop = async () => {
if (!filterId || !client) {
return;
}
try {
clearInterval(timer);
setTimer(null);
const res = await removeFilter(client, ethNodeUrl, filterId);
console.log(res);
setFilterId(null);
setData([]);
} catch (err) {
console.log('stop failed', err);
}
};
return (
<>
<div className="header-wrapper">
<div className="header">
<div className="header-item"></div>
<div className="header-item">
Connection status: {client ? <span className="accent">connected</span> : 'disconnected'}
</div>
</div>
</div>
<div className="content">
<div>Node address. e.g: https://eth-mainnet.alchemyapi.io/v2/xxxxxxx-xxxxxxxx-xxxxxxxxxx_xxxx</div>
<div>
<input
className="text-input"
onChange={(e) => setEthNodeUrl(e.target.value)}
type="text"
value={ethNodeUrl}
/>
</div>
<div className="buttons">
<button disabled={!ethNodeUrl} className="button" onClick={start}>
start
</button>
<button className="button" onClick={stop}>
stop
</button>
</div>
<div className="table-wrapper">
<table className="table">
<tr>
<th>from</th>
<th>to</th>
<th>gas</th>
<th>gas price</th>
<th>hash</th>
</tr>
{data.map((x) => (
<tr key={x.hash}>
<td className="td1">{x.from}</td>
<td className="td2">{x.to}</td>
<td className="td3">{parseInt(x.gas, 16)}</td>
<td className="td4">{parseInt(x.gasPrice, 16)}</td>
<td className="td5">{x.hash}</td>
</tr>
))}
</table>
</div>
</div>
</>
);
};
export default App;

View File

@ -0,0 +1,179 @@
import { FluenceClient, Particle, sendParticleAsFetch } from '@fluencelabs/fluence';
import { testNet, dev } from '@fluencelabs/fluence-network-environment';
const timeout = 20000;
export const relayNode = dev[2];
const node = dev[2].peerId;
const serviceId = '8067ab18-1a95-4cd9-b477-a33e3549012f';
const bluePrintId = 'uuid-dc0b258-65f0-11eb-bf24-acde48001122';
export const getInterface = async (client: FluenceClient) => {
const script = `
(seq
(call myRelay ("op" "identity") [])
(seq
(call node ("srv" "get_interfaces") [arg] result)
(seq
(call myRelay ("op" "identity") [])
(call myPeerId ("_callback" "getInterface") [result])
)
)
)
`;
const data = {
node: node,
// arg: { blueprint_id: bluePrintId, service_id: serviceId },
arg: serviceId,
myRelay: client.relayPeerId,
myPeerId: client.selfPeerId,
};
return sendParticleAsFetch(client, new Particle(script, data, 999999), 'getInterface');
};
type Method =
| 'eth_get_balance'
| 'test_eth_get_balance_bad'
| 'test_filters'
| 'test_drop_outliers_and_average'
| 'test_eth_get_balance_good'
| 'test_simple_average'
| 'test_pending_with_null_filter'
| 'new_pending_tx_filter'
| 'eth_hash_method_id'
| 'test_eth_hash_method_id'
| 'sum_data'
| 'drop_outliers_and_average'
| 'uninstall_filter'
| 'eth_get_tx_by_hash'
| 'simple_average'
| 'test_eth_get_tx_by_hash'
| 'eth_get_block_height'
| 'get_filter_changes'
| 'get_filter_changes_without_null';
const callEthService = async <T>(client: FluenceClient, method: Method, args: any[], ttl: number) => {
const argsNames = args.map((val, index) => `arg${index}`).join(' ');
const script = `
(seq
(call myRelay ("op" "identity") [])
(seq
(call node (serviceId fnName) [${argsNames}] result)
(seq
(call myRelay ("op" "identity") [])
(call myPeerId ("_callback" "${method}") [result])
)
)
)
`;
const data = new Map();
data.set('node', node);
data.set('serviceId', serviceId);
data.set('fnName', method);
data.set('myRelay', client.relayPeerId);
data.set('myPeerId', client.selfPeerId);
for (let i = 0; i < args.length; i++) {
data.set('arg' + i, args[i]);
}
return await sendParticleAsFetch<T>(client, new Particle(script, data, ttl), method);
};
export const createFilter = async (client: FluenceClient, url: string): Promise<string> => {
const [res] = await callEthService<[string]>(client, 'new_pending_tx_filter', [url], timeout);
return res;
};
export const getFilterChanges = async (
client: FluenceClient,
url: string,
filterId: string,
): Promise<Array<string>> => {
const [res] = await callEthService<[string]>(client, 'get_filter_changes', [url, filterId], timeout);
return JSON.parse(res).result;
};
export const getFilterChangesWithoutNulls = async (
client: FluenceClient,
url: string,
filterId: string,
n: string,
): Promise<Array<TxInfo>> => {
const [res] = await callEthService<[any]>(client, 'get_filter_changes_without_null', [url, filterId, n], timeout);
return res;
};
export const removeFilter = async (client: FluenceClient, url: string, filterId: string): Promise<boolean> => {
const [res] = await callEthService<[number]>(client, 'uninstall_filter', [url, filterId], timeout);
return res === 1 ? true : false;
};
export interface TxInfo {
/**
* DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending.
*/
blockHash: any;
/**
* QUANTITY - block number where this transaction was in. null when its pending.
*/
blockNumber: any;
/**
* DATA, 20 Bytes - address of the sender.
*/
from: any;
/**
* QUANTITY - gas provided by the sender.
*/
gas: any;
/**
* QUANTITY - gas price provided by the sender in Wei.
*/
gasPrice: any;
/**
* DATA, 32 Bytes - hash of the transaction.
*/
hash: any;
/**
* DATA - the data send along with the transaction.
*/
input: any;
/**
* QUANTITY - the number of transactions made by the sender prior to this one.
*/
nonce: any;
/**
* DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction.
*/
to: any;
/**
* QUANTITY - integer of the transactions index position in the block. null when its pending.
*/
transactionIndex: any;
/**
* QUANTITY - value transferred in Wei.
*/
value: any;
/**
* QUANTITY - ECDSA recovery id
*/
v: any;
/**
* DATA, 32 Bytes - ECDSA signature r
*/
r: any;
/**
* DATA, 32 Bytes - ECDSA signature s
*/
s: any;
}
export const getTxInfo = async (client: FluenceClient, url: string, tx: string): Promise<TxInfo> => {
const [raw] = await callEthService<[string]>(client, 'eth_get_tx_by_hash', [url, tx], timeout);
const res = JSON.parse(raw);
return res.result;
};

View File

@ -0,0 +1,144 @@
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote {
&:before,
&:after {
content: '';
content: none;
}
}
q {
&:before,
&:after {
content: '';
content: none;
}
}
table {
border-collapse: collapse;
border-spacing: 0;
}

View File

@ -0,0 +1,14 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.scss';
import App from './components/App';
import log from 'loglevel';
log.setLevel('error');
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root'),
);

View File

@ -0,0 +1 @@
/// <reference types="react-scripts" />

View File

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

View File

@ -0,0 +1,30 @@
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"baseUrl": ".",
"noImplicitAny": false,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx"
},
"include": [
"src"
]
}