├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── public
├── images
│ └── blue-q_icon.svg
└── index.html
├── src
├── components
│ ├── codeSample.js
│ ├── index.js
│ ├── log.js
│ ├── methodCall.js
│ ├── methodList.js
│ ├── navBar.js
│ ├── needLibMessage.js
│ ├── needMethodMessage.js
│ ├── needURLMessage.js
│ ├── sponsoredAd.js
│ ├── statusBar.js
│ └── web3Menu.js
├── containers
│ ├── codeSampleContainer.js
│ ├── index.js
│ ├── logsContainer.js
│ ├── methodCallContainer.js
│ ├── navBarContainer.js
│ ├── sponsoredAdContainer.js
│ ├── statusBarContainer.js
│ └── web3MenuContainer.js
├── context
│ ├── appProvider.js
│ ├── index.js
│ ├── logProvider.js
│ └── web3Provider.js
├── helpers
│ ├── buildProvider.js
│ ├── contracts.js
│ ├── libs
│ │ ├── curl.js
│ │ ├── ethers.js
│ │ ├── index.js
│ │ └── web3js.js
│ ├── web3Config.js
│ └── web3State.js
├── index.js
├── tailwind.css
└── tailwind.output.css
├── tailwind.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | build
3 | .DS_Store
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Auston Bunsen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | EtherFlow
3 |
4 |
5 | A tool for interacting/debugging with Ethereum JSON-RPC and generating sample code.
6 |
7 | View Demo
8 | ·
9 | Report Bug
10 | ·
11 | Request Feature
12 |
13 |
14 |
15 | # About
16 |
17 | EtherFlow is a tool for sending requests to Ethereum JSON-RPC endpoints without having to write code. It supports most standard RPC methods and the [trace module for Parity/OpenEthereum](https://openethereum.github.io/wiki/JSONRPC-trace-module#trace_transaction). It updates the URL and embeds your RPC endpoint, preferred library, method call and params in the URL for easy sharing to any relevant parties.
18 |
19 | # Quik Start
20 |
21 | If you don't want to install anything just go here: https://etherflow.quiknode.io
22 |
23 | You can also just run this in your terminal:
24 |
25 | ```
26 | git clone git@github.com:abunsen/etherflow.git && cd etherflow && npm install && npm start
27 | ```
28 |
29 | # Adding a new lib
30 |
31 | There is a folder `etherflow -> src -> helpers -> libs` [link](src/helpers/libs) that contains all of the supported libraries. If you'd like to add a new front end library, it's easy enough:
32 |
33 | 1. Add a file in the above folder with the `.js`
34 | 2. Add a every single supported RPC method from [here](src/helpers/web3Config.js) to an exported object
35 | 3. Add `exec`, `codeSample` and `args` to each method
36 | 4. Test it
37 | 5. You're done!
38 |
39 | If you'd like to add a new back end library, please [open an issue](https://github.com/abunsen/etherflow/issues/new?assignees=&labels=&template=feature_request.md&title=New+Backend+Lib+Support) so we can discuss the best way to support this!
40 |
41 | # Contributing
42 |
43 | Please feel free to add tests, change the code so it has better organization, etc. I'm very happy to receive PRs.
44 |
45 | # Wishlist (in order of priority)
46 |
47 | - [x] Enable ABI upload for smart contracts on eth_call
48 | - [x] Make trace_call use the ABI from point above (docs: https://openethereum.github.io/wiki/JSONRPC-trace-module)
49 | - [ ] Enable eth_newFilter for web3.js
50 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "etherflow",
3 | "version": "1.0.0",
4 | "description": "A web interface for debugging ethereum nodes",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build:tailwind": "tailwindcss build src/tailwind.css -o src/tailwind.output.css",
9 | "prestart": "npm run build:tailwind",
10 | "prebuild": "npm run build:tailwind",
11 | "start": "concurrently \"react-scripts start\""
12 | },
13 | "keywords": [
14 | "ethereum",
15 | "web3",
16 | "ethers.js"
17 | ],
18 | "author": "Auston Bunsen",
19 | "license": "MIT",
20 | "dependencies": {
21 | "@reach/router": "^1.3.4",
22 | "@tailwindcss/ui": "^0.3.1",
23 | "bootstrap": "^4.5.0",
24 | "concurrently": "^5.2.0",
25 | "console-feed": "^3.0.0",
26 | "cors": "^2.8.5",
27 | "ethers": "^5.0.5",
28 | "express": "^4.17.1",
29 | "lodash": "^4.17.19",
30 | "react": "^16.13.1",
31 | "react-dom": "^16.13.1",
32 | "react-scripts": "^3.4.3",
33 | "react-syntax-highlighter": "^12.2.1",
34 | "tailwindcss": "^1.5.1",
35 | "web3": "^1.2.11"
36 | },
37 | "eslintConfig": {
38 | "extends": "react-app"
39 | },
40 | "prettier": {
41 | "singleQuote": true,
42 | "semi": true
43 | },
44 | "browserslist": {
45 | "production": [
46 | ">0.2%",
47 | "not dead",
48 | "not op_mini all"
49 | ],
50 | "development": [
51 | "last 1 chrome version",
52 | "last 1 firefox version",
53 | "last 1 safari version"
54 | ]
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/public/images/blue-q_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 | EtherFlow - Ethereum Node Tester & RPC Call Composer
17 |
18 |
19 |
20 |
21 |
22 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/components/codeSample.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import SyntaxHighlighter from 'react-syntax-highlighter';
3 | import { docco } from 'react-syntax-highlighter/dist/esm/styles/hljs';
4 | import Web3RpcCalls from '../helpers/web3Config';
5 |
6 | const CodeSample = ({
7 | web3Lib,
8 | args,
9 | currentMethod,
10 | hideCodeSample,
11 | url,
12 | visible,
13 | }) => {
14 | const codeSampleText =
15 | currentMethod &&
16 | web3Lib &&
17 | url &&
18 | Web3RpcCalls[currentMethod][web3Lib]['codeSample'](url, ...args);
19 | const classes = `${visible ? '' : 'hidden'} fixed inset-0 overflow-hidden`;
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | Code Sample for{' '}
31 | {currentMethod}
32 |
33 |
34 |
39 |
45 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
66 | {codeSampleText}
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | );
76 | };
77 |
78 | export { CodeSample };
79 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import { Logs } from './log';
2 | import { MethodCall } from './methodCall';
3 | import { StatusBar } from './statusBar';
4 | import { CodeSample } from './codeSample';
5 | import { NavBar } from './navBar';
6 | import { Web3Menu } from './web3Menu';
7 | import { NeedMethodMessage } from './needMethodMessage';
8 | import { NeedURLMessage } from './needURLMessage';
9 | import { SponsoredAd } from './sponsoredAd';
10 |
11 | export {
12 | CodeSample,
13 | Logs,
14 | MethodCall,
15 | NavBar,
16 | NeedMethodMessage,
17 | NeedURLMessage,
18 | SponsoredAd,
19 | StatusBar,
20 | Web3Menu,
21 | };
22 |
--------------------------------------------------------------------------------
/src/components/log.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Console } from 'console-feed';
3 |
4 | const Logs = ({ logs }) => {
5 | return (
6 |
7 |
8 | Logs
9 |
10 |
11 |
12 |
13 |
14 | );
15 | };
16 |
17 | export { Logs };
18 |
--------------------------------------------------------------------------------
/src/components/methodCall.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Textarea = ({ placeholder, updateValue, initialVal }) => {
4 | return (
5 |
13 | );
14 | };
15 |
16 | const TextField = ({ placeholder, updateValue, initialVal }) => {
17 | return (
18 |
19 | updateValue(e.target.value)}
24 | defaultValue={initialVal}
25 | />
26 |
27 | );
28 | };
29 |
30 | const BooleanSelect = ({ initialVal, updateValue }) => {
31 | return (
32 | updateValue(e.target.value)}
36 | >
37 |
38 | {' '}
39 | -- select an option --{' '}
40 |
41 |
42 | false
43 |
44 |
45 | true
46 |
47 |
48 | );
49 | };
50 |
51 | const Dropdown = ({ dropdownOptions = [], updateValue, disabled, val }) => {
52 | return (
53 | updateValue(e.target.value)}
57 | disabled={disabled}
58 | >
59 | {dropdownOptions.length !== 1 && (
60 |
61 | {' '}
62 | -- select an option --{' '}
63 |
64 | )}
65 | {dropdownOptions.map((option, index) => (
66 |
67 | {option.name}
68 |
69 | ))}
70 |
71 | );
72 | };
73 |
74 | const Field = ({
75 | description,
76 | placeholder,
77 | type,
78 | val,
79 | updateValue,
80 | dropdownOptions,
81 | disabled,
82 | }) => {
83 | let actualField;
84 | switch (type) {
85 | case 'dropdown':
86 | actualField = (
87 |
93 | );
94 | break;
95 | case 'textfield':
96 | actualField = (
97 |
102 | );
103 | break;
104 | case 'boolean':
105 | actualField = (
106 |
107 | );
108 | break;
109 | default:
110 | actualField = (
111 |
116 | );
117 | }
118 |
119 | return (
120 |
121 |
122 |
123 | {actualField}
124 |
125 | ☝🏽
126 | {' '}
127 | {description}
128 |
129 |
130 | );
131 | };
132 |
133 | const MethodCall = ({
134 | web3URL,
135 | web3Lib,
136 | currentMethod,
137 | codeSampleVisible,
138 | toggleSampleCode,
139 | description,
140 | disabled,
141 | args,
142 | runRequest,
143 | argumentList,
144 | onUpdateArguments,
145 | }) => {
146 | return (
147 |
148 |
149 | Method: {' '}
150 | {currentMethod}
151 |
152 |
153 |
{description}
154 | {args.length > 0 && (
155 |
156 | Possible Arguments
157 |
158 | )}
159 | {args.map((arg, i) => (
160 |
{
165 | onUpdateArguments(val, i);
166 | }}
167 | />
168 | ))}
169 |
170 |
178 |
183 |
188 |
189 | Send Request To Node
190 |
191 |
192 |
193 |
194 |
195 |
200 |
201 |
205 |
206 |
210 |
211 |
212 |
213 |
214 | {codeSampleVisible ? 'Hide' : 'View'} sample code
215 |
216 |
217 |
218 | );
219 | };
220 |
221 | export { MethodCall };
222 |
--------------------------------------------------------------------------------
/src/components/methodList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from '@reach/router';
3 | import { NeedLibMessage } from './needLibMessage';
4 | import Web3RpcCalls from '../helpers/web3Config';
5 |
6 | const MethodItem = ({ index, methodName, web3URL, web3Lib }) => {
7 | return (
8 |
9 |
13 |
14 |
15 |
16 | {methodName}
17 |
18 |
31 |
32 |
33 |
34 |
35 | );
36 | };
37 |
38 | const MethodList = ({ web3Lib, web3URL }) => {
39 | const methodList = Object.keys(Web3RpcCalls);
40 | if (!web3Lib) return ;
41 |
42 | return (
43 |
44 |
45 | Possible Methods
46 |
47 |
48 |
49 | {methodList.map((key, i) => (
50 |
57 | ))}
58 |
59 |
60 |
61 |
62 |
63 | );
64 | };
65 |
66 | export { MethodList };
67 |
--------------------------------------------------------------------------------
/src/components/navBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NavBar = ({ web3URL, setWeb3URL }) => {
4 | return (
5 |
6 |
7 |
8 |
9 |
EtherFlow
10 |
11 |
12 |
13 |
14 | Node URL
15 |
16 |
17 |
30 |
setWeb3URL(e.target.value)}
37 | />
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | );
47 | };
48 |
49 | export { NavBar };
50 |
--------------------------------------------------------------------------------
/src/components/needLibMessage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NeedLibMessage = () => {
4 | return (
5 |
6 |
7 | Please select a library{' '}
8 |
9 | ☝🏽
10 |
11 |
12 |
13 |
14 | Select a web3 library and this area will populate with a list of support
15 | RPC methods for you to choose from.
16 |
17 |
18 | );
19 | };
20 |
21 | export { NeedLibMessage };
22 |
--------------------------------------------------------------------------------
/src/components/needMethodMessage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NeedMethodMessage = () => {
4 | return (
5 |
6 |
7 | Please select a method from the list
8 |
9 |
10 |
11 | Select a method from the list on the left and this pane will populate
12 | with a description and potential arguments.
13 |
14 |
15 | );
16 | };
17 |
18 | export { NeedMethodMessage };
19 |
--------------------------------------------------------------------------------
/src/components/needURLMessage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NeedURLMessage = () => {
4 | return (
5 |
6 |
7 | Please ENTER a Web3 URL in the nav bar
8 |
9 |
10 |
11 | We need you to drop a Web3 URL in the input field at the top before we
12 | can do anything meaningful.
13 |
14 |
15 | );
16 | };
17 |
18 | export { NeedURLMessage };
19 |
--------------------------------------------------------------------------------
/src/components/sponsoredAd.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const SponsoredAd = ({ visible, setSponsorVisible }) => {
4 | const classes = `${
5 | visible ? '' : 'hidden'
6 | } fixed inset-0 flex items-end justify-center px-4 py-6 pointer-events-none sm:p-6 sm:items-start sm:justify-end`;
7 | /* eslint-disable react/jsx-no-target-blank */
8 |
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 |
21 |
22 |
23 |
24 | Sponsored by QuikNode
25 |
26 |
27 | Huge thanks to QuikNode for letting us build EtherFlow with{' '}
28 |
29 | ⚡️
30 | {' '}
31 | fast nodes.
32 |
33 |
45 |
46 |
47 |
setSponsorVisible(false)}
50 | >
51 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 | );
70 | };
71 |
72 | export { SponsoredAd };
73 |
--------------------------------------------------------------------------------
/src/components/statusBar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const StatusBar = ({ httpConnects, wssConnects, lastBlock, web3Version }) => {
4 | const nulls = [undefined, null];
5 | const httpColor = nulls.includes(httpConnects)
6 | ? 'gray'
7 | : httpConnects
8 | ? 'green'
9 | : 'red';
10 | const wssColor = nulls.includes(wssConnects)
11 | ? 'gray'
12 | : wssConnects
13 | ? 'green'
14 | : 'red';
15 |
16 | return (
17 |
62 | );
63 | };
64 |
65 | export { StatusBar };
66 |
--------------------------------------------------------------------------------
/src/components/web3Menu.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { MethodList } from './methodList';
3 |
4 | const Web3Menu = ({ web3URL, web3Lib, setWeb3Lib }) => {
5 | return (
6 |
7 |
8 |
9 | Web3 library
10 |
11 | setWeb3Lib(e.target.value)}
15 | >
16 |
17 | {' '}
18 | -- select an option --{' '}
19 |
20 | Web3.js
21 | Ethers.js
22 |
23 |
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | export { Web3Menu };
31 |
--------------------------------------------------------------------------------
/src/containers/codeSampleContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import { CodeSample } from '../components';
3 | import { AppContext } from '../context';
4 | import { useParams } from '@reach/router';
5 | import { getCodeSampleFriendlyArguments } from '../helpers/contracts';
6 |
7 | const TRACE_CALL = 'trace_call';
8 | const TRACE_ARGS_OFFSET = 4;
9 |
10 | const CodeSampleContainer = () => {
11 | const { codeSampleVisible, toggleSampleCode, abi } = useContext(AppContext);
12 | const params = useParams();
13 | const {
14 | web3URL = '',
15 | web3Lib = '',
16 | currentMethod = '',
17 | formArgs = '',
18 | } = params;
19 | const argumentList = formArgs.split('/');
20 | const hideCodeSample = () => {
21 | toggleSampleCode();
22 | };
23 |
24 | const argOffset = currentMethod === TRACE_CALL ? TRACE_ARGS_OFFSET : 0;
25 |
26 | return (
27 |
35 | );
36 | };
37 |
38 | export { CodeSampleContainer };
39 |
--------------------------------------------------------------------------------
/src/containers/index.js:
--------------------------------------------------------------------------------
1 | import { LogsContainer } from './logsContainer';
2 | import { CodeSampleContainer } from './codeSampleContainer';
3 | import { MethodCallContainer } from './methodCallContainer';
4 | import { SponsoredAdContainer } from './sponsoredAdContainer';
5 | import { StatusBarContainer } from './statusBarContainer';
6 | import { NavBarContainer } from './navBarContainer';
7 | import { Web3MenuContainer } from './web3MenuContainer';
8 |
9 | export {
10 | CodeSampleContainer,
11 | LogsContainer,
12 | MethodCallContainer,
13 | SponsoredAdContainer,
14 | StatusBarContainer,
15 | NavBarContainer,
16 | Web3MenuContainer,
17 | };
18 |
--------------------------------------------------------------------------------
/src/containers/logsContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useCallback } from 'react';
2 | import { Logs } from '../components';
3 | import { LogContext } from '../context';
4 | import { useParams } from '@reach/router';
5 |
6 | const LogsContainer = () => {
7 | const { logs, addToLog } = useContext(LogContext);
8 | const params = useParams();
9 | const web3URL = params.web3URL || null;
10 | const logItem = useCallback(addToLog, []);
11 | useEffect(() => {
12 | if (!web3URL) {
13 | logItem({
14 | method: 'info',
15 | data: ['⬆️ Please ENTER a Web3 URL in the nav bar'],
16 | });
17 | } else {
18 | logItem({
19 | method: 'info',
20 | data: ['⏳ Web3 URL detected...'],
21 | });
22 | }
23 | }, [logItem, web3URL]);
24 |
25 | return ;
26 | };
27 |
28 | export { LogsContainer };
29 |
--------------------------------------------------------------------------------
/src/containers/methodCallContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useCallback, useState, useEffect } from 'react';
2 | import { NeedMethodMessage, NeedURLMessage, MethodCall } from '../components';
3 | import { AppContext, LogContext } from '../context';
4 | import Web3RpcCalls from '../helpers/web3Config';
5 | import buildProvider from '../helpers/buildProvider';
6 | import {
7 | fetchOrParseAbi,
8 | getFilteredMethods,
9 | getContractFriendlyArguments,
10 | getFormInputsFromMethod,
11 | onUpdateAbi,
12 | } from '../helpers/contracts';
13 | import { navigate, useParams } from '@reach/router';
14 |
15 | const ETH_CALL = 'eth_call';
16 | const TRACE_CALL = 'trace_call';
17 | const TRACE_ARGS_OFFSET = 4;
18 |
19 | const MethodCallContainer = () => {
20 | const params = useParams();
21 | const { codeSampleVisible, toggleSampleCode, abi, setAbi } = useContext(
22 | AppContext
23 | );
24 | const { addToLog } = useContext(LogContext);
25 | const logItem = useCallback(addToLog, []);
26 |
27 | const {
28 | web3URL = '',
29 | web3Lib = '',
30 | currentMethod = '',
31 | formArgs = '',
32 | } = params;
33 |
34 | const web3Method = Web3RpcCalls[currentMethod] || {};
35 | const { description, disabled } = web3Method || {};
36 | const { args: initialFormInputs, exec } = web3Method[web3Lib] || {};
37 |
38 | const [formInputs, setFormInputs] = useState([]);
39 | const [argumentList, setArgumentList] = useState([]);
40 |
41 | // Logic when using contract method (eth_call, trace_call)
42 | const isContractMethod = [ETH_CALL, TRACE_CALL].includes(currentMethod);
43 | const argOffset = currentMethod === TRACE_CALL ? TRACE_ARGS_OFFSET : 0;
44 | const isWriteAllowed = argOffset > 0;
45 |
46 | const updateURL = (val, index) => {
47 | let argsList = formArgs.split('/').slice(0, formInputs.length); // Remove dangling arguments
48 | argsList[index] = val;
49 | let joinedArgs = argsList.join('/');
50 | let url = `/${web3URL}/${web3Lib}/`;
51 | if (currentMethod) url += `${currentMethod}/`;
52 | if (formInputs.length > 0) url += `${joinedArgs}`;
53 | navigate(url);
54 | };
55 |
56 | const onUpdateArguments = async (val, index) => {
57 | if (isContractMethod && index === 1 + argOffset) {
58 | // Prevent updating URL if ABI error
59 | const { error } = await fetchOrParseAbi(val, isWriteAllowed);
60 | if (error)
61 | return logItem({
62 | method: 'error',
63 | data: ['🚨 Error:', error],
64 | });
65 | return updateURL(btoa(val), index);
66 | }
67 | updateURL(val, index);
68 | };
69 |
70 | const runRequest = () => {
71 | logItem({
72 | method: 'info',
73 | data: [`🚀 Sending request for **${currentMethod}**:`],
74 | });
75 | const [provider, proto] = buildProvider(web3Lib, atob(web3URL));
76 | let args = argumentList.slice();
77 | // Pre-flight conversion for contract calls
78 | if (isContractMethod)
79 | args = getContractFriendlyArguments(args, abi, argOffset);
80 | exec(provider, proto, ...args)
81 | .then((response) => {
82 | logItem({
83 | method: 'info',
84 | data: [`✅ Node response:`, response],
85 | });
86 | })
87 | .catch((err) => {
88 | logItem({
89 | method: 'error',
90 | data: ['🚨 Error response:', err],
91 | });
92 | });
93 | };
94 |
95 | const loadURL = async () => {
96 | const list = formArgs.split('/');
97 | if (isContractMethod && list[1 + argOffset]) {
98 | // Load ABI
99 | try {
100 | list[1 + argOffset] = atob(list[1 + argOffset]);
101 | const { error, abi } = await fetchOrParseAbi(
102 | list[1 + argOffset],
103 | isWriteAllowed
104 | );
105 | if (error)
106 | return logItem({
107 | method: 'error',
108 | data: ['🚨 Error:', error],
109 | });
110 | setAbi(abi);
111 | } catch (e) {
112 | console.log(e);
113 | }
114 | }
115 | setArgumentList(list);
116 | };
117 |
118 | // Load URL arguments
119 | useEffect(() => {
120 | loadURL();
121 | }, [formArgs, currentMethod, formInputs]);
122 |
123 | useEffect(() => {
124 | if (!abi) return;
125 | const { newFormInputs, newUrl } = onUpdateAbi(abi, formInputs, argOffset);
126 | setFormInputs(newFormInputs);
127 | if (newUrl) updateURL(newUrl, 2 + argOffset);
128 | }, [abi, formInputs]);
129 |
130 | // Update the form inputs whenever a new contract method is selected
131 | useEffect(() => {
132 | if (!argumentList) return;
133 | const methodId = argumentList[2 + argOffset];
134 | if (!methodId || !abi) return;
135 | setFormInputs(
136 | getFormInputsFromMethod(abi, methodId, formInputs, argOffset)
137 | );
138 | }, [argumentList[2 + argOffset]]);
139 |
140 | useEffect(() => {
141 | if (!initialFormInputs) return;
142 | setFormInputs(initialFormInputs);
143 | }, [initialFormInputs]);
144 |
145 | const contextProps = {
146 | codeSampleVisible,
147 | toggleSampleCode,
148 | currentMethod,
149 | web3Lib,
150 | web3URL,
151 | description,
152 | disabled,
153 | args: formInputs,
154 | runRequest,
155 | onUpdateArguments,
156 | argumentList,
157 | };
158 |
159 | if (!web3URL) {
160 | return (
161 |
162 |
163 |
164 | );
165 | }
166 | if (!currentMethod) {
167 | return (
168 |
169 |
170 |
171 | );
172 | }
173 |
174 | return ;
175 | };
176 |
177 | export { MethodCallContainer };
178 |
--------------------------------------------------------------------------------
/src/containers/navBarContainer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NavBar } from '../components';
3 | import { navigate, useParams } from '@reach/router';
4 |
5 | const NavBarContainer = () => {
6 | const params = useParams();
7 | const web3URL = atob(params.web3URL || '');
8 | const setWeb3URL = (url) => {
9 | const b64url = btoa(url);
10 | navigate(`/${b64url}`);
11 | };
12 |
13 | return ;
14 | };
15 |
16 | export { NavBarContainer };
17 |
--------------------------------------------------------------------------------
/src/containers/sponsoredAdContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { SponsoredAd } from '../components';
3 |
4 | const SponsoredAdContainer = () => {
5 | // should we be showing the sponsor?
6 | const [sponsorVisible, setSponsorVisible] = useState(false);
7 | useEffect(() => {
8 | let to = setTimeout(() => {
9 | setSponsorVisible(true);
10 | }, 130000);
11 |
12 | return () => {
13 | clearTimeout(to);
14 | };
15 | }, []);
16 |
17 | return (
18 |
22 | );
23 | };
24 |
25 | export { SponsoredAdContainer };
26 |
--------------------------------------------------------------------------------
/src/containers/statusBarContainer.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react';
2 | import { StatusBar } from '../components';
3 | import { useParams } from '@reach/router';
4 | import web3State from '../helpers/web3State';
5 |
6 | const StatusBarContainer = () => {
7 | const params = useParams();
8 | const web3URL = params.web3URL || '';
9 | const [statusInfo, setStatusInfo] = useState({});
10 | useEffect(() => {
11 | let isMounted = true;
12 | web3State(atob(web3URL)).then((data) => {
13 | if (isMounted) setStatusInfo(data);
14 | });
15 | return () => {
16 | isMounted = false;
17 | };
18 | }, [web3URL]);
19 |
20 | return ;
21 | };
22 |
23 | export { StatusBarContainer };
24 |
--------------------------------------------------------------------------------
/src/containers/web3MenuContainer.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NeedURLMessage, Web3Menu } from '../components';
3 | import { navigate, useParams } from '@reach/router';
4 |
5 | const Web3MenuContainer = () => {
6 | const params = useParams();
7 | const { web3URL = '', web3Lib = '' } = params;
8 | const setWeb3Lib = (libName) => {
9 | navigate(`/${web3URL}/${libName}`);
10 | };
11 | const props = {
12 | web3URL: web3URL,
13 | web3Lib,
14 | setWeb3Lib,
15 | };
16 |
17 | if (!web3URL)
18 | return (
19 |
20 |
21 |
22 | );
23 |
24 | return ;
25 | };
26 |
27 | export { Web3MenuContainer };
28 |
--------------------------------------------------------------------------------
/src/context/appProvider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useCallback, useState } from 'react';
2 |
3 | const AppContext = createContext({});
4 |
5 | const AppProvider = ({ children }) => {
6 | // should we be showing the code sample?
7 | const [codeSampleVisible, setCodeSampleVisible] = useState(false);
8 | const toggleSampleCode = useCallback(() => {
9 | setCodeSampleVisible(!codeSampleVisible);
10 | }, [codeSampleVisible]);
11 | const [abi, setAbi] = useState(null);
12 |
13 | return (
14 |
22 | {children}
23 |
24 | );
25 | };
26 |
27 | export { AppContext, AppProvider };
28 |
--------------------------------------------------------------------------------
/src/context/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { AppContext, AppProvider } from './appProvider';
3 | import { LogContext, LogProvider } from './logProvider';
4 | import { Web3Context, Web3Provider } from './web3Provider';
5 |
6 | const WrappedProvider = ({ children }) => {
7 | return (
8 |
9 |
10 | {children}
11 |
12 |
13 | );
14 | };
15 |
16 | export { WrappedProvider as AppProvider, AppContext, LogContext, Web3Context };
17 |
--------------------------------------------------------------------------------
/src/context/logProvider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useEffect, useState } from 'react';
2 | import { Hook, Unhook } from 'console-feed';
3 |
4 | const LogContext = createContext({});
5 |
6 | const LogProvider = ({ children }) => {
7 | // logs
8 | const [logs, setLogs] = useState([]);
9 | const addToLog = (log) => setLogs((currLogs) => [...currLogs, log]);
10 | // bundle it up for use
11 | const contextObject = {
12 | logs,
13 | addToLog,
14 | };
15 |
16 | // run once!
17 | useEffect(() => {
18 | Hook(
19 | window.console,
20 | (log) => setLogs((currLogs) => [...currLogs, log]),
21 | false
22 | );
23 |
24 | return () => Unhook(window.console);
25 | }, []);
26 |
27 | return (
28 | {children}
29 | );
30 | };
31 |
32 | export { LogContext, LogProvider };
33 |
--------------------------------------------------------------------------------
/src/context/web3Provider.js:
--------------------------------------------------------------------------------
1 | import React, { createContext, useState } from 'react';
2 | // import ethers from 'ethers';
3 |
4 | const Web3Context = createContext({});
5 |
6 | const Web3Provider = ({ children }) => {
7 | const [providerObject, setProviderObject] = useState(null);
8 | // bundle it up for use
9 | const web3ContextObject = {
10 | providerObject,
11 | setProviderObject,
12 | };
13 |
14 | return (
15 |
16 | {children}
17 |
18 | );
19 | };
20 |
21 | export { Web3Context, Web3Provider };
22 |
--------------------------------------------------------------------------------
/src/helpers/buildProvider.js:
--------------------------------------------------------------------------------
1 | import { ethers } from 'ethers';
2 | import Web3 from 'web3';
3 |
4 | export default (web3Lib, web3URL) => {
5 | let provider;
6 | const proto = web3URL.startsWith('wss') ? 'wss' : 'https';
7 | if (web3Lib === 'ethers') {
8 | provider =
9 | proto === 'wss'
10 | ? new ethers.providers.WebSocketProvider(web3URL)
11 | : new ethers.providers.JsonRpcProvider(web3URL);
12 | } else if (web3Lib === 'web3') {
13 | provider = new Web3(web3URL);
14 | }
15 |
16 | return [provider, proto];
17 | };
18 |
--------------------------------------------------------------------------------
/src/helpers/contracts.js:
--------------------------------------------------------------------------------
1 | const ERROR_MESSAGE_NO_ABI = 'No ABI provided';
2 | const ERROR_MESSAGE_PARSE_ABI =
3 | 'Error parsing ABI. Please ensure valid JSON format. Example: [{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]';
4 | const ERROR_MESSAGE_ABI_TOO_LONG = 'Please only pass one function object.';
5 | const ERROR_MESSAGE_ABI_NO_READ_FUNCTIONS =
6 | 'The ABI does not contain any READ functions.';
7 | const ERROR_MESSAGE_FETCH = 'Error fetching ABI. CORS header may not be set.';
8 |
9 | const getMethodDisplayName = ({ name, inputs }) => {
10 | // Convert a function entity to a human-friendly string
11 | const inputTypesText = inputs.map((input, index) => input.type);
12 | return `${name}${inputs.length > 0 ? ` (${inputTypesText})` : ''}`;
13 | };
14 |
15 | const getMethodId = ({ name, inputs }) => {
16 | // Convert a function to a unique ID
17 | const inputTypesText = inputs.map((input, index) => input.type);
18 | return `${name}${inputs.length > 0 ? `-${inputTypesText}` : ''}`;
19 | };
20 |
21 | const getFragmentFromMethodId = (abi, methodId) => {
22 | const [methodName, argTypes] = methodId.split('-');
23 | const typesList = argTypes ? argTypes.split(',') : [];
24 | if (abi.length === 1) return abi[0];
25 | return abi.find((element) => {
26 | if (element.name !== methodName) return false;
27 | const inputTypes = element.inputs.map((input) => input.type);
28 | return (
29 | inputTypes.length === typesList.length &&
30 | inputTypes.every((value, i) => value === typesList[i])
31 | );
32 | });
33 | };
34 |
35 | const PLACEHOLDER_BASE_TYPE = {
36 | int: '255',
37 | bool: 'true',
38 | address: '0x261b45d85ccfeabb11f022eba346ee8d1cd488c0',
39 | string: 'example text',
40 | byte: '01',
41 | };
42 |
43 | export const getArgumentsFromMethodId = (abi, methodId) => {
44 | /* eslint-disable-next-line no-unused-vars*/
45 | const [_, rawArgs] = methodId.split('-');
46 | if (!rawArgs) return;
47 | const args = rawArgs.split(',');
48 | const abiFragment = getFragmentFromMethodId(abi, methodId);
49 | return args.map((arg, index) => {
50 | const baseType = arg
51 | .replace(/(uint|int)[0-9]*/, 'int')
52 | .replace(/(byte|bytes)[0-9]*/, 'byte')
53 | .replace(/\[\]/, '');
54 | let placeholder = PLACEHOLDER_BASE_TYPE[baseType];
55 | const isArray = /\[\]/.test(arg);
56 | if (isArray) placeholder = `${placeholder}, ${placeholder}`;
57 | return {
58 | type: isArray ? 'textarea' : 'textfield',
59 | description: abiFragment.inputs[index].name || arg,
60 | placeholder: `i.e. ${placeholder}`,
61 | };
62 | });
63 | };
64 |
65 | const isValidUrl = (string) => {
66 | try {
67 | new URL(string);
68 | } catch (e) {
69 | return false;
70 | }
71 | return true;
72 | };
73 |
74 | export const getFilteredMethods = (abi, isWriteAllowed) => {
75 | try {
76 | return abi
77 | .filter((method) => isWriteAllowed || method.stateMutability === 'view')
78 | .map((method) => ({
79 | value: getMethodId(method),
80 | name: getMethodDisplayName(method),
81 | }));
82 | } catch (e) {
83 | console.log(e);
84 | return [];
85 | }
86 | };
87 |
88 | export const fetchOrParseAbi = async (abiVal, isWriteAllowed) => {
89 | if (!abiVal) return { error: ERROR_MESSAGE_NO_ABI };
90 | try {
91 | let abi = abiVal;
92 | if (isValidUrl(abiVal)) {
93 | let response = null;
94 | try {
95 | response = await fetch(abiVal);
96 | } catch (e) {
97 | return { error: ERROR_MESSAGE_FETCH };
98 | }
99 | const json = await response.json();
100 | if (Array.isArray(json)) abi = json;
101 | else abi = json.abi;
102 | }
103 | if (typeof abi !== 'object') abi = JSON.parse(abiVal);
104 | if (!isValidUrl(abiVal) && abi.length > 1)
105 | return { error: ERROR_MESSAGE_ABI_TOO_LONG };
106 | // Handle edge case when single function entity is passed
107 | if (!abi.length) abi = [abi];
108 | const filteredMethods = getFilteredMethods(abi, isWriteAllowed);
109 | if (filteredMethods.length === 0)
110 | return { error: ERROR_MESSAGE_ABI_NO_READ_FUNCTIONS };
111 | return { abi };
112 | } catch (e) {
113 | console.log(e);
114 | return { error: ERROR_MESSAGE_PARSE_ABI };
115 | }
116 | };
117 |
118 | export const formatContractArgs = (args, types) => {
119 | if (!args || !types) return null;
120 | return args.map((arg) => {
121 | if (/,/.test(arg)) {
122 | // Array value
123 |
124 | return arg.split(',');
125 | }
126 | return `${arg}`;
127 | });
128 | };
129 |
130 | export const getContractFriendlyArguments = (argumentList, abi, argOffset) => {
131 | /* eslint-disable-next-line no-unused-vars*/
132 | let list = argumentList;
133 | const traceArgs = list.splice(0, argOffset); // remove trace arguments (if any)
134 | let [address, _, methodId, ...methodSpecificArgs] = list;
135 | if (!methodId || !abi) return list;
136 | const [methodName, argTypes] = methodId.split('-');
137 | const typesList = argTypes ? argTypes.split(',') : [];
138 | // Pick out the relevant function fragment
139 | const abiFragment = [getFragmentFromMethodId(abi, methodId)];
140 | let args = [address, JSON.stringify(abiFragment), methodName];
141 | if (argTypes) args.push(...formatContractArgs(methodSpecificArgs, typesList));
142 | return traceArgs.concat(args); // add back trace arguments
143 | };
144 |
145 | export const getCodeSampleFriendlyArguments = (
146 | argumentList,
147 | abi,
148 | argOffset
149 | ) => {
150 | let list = argumentList;
151 | const traceArgs = list.splice(0, argOffset); // remove trace arguments (if any)
152 | const [
153 | contract,
154 | cleanAbi,
155 | methodId,
156 | ...methodSpecificArgs
157 | ] = getContractFriendlyArguments(list, abi);
158 | let abiObj = cleanAbi;
159 | try {
160 | abiObj = JSON.parse(cleanAbi);
161 | } catch (e) {
162 | // do nothing
163 | }
164 | let codeFriendlyArguments = [
165 | contract,
166 | abiObj,
167 | methodId,
168 | JSON.stringify(methodSpecificArgs).replace(/^\[/, '').replace(/\]$/, ''),
169 | ];
170 | if (traceArgs) codeFriendlyArguments.splice(0, 0, ...traceArgs);
171 | return codeFriendlyArguments;
172 | };
173 |
174 | export const getFormInputsFromMethod = (
175 | abi,
176 | methodId,
177 | formInputs,
178 | argOffset
179 | ) => {
180 | const newFormInputs = getArgumentsFromMethodId(abi, methodId);
181 | if (newFormInputs)
182 | return [
183 | ...formInputs.slice(0, 3 + argOffset), // Discard existing method-specific inputs
184 | ...newFormInputs,
185 | ];
186 | else return [...formInputs.slice(0, 3 + argOffset)];
187 | };
188 |
189 | export const onUpdateAbi = (abi, formInputs, argOffset) => {
190 | const isWriteAllowed = argOffset > 0;
191 | const filteredMethods = getFilteredMethods(abi, isWriteAllowed);
192 | const formInputsCopy = formInputs;
193 | formInputsCopy[2 + argOffset] = {
194 | ...formInputs[2 + argOffset],
195 | dropdownOptions: filteredMethods,
196 | disabled: abi.length === 1,
197 | };
198 | let newUrl = null;
199 | if (abi.length === 1) newUrl = filteredMethods[0].value;
200 | return { newFormInputs: formInputsCopy, newUrl };
201 | };
202 |
--------------------------------------------------------------------------------
/src/helpers/libs/curl.js:
--------------------------------------------------------------------------------
1 | const CURL = {};
2 |
3 | export default CURL;
4 |
--------------------------------------------------------------------------------
/src/helpers/libs/ethers.js:
--------------------------------------------------------------------------------
1 | import { ethers, BigNumber } from 'ethers';
2 |
3 | const ethersTemplate = (methodCall, varName, url) => {
4 | return `const ethers = require("ethers");
5 | // OR import ethers from 'ethers';
6 |
7 | // HTTP version
8 | (async () => {
9 | const provider = new ethers.providers.JsonRpcProvider('${url}');
10 | const ${varName} = await provider.${methodCall};
11 | console.log(${varName});
12 | })();
13 |
14 |
15 | // WebSocket version
16 | (async () => {
17 | const provider = new ethers.providers.WebSocketProvider('${url}');
18 | const ${varName} = await provider.${methodCall};
19 | console.log(${varName});
20 | })();
21 | `;
22 | };
23 |
24 | // TODO: Add Websocket example?
25 | const contractTemplate = (url, args) => {
26 | const [address, abi, method, methodArgumentsString] = args;
27 | return `const ethers = require("ethers");
28 | // OR import ethers from 'ethers';
29 |
30 | // HTTP version
31 | (async () => {
32 | const abi = ${abi && JSON.stringify(abi)}
33 | const provider = new ethers.providers.JsonRpcProvider('${url}');
34 | const contract = new ethers.Contract('${address}', abi, provider);
35 | const response = await contract.functions.${method}(${methodArgumentsString});
36 | console.log(response);
37 | })()
38 | `;
39 | };
40 |
41 | const contractTraceTemplate = (url, args) => {
42 | const [
43 | traceTypeList,
44 | block,
45 | from,
46 | value,
47 | contract,
48 | abi,
49 | method,
50 | methodArgumentsString,
51 | ] = args;
52 | return `const ethers = require("ethers");
53 | // OR import ethers from 'ethers';
54 |
55 | // HTTP version
56 | (async () => {
57 | const abi = ${abi && JSON.stringify(abi)}
58 | const provider = new ethers.providers.JsonRpcProvider('${url}');
59 | const iface = new ethers.utils.Interface(abi);
60 | const data = iface.encodeFunctionData("${method}"${
61 | methodArgumentsString ? ` , [${methodArgumentsString}]` : ''
62 | }); ${from ? `\n const from = "${from}";` : ''}
63 | const to = "${contract}"; ${value ? `\n const value = "${value}";` : ''}
64 | const transaction = { ${from ? `\n from,` : ''}
65 | to,${value ? `\n value,` : ''}
66 | data,
67 | };
68 | const response = await provider.send('trace_call', [transaction, ${traceTypeList}, ${block}]);
69 | console.log(response);
70 | })();
71 | `;
72 | };
73 |
74 | const filterTemplate = (url, filterMethod, filter) => {
75 | return `const ethers = require("ethers");
76 | // OR import ethers from 'ethers';
77 | ${filter ? `\n${filter}\n` : ''}
78 | // HTTP version
79 | (async () => {
80 | const provider = new ethers.providers.JsonRpcProvider('${url}');
81 | const filterId = await provider.send('${filterMethod}'${
82 | filter ? ', [filter]' : ''
83 | })
84 | console.log(filterId);
85 | const logs = await provider.send('eth_getFilterChanges', [filterId]);
86 | console.log(logs);
87 | })();
88 |
89 | // WebSocket version
90 | (async () => {
91 | const provider = new ethers.providers.WebSocketProvider('${url}');
92 | const filterId = await provider.send('${filterMethod}'${
93 | filter ? ', [filter]' : ''
94 | })
95 | console.log(filterId);
96 | const logs = await provider.send('eth_getFilterChanges', [filterId]);
97 | console.log(logs);
98 | })();
99 | `;
100 | };
101 |
102 | const EthersCalls = {
103 | web3_clientVersion: {
104 | exec: (provider, proto, ...args) => {
105 | return provider.send('web3_clientVersion');
106 | },
107 | codeSample: (url, ...args) => {
108 | return ethersTemplate("send('web3_clientVersion')", 'version', url);
109 | },
110 | args: [],
111 | },
112 | web3_sha3: {
113 | exec: (provider, proto, ...args) => {
114 | return provider.send('web3_sha3', [args[0]]);
115 | },
116 | codeSample: (url, ...args) => {
117 | return ethersTemplate(`send('web3_sha3', ['${args[0]}'])`, 'hash', url);
118 | },
119 | args: [
120 | {
121 | type: 'textarea',
122 | description: 'The hexified data to convert into a SHA3 hash',
123 | placeholder: 'i.e. 0x68656c6c6f20776f726c64',
124 | },
125 | ],
126 | },
127 | net_version: {
128 | exec: (provider, proto, ...args) => {
129 | return provider.send('net_version');
130 | },
131 | codeSample: (url, ...args) => {
132 | return ethersTemplate(`send('net_version')`, 'network', url);
133 | },
134 | args: [],
135 | },
136 | net_listening: {
137 | exec: (provider, proto, ...args) => {
138 | return provider.send('net_listening');
139 | },
140 | codeSample: (url, ...args) => {
141 | return ethersTemplate("send('net_listening')", 'listening', url);
142 | },
143 | args: [],
144 | },
145 | net_peerCount: {
146 | exec: (provider, proto, ...args) => {
147 | return provider.send('net_peerCount');
148 | },
149 | codeSample: (url, ...args) => {
150 | return ethersTemplate("send('net_peerCount')", 'peers', url);
151 | },
152 | args: [],
153 | },
154 | eth_protocolVersion: {
155 | exec: (provider, proto, ...args) => {
156 | return provider.send('eth_protocolVersion');
157 | },
158 | codeSample: (url, ...args) => {
159 | return ethersTemplate("send('eth_protocolVersion')", 'version', url);
160 | },
161 | args: [],
162 | },
163 | eth_syncing: {
164 | exec: (provider, proto, ...args) => {
165 | return provider.send('eth_syncing');
166 | },
167 | codeSample: (url, ...args) => {
168 | return ethersTemplate("send('eth_syncing')", 'isSyncing', url);
169 | },
170 | args: [],
171 | },
172 | eth_coinbase: {
173 | exec: (provider, proto, ...args) => {
174 | return provider.send('eth_coinbase');
175 | },
176 | codeSample: (url, ...args) => {
177 | return ethersTemplate("send('eth_coinbase')", 'coinbase', url);
178 | },
179 | args: [],
180 | },
181 | eth_mining: {
182 | exec: (provider, proto, ...args) => {
183 | return provider.send('eth_mining');
184 | },
185 | codeSample: (url, ...args) => {
186 | return ethersTemplate("send('eth_mining')", 'isMining', url);
187 | },
188 | args: [],
189 | },
190 | eth_hashrate: {
191 | exec: (provider, proto, ...args) => {
192 | return provider.send('eth_hashrate');
193 | },
194 | codeSample: (url, ...args) => {
195 | return ethersTemplate("send('eth_hashrate')", 'hashRate', url);
196 | },
197 | args: [],
198 | },
199 | eth_gasPrice: {
200 | exec: (provider, proto, ...args) => {
201 | return provider.getGasPrice().then(resp => BigNumber.from(resp._hex).toString());
202 | },
203 | codeSample: (url, ...args) => {
204 | return ethersTemplate('getGasPrice()', 'gasPrice', url);
205 | },
206 | args: [],
207 | },
208 | eth_accounts: {
209 | exec: (provider, proto, ...args) => {
210 | return provider.send('eth_accounts');
211 | },
212 | codeSample: (url, ...args) => {
213 | return ethersTemplate("send('eth_accounts')", 'accts', url);
214 | },
215 | args: [],
216 | },
217 | eth_blockNumber: {
218 | exec: (provider, proto, ...args) => {
219 | return provider.getBlockNumber();
220 | },
221 | codeSample: (url, ...args) => {
222 | return ethersTemplate('getBlockNumber()', 'blockNum', url);
223 | },
224 | args: [],
225 | },
226 | eth_getBalance: {
227 | exec: (provider, proto, ...args) => {
228 | return provider.getBalance(...args).then(resp => BigNumber.from(resp._hex).toString());
229 | },
230 | codeSample: (url, ...args) => {
231 | return ethersTemplate(
232 | `getBalance('${args[0]}', '${args[1]}')`,
233 | 'balance',
234 | url
235 | );
236 | },
237 | args: [
238 | {
239 | type: 'textarea',
240 | description: 'Address to check for balance',
241 | placeholder: 'i.e. 0x91b51c173a4...',
242 | },
243 | {
244 | type: 'textfield',
245 | description:
246 | 'Hex block number, or the string "latest", "earliest" or "pending"',
247 | placeholder: 'i.e. latest or pending',
248 | },
249 | ],
250 | },
251 | eth_getStorageAt: {
252 | exec: (provider, proto, ...args) => {
253 | return provider.getStorageAt(...args);
254 | },
255 | codeSample: (url, ...args) => {
256 | return ethersTemplate(
257 | `getStorageAt('${args[0]}', '${args[1]}', '${args[2]}')`,
258 | 'storage',
259 | url
260 | );
261 | },
262 | args: [
263 | {
264 | type: 'textarea',
265 | description: 'Address of the storage',
266 | placeholder: 'i.e. 0x91b51c173a4... or ENS domain',
267 | },
268 | {
269 | type: 'textfield',
270 | description: 'Hex of the position in the storage',
271 | placeholder: 'i.e. 0x0, 0x1, 0x2...',
272 | },
273 | {
274 | type: 'textfield',
275 | description:
276 | 'Hex block number, or the string "latest", "earliest" or "pending"',
277 | placeholder: 'i.e. latest or pending',
278 | },
279 | ],
280 | },
281 | eth_getTransactionCount: {
282 | exec: (provider, proto, ...args) => {
283 | return provider.getTransactionCount(...args);
284 | },
285 | codeSample: (url, ...args) => {
286 | return ethersTemplate(
287 | `getTransactionCount('${args[0]}', '${args[1]}')`,
288 | 'txCount',
289 | url
290 | );
291 | },
292 | args: [
293 | {
294 | type: 'textarea',
295 | description: 'Address to check for balance',
296 | placeholder: 'i.e. 0x91b51c173a4...',
297 | },
298 | {
299 | type: 'textfield',
300 | description:
301 | 'Hex block number, or the string "latest", "earliest" or "pending"',
302 | placeholder: 'i.e. latest or pending',
303 | },
304 | ],
305 | },
306 | eth_getBlockTransactionCountByHash: {
307 | exec: (provider, proto, ...args) => {
308 | return provider.send('eth_getBlockTransactionCountByHash', [args[0]]);
309 | },
310 | codeSample: (url, ...args) => {
311 | return ethersTemplate(
312 | `send('eth_getBlockTransactionCountByHash', ['${args[0]}'])`,
313 | 'txCount',
314 | url
315 | );
316 | },
317 | args: [
318 | {
319 | type: 'textarea',
320 | description: 'Hash of a block to get transaction count from',
321 | placeholder: 'i.e. 0x16c4e370736...',
322 | },
323 | ],
324 | },
325 | eth_getBlockTransactionCountByNumber: {
326 | exec: (provider, proto, ...args) => {
327 | return provider.send('eth_getBlockTransactionCountByNumber', [args[0]]);
328 | },
329 | codeSample: (url, ...args) => {
330 | return ethersTemplate(
331 | `send('eth_getBlockTransactionCountByNumber', ['${args[0]}'])`,
332 | 'txCount',
333 | url
334 | );
335 | },
336 | args: [
337 | {
338 | type: 'textarea',
339 | description: 'Hex of a block to get transaction count from',
340 | placeholder: 'i.e. 0x9C6EFE',
341 | },
342 | ],
343 | },
344 | eth_getUncleCountByBlockHash: {
345 | exec: (provider, proto, ...args) => {
346 | return provider.send('eth_getUncleCountByBlockHash', [args[0]]);
347 | },
348 | codeSample: (url, ...args) => {
349 | return ethersTemplate(
350 | `send('eth_getUncleCountByBlockHash', ['${args[0]}'])`,
351 | 'uncleCount',
352 | url
353 | );
354 | },
355 | args: [
356 | {
357 | type: 'textarea',
358 | description: 'Hash of a block to get uncle count from',
359 | placeholder: 'i.e. 0x16c4e370736...',
360 | },
361 | ],
362 | },
363 | eth_getUncleCountByBlockNumber: {
364 | exec: (provider, proto, ...args) => {
365 | return provider.send('eth_getUncleCountByBlockNumber', [args[0]]);
366 | },
367 | codeSample: (url, ...args) => {
368 | return ethersTemplate(
369 | `send('eth_getUncleCountByBlockNumber', ['${args[0]}'])`,
370 | 'uncleCount',
371 | url
372 | );
373 | },
374 | args: [
375 | {
376 | type: 'textarea',
377 | description: 'Hex of a block to get uncle count from',
378 | placeholder: 'i.e. 0x9C6EFE',
379 | },
380 | ],
381 | },
382 | eth_getCode: {
383 | exec: (provider, proto, ...args) => {
384 | return provider.getCode(...args);
385 | },
386 | codeSample: (url, ...args) => {
387 | return ethersTemplate(`getCode('${args[0]}', '${args[1]}')`, 'code', url);
388 | },
389 | args: [
390 | {
391 | type: 'textarea',
392 | description: 'Address to fetch code from',
393 | placeholder: 'i.e. 0x91b51c173a4...',
394 | },
395 | {
396 | type: 'textfield',
397 | description:
398 | 'Hex block number, or the string "latest", "earliest" or "pending"',
399 | placeholder: 'i.e. latest or pending',
400 | },
401 | ],
402 | },
403 | eth_sign: {
404 | exec: (provider, proto, ...args) => {
405 | return new Promise((resolve, reject) =>
406 | reject('EtherFlow does not support this method.')
407 | );
408 | },
409 | codeSample: (url, ...args) => {
410 | return '/* Not Supported by EtherFlow */';
411 | },
412 | args: [],
413 | },
414 | eth_signTransaction: {
415 | exec: (provider, proto, ...args) => {
416 | return new Promise((resolve, reject) =>
417 | reject('EtherFlow does not support this method.')
418 | );
419 | },
420 | codeSample: (url, ...args) => {
421 | return '/* Not Supported by EtherFlow */';
422 | },
423 | args: [],
424 | },
425 | eth_sendTransaction: {
426 | exec: (provider, proto, ...args) => {
427 | return new Promise((resolve, reject) =>
428 | reject('EtherFlow does not support this method.')
429 | );
430 | },
431 | codeSample: (url, ...args) => {
432 | return '/* Not Supported by EtherFlow */';
433 | },
434 | args: [],
435 | },
436 | eth_sendRawTransaction: {
437 | exec: (provider, proto, ...args) => {
438 | return provider.sendTransaction(...args);
439 | },
440 | codeSample: (url, ...args) => {
441 | return ethersTemplate(`sendTransaction('${args[0]}')`, 'tx', url);
442 | },
443 | args: [
444 | {
445 | type: 'textarea',
446 | description: 'The previously signed transaction data',
447 | placeholder:
448 | 'i.e. 0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
449 | },
450 | ],
451 | },
452 | eth_call: {
453 | exec: (provider, proto, ...args) => {
454 | const [address, abi, method, ...rest] = args;
455 | const contract = new ethers.Contract(address, abi, provider);
456 | return contract.functions[method](...rest);
457 | },
458 | codeSample: (url, ...args) => {
459 | return contractTemplate(url, args);
460 | },
461 | args: [
462 | {
463 | type: 'textarea',
464 | description: 'Address of contract',
465 | placeholder: 'i.e. 0x91b51c173a4...',
466 | },
467 | {
468 | type: 'textarea',
469 | description: 'Contract ABI (URL or single function object)',
470 | placeholder:
471 | 'i.e. [{"inputs":[{"name":"chainId...\nOR\nhttps://raw.githubusercontent.com/.../build/contracts/ERC20.json',
472 | },
473 | {
474 | type: 'dropdown',
475 | description: 'Function name (READ only)',
476 | },
477 | ],
478 | },
479 | eth_estimateGas: {
480 | exec: (provider, proto, ...args) => {
481 | return new Promise((resolve, reject) =>
482 | reject('EtherFlow does not support this method.')
483 | );
484 | },
485 | codeSample: (url, ...args) => {
486 | return '/* Not Supported by EtherFlow */';
487 | },
488 | args: [],
489 | },
490 | eth_getBlockByHash: {
491 | exec: (provider, proto, ...args) => {
492 | if (args[1] === 'true') {
493 | return provider.getBlockWithTransactions(args[0]);
494 | } else {
495 | return provider.getBlock(args[0]);
496 | }
497 | },
498 | codeSample: (url, ...args) => {
499 | if (args[1] === 'true') {
500 | return ethersTemplate(
501 | `getBlockWithTransactions('${args[0]}')`,
502 | 'blockData',
503 | url
504 | );
505 | } else {
506 | return ethersTemplate(`getBlock('${args[0]}')`, 'blockData', url);
507 | }
508 | },
509 | args: [
510 | {
511 | type: 'textarea',
512 | description: 'Hash of a block to get information from',
513 | placeholder: 'i.e. 0x16c4e370736...',
514 | },
515 | {
516 | type: 'boolean',
517 | description: 'Should we return full transaction objects?',
518 | placeholder: '',
519 | },
520 | ],
521 | },
522 | eth_getBlockByNumber: {
523 | exec: (provider, proto, ...args) => {
524 | if (args[1] === 'true') {
525 | return provider.getBlockWithTransactions(args[0]);
526 | } else {
527 | return provider.getBlock(args[0]);
528 | }
529 | },
530 | codeSample: (url, ...args) => {
531 | if (args[1] === 'true') {
532 | return ethersTemplate(
533 | `getBlockWithTransactions('${args[0]}')`,
534 | 'blockData',
535 | url
536 | );
537 | } else {
538 | return ethersTemplate(`getBlock('${args[0]}')`, 'blockData', url);
539 | }
540 | },
541 | args: [
542 | {
543 | type: 'textarea',
544 | description: 'Hex of a block number to get information from',
545 | placeholder: 'i.e. 0x9C6EFE',
546 | },
547 | {
548 | type: 'boolean',
549 | description: 'Should we return full transaction objects?',
550 | placeholder: '',
551 | },
552 | ],
553 | },
554 | eth_getTransactionByHash: {
555 | exec: (provider, proto, ...args) => {
556 | return provider.send('eth_getTransactionByHash', [args[0]]);
557 | },
558 | codeSample: (url, ...args) => {
559 | return ethersTemplate(
560 | `send('eth_getTransactionByHash', ['${args[0]}'])`,
561 | 'txInfo',
562 | url
563 | );
564 | },
565 | args: [
566 | {
567 | type: 'textarea',
568 | description: 'Hash of a transaction to get information for',
569 | placeholder:
570 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
571 | },
572 | ],
573 | },
574 | eth_getTransactionByBlockHashAndIndex: {
575 | exec: (provider, proto, ...args) => {
576 | return provider.send('eth_getTransactionByBlockHashAndIndex', [...args]);
577 | },
578 | codeSample: (url, ...args) => {
579 | return ethersTemplate(
580 | `send('eth_getTransactionByBlockHashAndIndex', ['${args[0]}', '${args[1]}'])`,
581 | 'txInfo',
582 | url
583 | );
584 | },
585 | args: [
586 | {
587 | type: 'textarea',
588 | description: 'Hash of a block to get information from',
589 | placeholder: 'i.e. 0x16c4e370736...',
590 | },
591 | {
592 | type: 'textfield',
593 | description: 'Hex of tx position in the block',
594 | placeholder: 'i.e. 0x0, 0x1, 0x2...',
595 | },
596 | ],
597 | },
598 | eth_getTransactionByBlockNumberAndIndex: {
599 | exec: (provider, proto, ...args) => {
600 | return provider.send('eth_getTransactionByBlockNumberAndIndex', [
601 | ...args,
602 | ]);
603 | },
604 | codeSample: (url, ...args) => {
605 | return ethersTemplate(
606 | `send('eth_getTransactionByBlockNumberAndIndex', ['${args[0]}', '${args[1]}'])`,
607 | 'txInfo',
608 | url
609 | );
610 | },
611 | args: [
612 | {
613 | type: 'textfield',
614 | description:
615 | 'Hex block number, or the string "latest", "earliest" or "pending"',
616 | placeholder: 'i.e. latest or pending',
617 | },
618 | {
619 | type: 'textfield',
620 | description: 'Hex of tx position in the block',
621 | placeholder: 'i.e. 0x0, 0x1, 0x2...',
622 | },
623 | ],
624 | },
625 | eth_getTransactionReceipt: {
626 | exec: (provider, proto, ...args) => {
627 | return provider.waitForTransaction(...args);
628 | },
629 | codeSample: (url, ...args) => {
630 | return ethersTemplate(
631 | `waitForTransaction('${args[0]}')`,
632 | 'txReceipt',
633 | url
634 | );
635 | },
636 | args: [
637 | {
638 | type: 'textarea',
639 | description: 'Hash of a transaction to get information for',
640 | placeholder:
641 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
642 | },
643 | ],
644 | },
645 | eth_getUncleByBlockHashAndIndex: {
646 | exec: (provider, proto, ...args) => {
647 | return provider.send('eth_getUncleByBlockHashAndIndex', args);
648 | },
649 | codeSample: (url, ...args) => {
650 | return ethersTemplate(
651 | `send('eth_getUncleByBlockHashAndIndex', ['${args[0]}', '${args[1]}'])`,
652 | 'blockUncle',
653 | url
654 | );
655 | },
656 | args: [
657 | {
658 | type: 'textarea',
659 | description: 'Hash of a block to get information from',
660 | placeholder: 'i.e. 0x16c4e370736...',
661 | },
662 | {
663 | type: 'textfield',
664 | description: 'The uncle’s index position.',
665 | placeholder: 'i.e. 0x0',
666 | },
667 | ],
668 | },
669 | eth_getUncleByBlockNumberAndIndex: {
670 | exec: (provider, proto, ...args) => {
671 | return provider.send('eth_getUncleByBlockNumberAndIndex', args);
672 | },
673 | codeSample: (url, ...args) => {
674 | return ethersTemplate(
675 | `send('eth_getUncleByBlockNumberAndIndex', ['${args[0]}', '${args[1]}']`,
676 | 'blockUncle',
677 | url
678 | );
679 | },
680 | args: [
681 | {
682 | type: 'textarea',
683 | description:
684 | 'Hex block number, or the string "latest", "earliest" or "pending"',
685 | placeholder: 'i.e. 0x29c',
686 | },
687 | {
688 | type: 'textfield',
689 | description: 'The uncle’s index position.',
690 | placeholder: 'i.e. 0x0',
691 | },
692 | ],
693 | },
694 | eth_getCompilers: {
695 | exec: (provider, proto, ...args) => {
696 | return provider.send('eth_getCompilers');
697 | },
698 | codeSample: (url, ...args) => {
699 | return ethersTemplate("send('eth_getCompilers')", 'compilerList', url);
700 | },
701 | args: [],
702 | },
703 | eth_compileSolidity: {
704 | exec: (provider, proto, ...args) => {
705 | return provider.send('eth_compileSolidity', [args[0]]);
706 | },
707 | codeSample: (url, ...args) => {
708 | return ethersTemplate(
709 | `send('eth_compileSolidity', ['${args[0]}'])`,
710 | 'compiledCode',
711 | url
712 | );
713 | },
714 | args: [
715 | {
716 | type: 'textarea',
717 | description: 'The source code you wish to compile.',
718 | placeholder:
719 | 'i.e. contract test { function multiply(uint a) returns(uint d) { return a * 7; } }',
720 | },
721 | ],
722 | },
723 | eth_compileSerpent: {
724 | exec: (provider, proto, ...args) => {
725 | return provider.send('eth_compileSerpent', args);
726 | },
727 | codeSample: (url, ...args) => {
728 | return ethersTemplate(
729 | `send('eth_compileSerpent', ['${args[0]}'])`,
730 | 'compiledCode',
731 | url
732 | );
733 | },
734 | args: [
735 | {
736 | type: 'textarea',
737 | description: 'The source code you wish to compile.',
738 | placeholder: 'i.e. /* some serpent */',
739 | },
740 | ],
741 | },
742 | eth_newFilter: {
743 | exec: async (provider, proto, ...args) => {
744 | const filter = {};
745 | filter.topics = args[3]
746 | ? args[3].split(',').map((x) => (x === 'null' ? null : x.split('||')))
747 | : [];
748 | filter.fromBlock = args[0] ? args[0] : 'latest';
749 | filter.toBlock = args[1] ? args[1] : 'latest';
750 | filter.address = args[2] ? args[2] : null;
751 |
752 | const filterId = await provider.send('eth_newFilter', [filter]);
753 | return provider.send('eth_getFilterChanges', [filterId]);
754 | },
755 | codeSample: (url, ...args) => {
756 | const filter = `const filter = {
757 | ${args[0] ? "fromBlock: '" + args[0] + "'" : "fromBlock: 'latest'"},
758 | ${args[1] ? "toBlock: '" + args[1] + "'" : "toBlock: 'latest'"},${
759 | args[2] ? "\n address: '" + args[2] + "'," : ''
760 | }
761 | topics: ${
762 | args[3]
763 | ? JSON.stringify(
764 | args[3].split(',').map((x) => (x === 'null' ? null : x.split('||')))
765 | )
766 | : '[]'
767 | }
768 | };`;
769 | return filterTemplate(url, 'eth_newFilter', filter);
770 | },
771 | args: [
772 | {
773 | type: 'textfield',
774 | description:
775 | 'fromBlock: Hex block number, or the string "latest", "earliest" or "pending"',
776 | placeholder: 'i.e. 0x29c',
777 | },
778 | {
779 | type: 'textfield',
780 | description:
781 | 'toBlock: Hex block number, or the string "latest", "earliest" or "pending"',
782 | placeholder: 'i.e. 0x29c',
783 | },
784 | {
785 | type: 'textarea',
786 | description:
787 | 'address: (optional) Contract address or a list of addresses from which logs should originate.',
788 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
789 | },
790 | {
791 | type: 'textarea',
792 | description:
793 | 'topics: (optional) Comma separated strings with filter topics, for "or" functionality use ||. Topics are order-dependent.',
794 | placeholder: 'i.e. 0x1962||0x16c4,null',
795 | },
796 | ],
797 | },
798 | eth_newBlockFilter: {
799 | exec: async (provider, proto, ...args) => {
800 | const filterId = await provider.send('eth_newBlockFilter');
801 | return provider.send('eth_getFilterChanges', [filterId]);
802 | },
803 | codeSample: (url) => filterTemplate(url, 'eth_newBlockFilter'),
804 | args: [],
805 | },
806 | eth_newPendingTransactionFilter: {
807 | exec: async (provider, proto, ...args) => {
808 | const filterId = await provider.send('eth_newPendingTransactionFilter');
809 | return provider.send('eth_getFilterChanges', [filterId]);
810 | },
811 | codeSample: (url) => filterTemplate(url, 'eth_newPendingTransactionFilter'),
812 | args: [],
813 | },
814 | eth_uninstallFilter: {
815 | exec: (provider, proto, ...args) => {
816 | return new Promise((resolve, reject) =>
817 | reject('EtherFlow does not support this method.')
818 | );
819 | },
820 | codeSample: (url, ...args) => {
821 | return '/* Not Supported by EtherFlow */';
822 | },
823 | args: [],
824 | },
825 | eth_getFilterChanges: {
826 | exec: (provider, proto, ...args) => {
827 | return new Promise((resolve, reject) =>
828 | reject(
829 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
830 | )
831 | );
832 | },
833 | codeSample: (url, ...args) => {
834 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
835 | },
836 | args: [],
837 | },
838 | eth_getFilterLogs: {
839 | exec: (provider, proto, ...args) => {
840 | return new Promise((resolve, reject) =>
841 | reject(
842 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
843 | )
844 | );
845 | },
846 | codeSample: (url, ...args) => {
847 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
848 | },
849 | args: [],
850 | },
851 | eth_getLogs: {
852 | exec: (provider, proto, ...args) => {
853 | return new Promise((resolve, reject) =>
854 | reject(
855 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
856 | )
857 | );
858 | },
859 | codeSample: (url, ...args) => {
860 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
861 | },
862 | args: [],
863 | },
864 | eth_getWork: {
865 | exec: (provider, proto, ...args) => {
866 | return provider.send('eth_getWork');
867 | },
868 | codeSample: (url, ...args) => {
869 | return ethersTemplate(`send('eth_getWork')`, 'work', url);
870 | },
871 | args: [],
872 | },
873 | trace_block: {
874 | exec: (provider, proto, ...args) => {
875 | return provider.send('trace_block', [args[0]]);
876 | },
877 | codeSample: (url, ...args) => {
878 | return ethersTemplate(
879 | `send('trace_block', ['${args[0]}'])`,
880 | 'trace',
881 | url
882 | );
883 | },
884 | args: [
885 | {
886 | type: 'textfield',
887 | description:
888 | 'Hex block number, or the string "latest", "earliest" or "pending"',
889 | placeholder: 'i.e. latest or pending',
890 | },
891 | ],
892 | },
893 | trace_transaction: {
894 | exec: (provider, proto, ...args) => {
895 | return provider.send('trace_transaction', [args[0]]);
896 | },
897 | codeSample: (url, ...args) => {
898 | return ethersTemplate(
899 | `send('trace_transaction', ['${args[0]}'])`,
900 | 'trace',
901 | url
902 | );
903 | },
904 | args: [
905 | {
906 | type: 'textarea',
907 | description: 'Hash of a transaction to get information for',
908 | placeholder:
909 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
910 | },
911 | ],
912 | },
913 | trace_get: {
914 | exec: (provider, proto, ...args) => {
915 | return provider.send('trace_get', [args[0], (args[1] || '').split(',')]);
916 | },
917 | codeSample: (url, ...args) => {
918 | return ethersTemplate(
919 | `send('trace_get', ['${args[0]}', ['${(args[1] || '')
920 | .split(',')
921 | .join(', ')}']])`,
922 | 'trace',
923 | url
924 | );
925 | },
926 | args: [
927 | {
928 | type: 'textarea',
929 | description: 'Hash of a transaction to get information for',
930 | placeholder:
931 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
932 | },
933 | {
934 | type: 'textfield',
935 | description: 'Index positions of the traces, separated by commas',
936 | placeholder: 'i.e. 0x0,0x2,0x4',
937 | },
938 | ],
939 | },
940 | trace_rawTransaction: {
941 | exec: (provider, proto, ...args) => {
942 | return provider.send('trace_rawTransaction', [args[0], [args[1]]]);
943 | },
944 | codeSample: (url, ...args) => {
945 | return ethersTemplate(
946 | `send('trace_rawTransaction', ['${args[0]}', ['${args[1]}']])`,
947 | 'trace',
948 | url
949 | );
950 | },
951 | args: [
952 | {
953 | type: 'textarea',
954 | description: 'Raw transaction data.',
955 | placeholder:
956 | 'i.e. 0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428',
957 | },
958 | {
959 | type: 'textfield',
960 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
961 | placeholder: 'i.e. vmTrace',
962 | },
963 | ],
964 | },
965 | trace_replayBlockTransactions: {
966 | exec: (provider, proto, ...args) => {
967 | return provider.send('trace_replayBlockTransactions', [
968 | args[0],
969 | [args[1]],
970 | ]);
971 | },
972 | codeSample: (url, ...args) => {
973 | return ethersTemplate(
974 | `send('trace_replayBlockTransactions', ['${args[0]}', ['${args[1]}']])`,
975 | 'trace',
976 | url
977 | );
978 | },
979 | args: [
980 | {
981 | type: 'textarea',
982 | description:
983 | 'Hex block number, or the string "latest", "earliest" or "pending"',
984 | placeholder: 'i.e. latest or pending',
985 | },
986 | {
987 | type: 'textfield',
988 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
989 | placeholder: 'i.e. vmTrace',
990 | },
991 | ],
992 | },
993 | trace_replayTransaction: {
994 | exec: (provider, proto, ...args) => {
995 | return provider.send('trace_replayTransaction', [args[0], [args[1]]]);
996 | },
997 | codeSample: (url, ...args) => {
998 | return ethersTemplate(
999 | `send('trace_replayTransaction', ['${args[0]}', ['${args[1]}']])`,
1000 | 'trace',
1001 | url
1002 | );
1003 | },
1004 | args: [
1005 | {
1006 | type: 'textarea',
1007 | description: 'Hash of a transaction to get trace for',
1008 | placeholder:
1009 | 'i.e. 0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f',
1010 | },
1011 | {
1012 | type: 'textfield',
1013 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
1014 | placeholder: 'i.e. vmTrace',
1015 | },
1016 | ],
1017 | },
1018 | trace_filter: {
1019 | exec: (provider, proto, ...args) => {
1020 | const filter = {
1021 | ...(args[2] && { fromAddress: [args[2]] }),
1022 | ...(args[3] && { toAddress: [args[3]] }),
1023 | ...(args[4] && { after: args[4] }),
1024 | ...(args[5] && { count: args[5] }),
1025 | };
1026 | filter.fromBlock = args[0] ? args[0] : 'latest';
1027 | filter.toBlock = args[1] ? args[1] : 'latest';
1028 |
1029 | return provider.send('trace_filter', [filter]);
1030 | },
1031 | codeSample: (url, ...args) => {
1032 | return ethersTemplate(
1033 | `send('trace_filter', [{
1034 | "fromBlock": "${args[0] || 'latest'}",
1035 | "toBlock": "${args[1] || 'latest'}",${
1036 | args[2] ? '\n\t"fromAddress": [' + args[2] + '],' : ''
1037 | }${args[3] ? '\n\t"toAddress": [' + args[3] + '],' : ''}${
1038 | args[4] ? '\n\t"after": ' + args[3] + ',' : ''
1039 | }${args[4] ? '\n\t"count": ' + args[4] + ',' : ''}
1040 | }])`,
1041 | 'trace',
1042 | url
1043 | );
1044 | },
1045 | args: [
1046 | {
1047 | type: 'textfield',
1048 | description:
1049 | 'fromBlock: Hex block number, or the string "latest", "earliest" or "pending"',
1050 | placeholder: 'i.e. 0x29c',
1051 | },
1052 | {
1053 | type: 'textfield',
1054 | description:
1055 | 'toBlock: Hex block number, or the string "latest", "earliest" or "pending"',
1056 | placeholder: 'i.e. 0x29c',
1057 | },
1058 | {
1059 | type: 'textarea',
1060 | description:
1061 | 'fromAddress: (optional) Contract address or a list of addresses from which logs should originate.',
1062 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
1063 | },
1064 | {
1065 | type: 'textarea',
1066 | description:
1067 | 'toAddress: (optional) Contract address or a list of addresses to which logs should terminate.',
1068 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
1069 | },
1070 | {
1071 | type: 'textfield',
1072 | description:
1073 | 'topics: (optional) The offset trace number as an integer.',
1074 | placeholder: 'i.e. 1000',
1075 | },
1076 | {
1077 | type: 'textfield',
1078 | description:
1079 | 'topics: (optional) The number of traces to display in a batch as an integer.',
1080 | placeholder: 'i.e. 10',
1081 | },
1082 | ],
1083 | },
1084 | trace_call: {
1085 | exec: (provider, proto, ...args) => {
1086 | let [
1087 | traceType,
1088 | block,
1089 | from,
1090 | value,
1091 | contract,
1092 | abi,
1093 | method,
1094 | ...rest
1095 | ] = args;
1096 | let iface = new ethers.utils.Interface(abi);
1097 | const data = iface.encodeFunctionData(method, rest);
1098 | if (value === '') value = null;
1099 | if (from === '') from = null;
1100 | const transaction = {
1101 | from,
1102 | to: contract,
1103 | value,
1104 | data,
1105 | };
1106 | return provider.send('trace_call', [
1107 | transaction,
1108 | traceType.split(', '),
1109 | block,
1110 | ]);
1111 | },
1112 | codeSample: (url, ...args) => {
1113 | const [traceType, block, ...rest] = args;
1114 | return contractTraceTemplate(url, [
1115 | JSON.stringify(traceType.split(', ')),
1116 | JSON.stringify(block),
1117 | ...rest,
1118 | ]);
1119 | },
1120 | args: [
1121 | {
1122 | type: 'textfield',
1123 | description:
1124 | 'Type of trace, one or more of: `vmTrace`, `trace`, `stateDiff`',
1125 | placeholder: 'i.e. vmTrace, trace',
1126 | },
1127 | {
1128 | type: 'textfield',
1129 | description:
1130 | 'Hex block number, or the string "latest", "earliest" or "pending"',
1131 | placeholder: 'i.e. latest or pending',
1132 | },
1133 | {
1134 | type: 'textarea',
1135 | description:
1136 | 'address: (optional) The address the transaction is sent from',
1137 | placeholder: 'i.e. 0x19624ffa41f...',
1138 | },
1139 | {
1140 | type: 'textfield',
1141 | description:
1142 | 'value: (optional) Integer formatted as a hex string of the value sent with this transaction',
1143 | placeholder: 'i.e. 0x19624ffa41f...',
1144 | },
1145 | {
1146 | type: 'textarea',
1147 | description: 'Address of contract',
1148 | placeholder: 'i.e. 0x91b51c173a4...',
1149 | },
1150 | {
1151 | type: 'textarea',
1152 | description: 'Contract ABI (URL or single function object)',
1153 | placeholder:
1154 | 'i.e. [{"inputs":[{"name":"chainId...\nOR\nhttps://raw.githubusercontent.com/.../build/contracts/ERC20.json',
1155 | },
1156 | {
1157 | type: 'dropdown',
1158 | description: 'Function name (READ only)',
1159 | },
1160 | ],
1161 | },
1162 | };
1163 |
1164 | export default EthersCalls;
1165 |
--------------------------------------------------------------------------------
/src/helpers/libs/index.js:
--------------------------------------------------------------------------------
1 | import CURLCalls from './curl';
2 | import * as ethers from './ethers';
3 | import * as web3 from './web3js';
4 |
5 | export { ethers, web3 };
6 |
--------------------------------------------------------------------------------
/src/helpers/libs/web3js.js:
--------------------------------------------------------------------------------
1 | const web3Template = (methodCall, varName, url) => {
2 | return `const Web3 = require("web3");
3 | // OR import Web3 from 'web3';
4 |
5 | // HTTP version
6 | (async () => {
7 | const web3 = new Web3('${url}');
8 | const ${varName} = await web3.${methodCall};
9 | console.log(${varName});
10 | })();
11 | `;
12 | };
13 |
14 | const web3TraceTemplate = (
15 | rpcMethod,
16 | methodCall,
17 | args,
18 | formatters,
19 | varName,
20 | url
21 | ) => {
22 | return `const Web3 = require("web3");
23 | // OR import Web3 from 'web3';
24 |
25 | // HTTP version
26 | (async () => {
27 | const web3 = new Web3('${url}');
28 | web3.extend({
29 | methods: [
30 | {
31 | name: '${methodCall}',
32 | call: '${rpcMethod}',
33 | params: ${formatters.length},
34 | inputFormatter: [${formatters.join(', ')}],
35 | },
36 | ],
37 | });
38 | const ${varName} = await web3.${methodCall}('${args.join("', '")}');
39 | console.log(${varName});
40 | })();
41 | `;
42 | };
43 |
44 | const contractTemplate = (url, args) => {
45 | const [address, abi, method, methodArgumentsString] = args;
46 | return `const Web3 = require("web3");
47 | // OR import Web3 from 'web3';
48 |
49 | // HTTP version
50 | (async () => {
51 | const abi = ${abi && JSON.stringify(abi)}
52 | const web3 = new Web3('${url}');
53 | const contract = new web3.eth.Contract(abi, '${address}');
54 | const response = await contract.methods.${method}(${methodArgumentsString});
55 | console.log(response);
56 | })();`;
57 | };
58 |
59 | const contractTraceTemplate = (url, args) => {
60 | const [
61 | traceTypeList,
62 | block,
63 | from,
64 | value,
65 | contract,
66 | abi,
67 | method,
68 | methodArgumentsString,
69 | ] = args;
70 | return `const Web3 = require("web3");
71 | // OR import Web3 from 'web3';
72 |
73 | // HTTP version
74 | (async () => {
75 | const abiFragment = ${abi && JSON.stringify(abi[0])}
76 | const web3 = new Web3('${url}');
77 | const data = web3.eth.abi.encodeFunctionCall(abiFragment, [${methodArgumentsString}]);${
78 | from ? `\n const from = "${from}";` : ''
79 | }
80 | const to = "${contract}"; ${value ? `\n const value = "${value}";` : ''}
81 | const transaction = { ${from ? `\n from,` : ''}
82 | to,${value ? `\n value,` : ''}
83 | data,
84 | };
85 | web3.extend({
86 | methods: [
87 | {
88 | name: 'parityTraceCall',
89 | call: 'trace_call',
90 | params: 3,
91 | inputFormatter: [null, null, null],
92 | },
93 | ],
94 | });
95 | const response = await web3.parityTraceCall(transaction, ${traceTypeList}, ${block});
96 | console.log(response);
97 | })();`;
98 | };
99 |
100 | const filterTemplate = (url, filterMethod, filter) => {
101 | return `const Web3 = require("web3");
102 | // OR import Web3 from 'web3';
103 | ${filter ? `\n${filter}\n` : ''}
104 | // HTTP version
105 | (async () => {
106 | const web3 = new Web3('${url}');
107 | web3.extend({
108 | methods: [
109 | {
110 | name: '${filterMethod}',
111 | call: '${filterMethod}',
112 | params: ${filter ? 1 : 0},
113 | inputFormatter: [${filter ? 'null' : ''}],
114 | },
115 | ],
116 | });
117 | web3.extend({
118 | methods: [
119 | {
120 | name: 'eth_getFilterChanges',
121 | call: 'eth_getFilterChanges',
122 | params: 1,
123 | inputFormatter: [null],
124 | },
125 | ],
126 | });
127 | const filterId = await web3.${filterMethod}(${filter ? 'filter' : ''});
128 | console.log(filterId);
129 | const response = await web3.eth_getFilterChanges(filterId);
130 | console.log(response);
131 | })();`;
132 | };
133 |
134 | const Web3JSCalls = {
135 | web3_clientVersion: {
136 | exec: (provider, proto, ...args) => {
137 | return provider.eth.getNodeInfo();
138 | },
139 | codeSample: (url, ...args) => {
140 | return web3Template('eth.getNodeInfo()', 'version', url);
141 | },
142 | args: [],
143 | },
144 | web3_sha3: {
145 | exec: (provider, proto, ...args) => {
146 | return new Promise((resolve, reject) =>
147 | resolve(provider.utils.sha3(args[0], { encoding: 'hex' }))
148 | );
149 | },
150 | codeSample: (url, ...args) => {
151 | return web3Template(
152 | `utils.sha3('${args[0]}', { encoding: 'hex' })`,
153 | 'hash',
154 | url
155 | );
156 | },
157 | args: [
158 | {
159 | type: 'textarea',
160 | description: 'The hexified data to convert into a SHA3 hash',
161 | placeholder: 'i.e. 0x68656c6c6f20776f726c64',
162 | },
163 | ],
164 | },
165 | net_version: {
166 | exec: (provider, proto, ...args) => {
167 | return provider.eth.net.getId();
168 | },
169 | codeSample: (url, ...args) => {
170 | return web3Template(`eth.net.getId()`, 'network', url);
171 | },
172 | args: [],
173 | },
174 | net_listening: {
175 | exec: (provider, proto, ...args) => {
176 | return provider.eth.net.isListening();
177 | },
178 | codeSample: (url, ...args) => {
179 | return web3Template(`eth.net.isListening()`, 'listening', url);
180 | },
181 | args: [],
182 | },
183 | net_peerCount: {
184 | exec: (provider, proto, ...args) => {
185 | return provider.eth.net.getPeerCount();
186 | },
187 | codeSample: (url, ...args) => {
188 | return web3Template(`eth.net.getPeerCount()`, 'peers', url);
189 | },
190 | args: [],
191 | },
192 | eth_protocolVersion: {
193 | exec: (provider, proto, ...args) => {
194 | return provider.eth.getProtocolVersion();
195 | },
196 | codeSample: (url, ...args) => {
197 | return web3Template(`eth.getProtocolVersion()`, 'version', url);
198 | },
199 | args: [],
200 | },
201 | eth_syncing: {
202 | exec: (provider, proto, ...args) => {
203 | return provider.eth.isSyncing();
204 | },
205 | codeSample: (url, ...args) => {
206 | return web3Template(`eth.isSyncing()`, 'isSyncing', url);
207 | },
208 | args: [],
209 | },
210 | eth_coinbase: {
211 | exec: (provider, proto, ...args) => {
212 | return provider.eth.getCoinbase();
213 | },
214 | codeSample: (url, ...args) => {
215 | return web3Template(`eth.getCoinbase()`, 'coinbase', url);
216 | },
217 | args: [],
218 | },
219 | eth_mining: {
220 | exec: (provider, proto, ...args) => {
221 | return provider.eth.isMining();
222 | },
223 | codeSample: (url, ...args) => {
224 | return web3Template(`eth.isMining()`, 'isMining', url);
225 | },
226 | args: [],
227 | },
228 | eth_hashrate: {
229 | exec: (provider, proto, ...args) => {
230 | return provider.eth.getHashrate();
231 | },
232 | codeSample: (url, ...args) => {
233 | return web3Template(`eth.getHashrate()`, 'hashRate', url);
234 | },
235 | args: [],
236 | },
237 | eth_gasPrice: {
238 | exec: (provider, proto, ...args) => {
239 | return provider.eth.getGasPrice();
240 | },
241 | codeSample: (url, ...args) => {
242 | return web3Template(`eth.getGasPrice()`, 'gasPrice', url);
243 | },
244 | args: [],
245 | },
246 | eth_accounts: {
247 | exec: (provider, proto, ...args) => {
248 | return provider.eth.getAccounts();
249 | },
250 | codeSample: (url, ...args) => {
251 | return web3Template(`eth.getAccounts()`, 'accts', url);
252 | },
253 | args: [],
254 | },
255 | eth_blockNumber: {
256 | exec: (provider, proto, ...args) => {
257 | return provider.eth.getBlockNumber();
258 | },
259 | codeSample: (url, ...args) => {
260 | return web3Template(`eth.getBlockNumber()`, 'blockNum', url);
261 | },
262 | args: [],
263 | },
264 | eth_getBalance: {
265 | exec: (provider, proto, ...args) => {
266 | return provider.eth.getBalance(args[0], args[1]);
267 | },
268 | codeSample: (url, ...args) => {
269 | return web3Template(
270 | `eth.getBalance('${args[0]}', '${args[1]}')`,
271 | 'balance',
272 | url
273 | );
274 | },
275 | args: [
276 | {
277 | type: 'textarea',
278 | description: 'Address to check for balance',
279 | placeholder: 'i.e. 0x91b51c173a4...',
280 | },
281 | {
282 | type: 'textfield',
283 | description:
284 | 'Hex block number, or the string "latest", "earliest" or "pending"',
285 | placeholder: 'i.e. latest or pending',
286 | },
287 | ],
288 | },
289 | eth_getStorageAt: {
290 | exec: (provider, proto, ...args) => {
291 | return provider.eth.getStorageAt(...args);
292 | },
293 | codeSample: (url, ...args) => {
294 | return web3Template(
295 | `getStorageAt('${args[0]}', '${args[1]}', '${args[2]}')`,
296 | 'storage',
297 | url
298 | );
299 | },
300 | args: [
301 | {
302 | type: 'textarea',
303 | description: 'Address of the storage',
304 | placeholder: 'i.e. 0x91b51c173a4... or ENS domain',
305 | },
306 | {
307 | type: 'textfield',
308 | description: 'Hex of the position in the storage',
309 | placeholder: 'i.e. 0x0, 0x1, 0x2...',
310 | },
311 | {
312 | type: 'textfield',
313 | description:
314 | 'Hex block number, or the string "latest", "earliest" or "pending"',
315 | placeholder: 'i.e. latest or pending',
316 | },
317 | ],
318 | },
319 | eth_getTransactionCount: {
320 | exec: (provider, proto, ...args) => {
321 | return provider.eth.getTransactionCount(...args);
322 | },
323 | codeSample: (url, ...args) => {
324 | return web3Template(
325 | `eth.getTransactionCount('${args[0]}', '${args[1]}')`,
326 | 'txCount',
327 | url
328 | );
329 | },
330 | args: [
331 | {
332 | type: 'textarea',
333 | description: 'Address to check for balance',
334 | placeholder: 'i.e. 0x91b51c173a4...',
335 | },
336 | {
337 | type: 'textfield',
338 | description:
339 | 'Hex block number, or the string "latest", "earliest" or "pending"',
340 | placeholder: 'i.e. latest or pending',
341 | },
342 | ],
343 | },
344 | eth_getBlockTransactionCountByHash: {
345 | exec: (provider, proto, ...args) => {
346 | return provider.eth.getBlockTransactionCount(args[0]);
347 | },
348 | codeSample: (url, ...args) => {
349 | return web3Template(
350 | `eth.getBlockTransactionCount('${args[0]}')`,
351 | 'txCount',
352 | url
353 | );
354 | },
355 | args: [
356 | {
357 | type: 'textarea',
358 | description: 'Hash of a block to get transaction count from',
359 | placeholder: 'i.e. 0x16c4e370736...',
360 | },
361 | ],
362 | },
363 | eth_getBlockTransactionCountByNumber: {
364 | exec: (provider, proto, ...args) => {
365 | return provider.eth.getBlockTransactionCount(args[0]);
366 | },
367 | codeSample: (url, ...args) => {
368 | return web3Template(
369 | `eth.getBlockTransactionCount('${args[0]}')`,
370 | 'txCount',
371 | url
372 | );
373 | },
374 | args: [
375 | {
376 | type: 'textarea',
377 | description:
378 | 'Integer in decimal format of a block to get transaction count from',
379 | placeholder: 'i.e. 10674793',
380 | },
381 | ],
382 | },
383 | eth_getUncleCountByBlockHash: {
384 | exec: (provider, proto, ...args) => {
385 | return provider.eth.getBlockUncleCount(args[0]);
386 | },
387 | codeSample: (url, ...args) => {
388 | return web3Template(
389 | `eth.getBlockUncleCount('${args[0]}')`,
390 | 'uncleCount',
391 | url
392 | );
393 | },
394 | args: [
395 | {
396 | type: 'textarea',
397 | description: 'Hash of a block to get uncle count from',
398 | placeholder: 'i.e. 0x16c4e370736...',
399 | },
400 | ],
401 | },
402 | eth_getUncleCountByBlockNumber: {
403 | exec: (provider, proto, ...args) => {
404 | return provider.eth.getBlockUncleCount(args[0]);
405 | },
406 | codeSample: (url, ...args) => {
407 | return web3Template(
408 | `eth.getBlockUncleCount('${args[0]}')`,
409 | 'uncleCount',
410 | url
411 | );
412 | },
413 | args: [
414 | {
415 | type: 'textarea',
416 | description:
417 | 'Integer in decimal format of a block to get uncle count from',
418 | placeholder: 'i.e. 10674793',
419 | },
420 | ],
421 | },
422 | eth_getCode: {
423 | exec: (provider, proto, ...args) => {
424 | return provider.eth.getCode(...args);
425 | },
426 | codeSample: (url, ...args) => {
427 | return web3Template(
428 | `eth.getCode('${args[0]}', '${args[1]}')`,
429 | 'code',
430 | url
431 | );
432 | },
433 | args: [
434 | {
435 | type: 'textarea',
436 | description: 'Address to fetch code from',
437 | placeholder: 'i.e. 0x91b51c173a4...',
438 | },
439 | {
440 | type: 'textfield',
441 | description:
442 | 'Integer block number, or the string "latest", "earliest" or "pending"',
443 | placeholder: 'i.e. latest or pending',
444 | },
445 | ],
446 | },
447 | eth_sign: {
448 | exec: (provider, proto, ...args) => {
449 | return new Promise((resolve, reject) =>
450 | reject('EtherFlow does not support this method.')
451 | );
452 | },
453 | codeSample: (url, ...args) => {
454 | return '/* Not Supported by EtherFlow */';
455 | },
456 | args: [],
457 | },
458 | eth_signTransaction: {
459 | exec: (provider, proto, ...args) => {
460 | return new Promise((resolve, reject) =>
461 | reject('EtherFlow does not support this method.')
462 | );
463 | },
464 | codeSample: (url, ...args) => {
465 | return '/* Not Supported by EtherFlow */';
466 | },
467 | args: [],
468 | },
469 | eth_sendTransaction: {
470 | exec: (provider, proto, ...args) => {
471 | return new Promise((resolve, reject) =>
472 | reject('EtherFlow does not support this method.')
473 | );
474 | },
475 | codeSample: (url, ...args) => {
476 | return '/* Not Supported by EtherFlow */';
477 | },
478 | args: [],
479 | },
480 | eth_sendRawTransaction: {
481 | exec: (provider, proto, ...args) => {
482 | return provider.eth.sendSignedTransaction(...args);
483 | },
484 | codeSample: (url, ...args) => {
485 | return web3Template(`eth.sendSignedTransaction('${args[0]}')`, 'tx', url);
486 | },
487 | args: [
488 | {
489 | type: 'textarea',
490 | description: 'The previously signed transaction data',
491 | placeholder:
492 | 'i.e. 0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675',
493 | },
494 | ],
495 | },
496 | eth_call: {
497 | exec: (provider, proto, ...args) => {
498 | const [address, abi, method, ...rest] = args;
499 | try {
500 | const contract = new provider.eth.Contract(JSON.parse(abi), address);
501 | return contract.methods[method](...rest).call();
502 | } catch (e) {
503 | console.log(e);
504 | }
505 | },
506 | codeSample: (url, ...args) => {
507 | return contractTemplate(url, args);
508 | },
509 | args: [
510 | {
511 | type: 'textarea',
512 | description: 'Address of contract',
513 | placeholder: 'i.e. 0x91b51c173a4...',
514 | },
515 | {
516 | type: 'textarea',
517 | description: 'Contract ABI (URL or single function object)',
518 | placeholder:
519 | 'i.e. [{"inputs":[{"name":"chainId...\nOR\nhttps://raw.githubusercontent.com/.../build/contracts/ERC20.json',
520 | },
521 | {
522 | type: 'dropdown',
523 | description: 'Function name (READ only)',
524 | },
525 | ],
526 | },
527 | eth_estimateGas: {
528 | exec: (provider, proto, ...args) => {
529 | return new Promise((resolve, reject) =>
530 | reject('EtherFlow does not support this method.')
531 | );
532 | },
533 | codeSample: (url, ...args) => {
534 | return '/* Not Supported by EtherFlow */';
535 | },
536 | args: [],
537 | },
538 | eth_getBlockByHash: {
539 | exec: (provider, proto, ...args) => {
540 | return provider.eth.getBlock(args[0], args[1] === 'true');
541 | },
542 | codeSample: (url, ...args) => {
543 | return web3Template(
544 | `eth.getBlock('${args[0]}', ${args[1]})`,
545 | 'blockData',
546 | url
547 | );
548 | },
549 | args: [
550 | {
551 | type: 'textarea',
552 | description: 'Hash of a block to get information from',
553 | placeholder: 'i.e. 0x16c4e370736...',
554 | },
555 | {
556 | type: 'boolean',
557 | description: 'Should we return full transaction objects?',
558 | placeholder: '',
559 | },
560 | ],
561 | },
562 | eth_getBlockByNumber: {
563 | exec: (provider, proto, ...args) => {
564 | return provider.eth.getBlock(args[0], args[1] === 'true');
565 | },
566 | codeSample: (url, ...args) => {
567 | return web3Template(
568 | `eth.getBlock('${args[0]}', ${args[1]})`,
569 | 'blockData',
570 | url
571 | );
572 | },
573 | args: [
574 | {
575 | type: 'textarea',
576 | description:
577 | 'Integer in decimal format of a block number to get information from',
578 | placeholder: 'i.e. 10674793',
579 | },
580 | {
581 | type: 'boolean',
582 | description: 'Should we return full transaction objects?',
583 | placeholder: '',
584 | },
585 | ],
586 | },
587 | eth_getTransactionByHash: {
588 | exec: (provider, proto, ...args) => {
589 | return provider.eth.getTransaction(args[0]);
590 | },
591 | codeSample: (url, ...args) => {
592 | return web3Template(`eth.getTransaction('${args[0]}')`, 'txInfo', url);
593 | },
594 | args: [
595 | {
596 | type: 'textarea',
597 | description: 'Hash of a transaction to get information for',
598 | placeholder:
599 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
600 | },
601 | ],
602 | },
603 | eth_getTransactionByBlockHashAndIndex: {
604 | exec: (provider, proto, ...args) => {
605 | return provider.eth.getTransactionFromBlock(...args);
606 | },
607 | codeSample: (url, ...args) => {
608 | return web3Template(
609 | `eth.getTransactionFromBlock('${args[0]}', '${args[1]}')`,
610 | 'txInfo',
611 | url
612 | );
613 | },
614 | args: [
615 | {
616 | type: 'textarea',
617 | description: 'Hash of a block to get information from',
618 | placeholder: 'i.e. 0x16c4e370736...',
619 | },
620 | {
621 | type: 'textfield',
622 | description: 'Integer in decimal format of tx position in the block',
623 | placeholder: 'i.e. 0, 1, 2...',
624 | },
625 | ],
626 | },
627 | eth_getTransactionByBlockNumberAndIndex: {
628 | exec: (provider, proto, ...args) => {
629 | return provider.eth.getTransactionFromBlock(...args);
630 | },
631 | codeSample: (url, ...args) => {
632 | return web3Template(
633 | `eth.getTransactionFromBlock('${args[0]}', '${args[1]}')`,
634 | 'txInfo',
635 | url
636 | );
637 | },
638 | args: [
639 | {
640 | type: 'textarea',
641 | description:
642 | 'Integer in decimal format, or the string "latest", "earliest" or "pending"',
643 | placeholder: 'i.e. 10674793',
644 | },
645 | {
646 | type: 'textfield',
647 | description: 'Integer in decimal format of tx position in the block',
648 | placeholder: 'i.e. 0, 1, 2...',
649 | },
650 | ],
651 | },
652 | eth_getTransactionReceipt: {
653 | exec: (provider, proto, ...args) => {
654 | return provider.eth.getTransactionReceipt(args[0]);
655 | },
656 | codeSample: (url, ...args) => {
657 | return web3Template(
658 | `eth.getTransactionReceipt('${args[0]}')`,
659 | 'txReceipt',
660 | url
661 | );
662 | },
663 | args: [
664 | {
665 | type: 'textarea',
666 | description: 'Hash of a transaction to get information for',
667 | placeholder:
668 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
669 | },
670 | ],
671 | },
672 | eth_getUncleByBlockHashAndIndex: {
673 | exec: (provider, proto, ...args) => {
674 | return provider.eth.getUncle(...args);
675 | },
676 | codeSample: (url, ...args) => {
677 | return web3Template(
678 | `eth.getUncle('${args[0]}', '${args[1]}')`,
679 | 'blockUncle',
680 | url
681 | );
682 | },
683 | args: [
684 | {
685 | type: 'textarea',
686 | description: 'Hash of a block to get information from',
687 | placeholder: 'i.e. 0x16c4e370736...',
688 | },
689 | {
690 | type: 'textfield',
691 | description: 'The uncle’s index position as an integer.',
692 | placeholder: 'i.e. 0, 1, 2...',
693 | },
694 | ],
695 | },
696 | eth_getUncleByBlockNumberAndIndex: {
697 | exec: (provider, proto, ...args) => {
698 | return provider.eth.getUncle(...args);
699 | },
700 | codeSample: (url, ...args) => {
701 | return web3Template(
702 | `eth.getUncle('${args[0]}', '${args[1]}')`,
703 | 'blockUncle',
704 | url
705 | );
706 | },
707 | args: [
708 | {
709 | type: 'textarea',
710 | description:
711 | 'Integer in decimal format of a block to get transaction count from',
712 | placeholder: 'i.e. 10674793',
713 | },
714 | {
715 | type: 'textfield',
716 | description: 'The uncle’s index position as an integer.',
717 | placeholder: 'i.e. 0, 1, 2...',
718 | },
719 | ],
720 | },
721 | eth_getCompilers: {
722 | exec: (provider, proto, ...args) => {
723 | return new Promise((resolve, reject) =>
724 | reject('web3.js does not support this method.')
725 | );
726 | },
727 | codeSample: (url, ...args) => {
728 | return '/* Not Supported by web3.js */';
729 | },
730 | args: [],
731 | },
732 | eth_compileSolidity: {
733 | exec: (provider, proto, ...args) => {
734 | return new Promise((resolve, reject) =>
735 | reject('web3.js does not support this method.')
736 | );
737 | },
738 | codeSample: (url, ...args) => {
739 | return '/* Not Supported by web3.js */';
740 | },
741 | args: [],
742 | },
743 | eth_compileSerpent: {
744 | exec: (provider, proto, ...args) => {
745 | return new Promise((resolve, reject) =>
746 | reject('web3.js does not support this method.')
747 | );
748 | },
749 | codeSample: (url, ...args) => {
750 | return '/* Not Supported by web3.js */';
751 | },
752 | args: [],
753 | },
754 | eth_newFilter: {
755 | exec: async (provider, proto, ...args) => {
756 | const filter = {};
757 | filter.topics = args[3]
758 | ? args[3].split(',').map((x) => (x === 'null' ? null : x.split('||')))
759 | : [];
760 | filter.fromBlock = args[0] ? args[0] : 'latest';
761 | filter.toBlock = args[1] ? args[1] : 'latest';
762 | filter.address = args[2] ? args[2] : null;
763 | provider.extend({
764 | methods: [
765 | {
766 | name: 'eth_newFilter',
767 | call: 'eth_newFilter',
768 | params: 1,
769 | inputFormatter: [null],
770 | },
771 | ],
772 | });
773 | provider.extend({
774 | methods: [
775 | {
776 | name: 'eth_getFilterChanges',
777 | call: 'eth_getFilterChanges',
778 | params: 1,
779 | inputFormatter: [null],
780 | },
781 | ],
782 | });
783 | const filterId = await provider.eth_newFilter(filter);
784 | return provider.eth_getFilterChanges(filterId);
785 | },
786 | codeSample: (url, ...args) => {
787 | const filter = `const filter = {
788 | ${args[0] ? "fromBlock: '" + args[0] + "'" : "fromBlock: 'latest'"},
789 | ${args[1] ? "toBlock: '" + args[1] + "'" : "toBlock: 'latest'"},${
790 | args[2] ? "\n address: '" + args[2] + "'," : ''
791 | }
792 | topics: ${
793 | args[3]
794 | ? JSON.stringify(
795 | args[3].split(',').map((x) => (x === 'null' ? null : x.split('||')))
796 | )
797 | : '[]'
798 | }
799 | };`;
800 | return filterTemplate(url, 'eth_newFilter', filter);
801 | },
802 | args: [
803 | {
804 | type: 'textfield',
805 | description:
806 | 'fromBlock: Hex block number, or the string "latest", "earliest" or "pending"',
807 | placeholder: 'i.e. 0x29c',
808 | },
809 | {
810 | type: 'textfield',
811 | description:
812 | 'toBlock: Hex block number, or the string "latest", "earliest" or "pending"',
813 | placeholder: 'i.e. 0x29c',
814 | },
815 | {
816 | type: 'textarea',
817 | description:
818 | 'address: (optional) Contract address or a list of addresses from which logs should originate.',
819 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
820 | },
821 | {
822 | type: 'textarea',
823 | description:
824 | 'topics: (optional) Comma separated strings with filter topics, for "or" functionality use ||. Topics are order-dependent.',
825 | placeholder: 'i.e. 0x1962||0x16c4,null',
826 | },
827 | ],
828 | },
829 | eth_newBlockFilter: {
830 | exec: async (provider, proto, ...args) => {
831 | provider.extend({
832 | methods: [
833 | {
834 | name: 'eth_newBlockFilter',
835 | call: 'eth_newBlockFilter',
836 | params: 0,
837 | inputFormatter: [],
838 | },
839 | ],
840 | });
841 | provider.extend({
842 | methods: [
843 | {
844 | name: 'eth_getFilterChanges',
845 | call: 'eth_getFilterChanges',
846 | params: 1,
847 | inputFormatter: [null],
848 | },
849 | ],
850 | });
851 | const filterId = await provider.eth_newBlockFilter();
852 | return provider.eth_getFilterChanges(filterId);
853 | },
854 | codeSample: (url, ...args) => filterTemplate(url, 'eth_newBlockFilter'),
855 | args: [],
856 | },
857 | eth_newPendingTransactionFilter: {
858 | exec: async (provider, proto) => {
859 | provider.extend({
860 | methods: [
861 | {
862 | name: 'eth_newPendingTransactionFilter',
863 | call: 'eth_newPendingTransactionFilter',
864 | params: 0,
865 | inputFormatter: [],
866 | },
867 | ],
868 | });
869 | provider.extend({
870 | methods: [
871 | {
872 | name: 'eth_getFilterChanges',
873 | call: 'eth_getFilterChanges',
874 | params: 1,
875 | inputFormatter: [null],
876 | },
877 | ],
878 | });
879 | const filterId = await provider.eth_newPendingTransactionFilter();
880 | return provider.eth_getFilterChanges(filterId);
881 | },
882 | codeSample: (url) => filterTemplate(url, 'eth_newPendingTransactionFilter'),
883 | args: [],
884 | },
885 | eth_uninstallFilter: {
886 | exec: (provider, proto, ...args) => {
887 | return new Promise((resolve, reject) =>
888 | reject('EtherFlow does not support this method.')
889 | );
890 | },
891 | codeSample: (url, ...args) => {
892 | return '/* Not Supported by EtherFlow */';
893 | },
894 | args: [],
895 | },
896 | eth_getFilterChanges: {
897 | exec: (provider, proto, ...args) => {
898 | return new Promise((resolve, reject) =>
899 | reject(
900 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
901 | )
902 | );
903 | },
904 | codeSample: (url, ...args) => {
905 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
906 | },
907 | args: [],
908 | },
909 | eth_getFilterLogs: {
910 | exec: (provider, proto, ...args) => {
911 | return new Promise((resolve, reject) =>
912 | reject(
913 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
914 | )
915 | );
916 | },
917 | codeSample: (url, ...args) => {
918 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
919 | },
920 | args: [],
921 | },
922 | eth_getLogs: {
923 | exec: (provider, proto, ...args) => {
924 | return new Promise((resolve, reject) =>
925 | reject(
926 | 'EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.'
927 | )
928 | );
929 | },
930 | codeSample: (url, ...args) => {
931 | return '/* EtherFlow covers this method via eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter */';
932 | },
933 | args: [],
934 | },
935 | eth_getWork: {
936 | exec: (provider, proto, ...args) => {
937 | return provider.eth.getWork();
938 | },
939 | codeSample: (url, ...args) => {
940 | return web3Template(`eth.getWork()`, 'work', url);
941 | },
942 | args: [],
943 | },
944 | trace_block: {
945 | exec: (provider, proto, ...args) => {
946 | provider.extend({
947 | methods: [
948 | {
949 | name: 'parityTraceBlock',
950 | call: 'trace_block',
951 | params: 1,
952 | inputFormatter: [provider.utils.numberToHex],
953 | },
954 | ],
955 | });
956 | return provider.parityTraceBlock(args[0]);
957 | },
958 | codeSample: (url, ...args) => {
959 | return web3TraceTemplate(
960 | 'trace_block',
961 | 'parityTraceBlock',
962 | [args[0]],
963 | ['web3.utils.numberToHex'],
964 | 'trace',
965 | url
966 | );
967 | },
968 | args: [
969 | {
970 | type: 'textfield',
971 | description: 'Integer of block number only',
972 | placeholder: 'i.e. 10708846',
973 | },
974 | ],
975 | },
976 | trace_transaction: {
977 | exec: (provider, proto, ...args) => {
978 | provider.extend({
979 | methods: [
980 | {
981 | name: 'parityTraceTx',
982 | call: 'trace_transaction',
983 | params: 1,
984 | inputFormatter: [null],
985 | },
986 | ],
987 | });
988 | return provider.parityTraceTx(args[0]);
989 | },
990 | codeSample: (url, ...args) => {
991 | return web3TraceTemplate(
992 | 'trace_transaction',
993 | 'parityTraceTx',
994 | args,
995 | ['null'],
996 | 'trace',
997 | url
998 | );
999 | },
1000 | args: [
1001 | {
1002 | type: 'textarea',
1003 | description: 'Hash of a transaction to get information for',
1004 | placeholder:
1005 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
1006 | },
1007 | ],
1008 | },
1009 | trace_get: {
1010 | exec: (provider, proto, ...args) => {
1011 | provider.extend({
1012 | methods: [
1013 | {
1014 | name: 'parityTraceGet',
1015 | call: 'trace_get',
1016 | params: 1,
1017 | inputFormatter: [null, provider.utils.numberToHex],
1018 | },
1019 | ],
1020 | });
1021 | return provider.parityTraceGet(args[0], args[1].split(','));
1022 | },
1023 | codeSample: (url, ...args) => {
1024 | return web3TraceTemplate(
1025 | 'trace_get',
1026 | 'parityTraceGet',
1027 | args,
1028 | ['null', 'web3.utils.numberToHex'],
1029 | 'trace',
1030 | url
1031 | );
1032 | },
1033 | args: [
1034 | {
1035 | type: 'textarea',
1036 | description: 'Hash of a transaction to get information for',
1037 | placeholder:
1038 | 'i.e. 0x95575ee5f6cdb3907cd2983516f33828855ed4f12320103dc8524b96a5a5414b',
1039 | },
1040 | {
1041 | type: 'textfield',
1042 | description:
1043 | 'Integer index positions of the traces, separated by commas',
1044 | placeholder: 'i.e. 0,1,2',
1045 | },
1046 | ],
1047 | },
1048 | trace_rawTransaction: {
1049 | exec: (provider, proto, ...args) => {
1050 | provider.extend({
1051 | methods: [
1052 | {
1053 | name: 'parityTraceRawTx',
1054 | call: 'trace_rawTransaction',
1055 | params: 2,
1056 | inputFormatter: [null, null],
1057 | },
1058 | ],
1059 | });
1060 | return provider.parityTraceRawTx(args[0], [args[1]]);
1061 | },
1062 | codeSample: (url, ...args) => {
1063 | return web3TraceTemplate(
1064 | 'trace_rawTransaction',
1065 | 'parityTraceRawTx',
1066 | [args[0], [args[1]]],
1067 | ['null', 'null'],
1068 | 'trace',
1069 | url
1070 | );
1071 | },
1072 | args: [
1073 | {
1074 | type: 'textarea',
1075 | description: 'Raw transaction data.',
1076 | placeholder:
1077 | 'i.e. 0xf86a8086d55698372431831e848094f0109fc8df283027b6285cc889f5aa624eac1f55843b9aca008025a009ebb6ca057a0535d6186462bc0b465b561c94a295bdb0621fc19208ab149a9ca0440ffd775ce91a833ab410777204d5341a6f9fa91216a6f3ee2c051fea6a0428',
1078 | },
1079 | {
1080 | type: 'textfield',
1081 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
1082 | placeholder: 'i.e. vmTrace',
1083 | },
1084 | ],
1085 | },
1086 | trace_replayBlockTransactions: {
1087 | exec: (provider, proto, ...args) => {
1088 | provider.extend({
1089 | methods: [
1090 | {
1091 | name: 'parityTraceBlockTx',
1092 | call: 'trace_replayBlockTransactions',
1093 | params: 2,
1094 | inputFormatter: [provider.utils.numberToHex, null],
1095 | },
1096 | ],
1097 | });
1098 | return provider.parityTraceBlockTx(args[0], [args[1]]);
1099 | },
1100 | codeSample: (url, ...args) => {
1101 | return web3TraceTemplate(
1102 | 'trace_replayBlockTransactions',
1103 | 'parityTraceBlockTx',
1104 | [args[0], [args[1]]],
1105 | ['web3.utils.numberToHex', 'null'],
1106 | 'trace',
1107 | url
1108 | );
1109 | },
1110 | args: [
1111 | {
1112 | type: 'textarea',
1113 | description: 'Integer of block number only',
1114 | placeholder: 'i.e. 10708846',
1115 | },
1116 | {
1117 | type: 'textfield',
1118 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
1119 | placeholder: 'i.e. vmTrace',
1120 | },
1121 | ],
1122 | },
1123 | trace_replayTransaction: {
1124 | exec: (provider, proto, ...args) => {
1125 | provider.extend({
1126 | methods: [
1127 | {
1128 | name: 'parityTraceReplayTx',
1129 | call: 'trace_replayTransaction',
1130 | params: 2,
1131 | inputFormatter: [null, null],
1132 | },
1133 | ],
1134 | });
1135 | return provider.parityTraceReplayTx(args[0], [args[1]]);
1136 | },
1137 | codeSample: (url, ...args) => {
1138 | return web3TraceTemplate(
1139 | 'trace_replayTransaction',
1140 | 'parityTraceReplayTx',
1141 | [args[0], [args[1]]],
1142 | ['null', 'null'],
1143 | 'trace',
1144 | url
1145 | );
1146 | },
1147 | args: [
1148 | {
1149 | type: 'textarea',
1150 | description: 'Hash of a transaction to get trace for',
1151 | placeholder:
1152 | 'i.e. 0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f',
1153 | },
1154 | {
1155 | type: 'textfield',
1156 | description: 'Type of trace, one of: `vmTrace`, `trace`, `stateDiff`',
1157 | placeholder: 'i.e. vmTrace',
1158 | },
1159 | ],
1160 | },
1161 | trace_filter: {
1162 | exec: (provider, proto, ...args) => {
1163 | const filter = {
1164 | ...(args[2] && { fromAddress: [args[2]] }),
1165 | ...(args[3] && { toAddress: [args[3]] }),
1166 | ...(args[4] && { after: args[4] }),
1167 | ...(args[5] && { count: args[5] }),
1168 | };
1169 | filter.fromBlock = args[0] ? args[0] : 'latest';
1170 | filter.toBlock = args[1] ? args[1] : 'latest';
1171 |
1172 | provider.extend({
1173 | methods: [
1174 | {
1175 | name: 'parityTraceFilter',
1176 | call: 'trace_filter',
1177 | params: 1,
1178 | inputFormatter: [null],
1179 | },
1180 | ],
1181 | });
1182 | return provider.parityTraceFilter(filter);
1183 | },
1184 | codeSample: (url, ...args) => {
1185 | return `const Web3 = require("web3");
1186 | // OR import Web3 from 'web3';
1187 |
1188 | // HTTP version
1189 | (async () => {
1190 | const web3 = new Web3('${url}');
1191 | web3.extend({
1192 | methods: [
1193 | {
1194 | name: 'parityTraceFilter',
1195 | call: 'trace_filter',
1196 | params: 1,
1197 | inputFormatter: [null],
1198 | },
1199 | ],
1200 | });
1201 | const trace = await web3.parityTraceFilter({
1202 | "fromBlock": "${args[0] || 'latest'}",
1203 | "toBlock": "${args[1] || 'latest'}",${
1204 | args[2] ? '\n\t"fromAddress": [' + args[2] + '],' : ''
1205 | }${args[3] ? '\n\t"toAddress": [' + args[3] + '],' : ''}${
1206 | args[4] ? '\n\t"after": ' + args[3] + ',' : ''
1207 | }${args[4] ? '\n\t"count": ' + args[4] + ',' : ''}
1208 | });
1209 | console.log(trace);
1210 | })()
1211 | `;
1212 | },
1213 | args: [
1214 | {
1215 | type: 'textfield',
1216 | description:
1217 | 'fromBlock: Hex block number, or the string "latest", "earliest" or "pending"',
1218 | placeholder: 'i.e. 0xA37D49',
1219 | },
1220 | {
1221 | type: 'textfield',
1222 | description:
1223 | 'toBlock: Hex block number, or the string "latest", "earliest" or "pending"',
1224 | placeholder: 'i.e. 0xA37E63',
1225 | },
1226 | {
1227 | type: 'textarea',
1228 | description:
1229 | 'fromAddress: (optional) Contract address or a list of addresses from which logs should originate.',
1230 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
1231 | },
1232 | {
1233 | type: 'textarea',
1234 | description:
1235 | 'toAddress: (optional) Contract address or a list of addresses to which logs should terminate.',
1236 | placeholder: 'i.e. 0x19624ffa41fe26744e74fdbba77bef967a222d4c',
1237 | },
1238 | {
1239 | type: 'textfield',
1240 | description:
1241 | 'topics: (optional) The offset trace number as an integer.',
1242 | placeholder: 'i.e. 1000',
1243 | },
1244 | {
1245 | type: 'textfield',
1246 | description:
1247 | 'topics: (optional) The number of traces to display in a batch as an integer.',
1248 | placeholder: 'i.e. 10',
1249 | },
1250 | ],
1251 | },
1252 | trace_call: {
1253 | exec: (provider, proto, ...args) => {
1254 | let [
1255 | traceType,
1256 | block,
1257 | from,
1258 | value,
1259 | contract,
1260 | abi,
1261 | method,
1262 | ...rest
1263 | ] = args;
1264 | const data = provider.eth.abi.encodeFunctionCall(
1265 | JSON.parse(abi)[0],
1266 | rest
1267 | );
1268 | if (value === '') value = null;
1269 | if (from === '') from = null;
1270 | const transaction = {
1271 | from,
1272 | to: contract,
1273 | value,
1274 | data,
1275 | };
1276 | provider.extend({
1277 | methods: [
1278 | {
1279 | name: 'parityTraceCall',
1280 | call: 'trace_call',
1281 | params: 3,
1282 | inputFormatter: [null, null, null],
1283 | },
1284 | ],
1285 | });
1286 | return provider.parityTraceCall(
1287 | transaction,
1288 | traceType.split(', '),
1289 | block
1290 | );
1291 | },
1292 | codeSample: (url, ...args) => {
1293 | const [traceType, block, ...rest] = args;
1294 | return contractTraceTemplate(url, [
1295 | JSON.stringify(traceType.split(', ')),
1296 | JSON.stringify(block),
1297 | ...rest,
1298 | ]);
1299 | },
1300 | args: [
1301 | {
1302 | type: 'textfield',
1303 | description:
1304 | 'Type of trace, one or more of: `vmTrace`, `trace`, `stateDiff`',
1305 | placeholder: 'i.e. vmTrace, trace',
1306 | },
1307 | {
1308 | type: 'textfield',
1309 | description:
1310 | 'Hex block number, or the string "latest", "earliest" or "pending"',
1311 | placeholder: 'i.e. latest or pending',
1312 | },
1313 | {
1314 | type: 'textarea',
1315 | description:
1316 | 'address: (optional) The address the transaction is sent from',
1317 | placeholder: 'i.e. 0x19624ffa41f...',
1318 | },
1319 | {
1320 | type: 'textfield',
1321 | description:
1322 | 'value: (optional) Integer formatted as a hex string of the value sent with this transaction',
1323 | placeholder: 'i.e. 0x19624ffa41f...',
1324 | },
1325 | {
1326 | type: 'textarea',
1327 | description: 'Address of contract',
1328 | placeholder: 'i.e. 0x91b51c173a4...',
1329 | },
1330 | {
1331 | type: 'textarea',
1332 | description: 'Contract ABI (URL or single function object)',
1333 | placeholder:
1334 | 'i.e. [{"inputs":[{"name":"chainId...\nOR\nhttps://raw.githubusercontent.com/.../build/contracts/ERC20.json',
1335 | },
1336 | {
1337 | type: 'dropdown',
1338 | description: 'Function name (READ only)',
1339 | },
1340 | ],
1341 | },
1342 | };
1343 |
1344 | export default Web3JSCalls;
1345 |
--------------------------------------------------------------------------------
/src/helpers/web3Config.js:
--------------------------------------------------------------------------------
1 | import * as calls from './libs';
2 |
3 | const Web3RpcCalls = {
4 | web3_clientVersion: {
5 | description: 'Returns the current client version.',
6 | web3: calls.web3.default.web3_clientVersion,
7 | ethers: calls.ethers.default.web3_clientVersion,
8 | },
9 | web3_sha3: {
10 | description:
11 | 'Returns Keccak-256 (not the standardized SHA3-256) of the given data.',
12 | web3: calls.web3.default.web3_sha3,
13 | ethers: calls.ethers.default.web3_sha3,
14 | },
15 | net_version: {
16 | description: 'Returns the current network id.',
17 | web3: calls.web3.default.net_version,
18 | ethers: calls.ethers.default.net_version,
19 | },
20 | net_listening: {
21 | description:
22 | 'Returns `true` if client is actively listening for network connections.',
23 | web3: calls.web3.default.net_listening,
24 | ethers: calls.ethers.default.net_listening,
25 | },
26 | net_peerCount: {
27 | description: 'Returns number of peers currently connected to the client.',
28 | web3: calls.web3.default.net_peerCount,
29 | ethers: calls.ethers.default.net_peerCount,
30 | },
31 | eth_protocolVersion: {
32 | description: 'Returns the current ethereum protocol version.',
33 | web3: calls.web3.default.eth_protocolVersion,
34 | ethers: calls.ethers.default.eth_protocolVersion,
35 | },
36 | eth_syncing: {
37 | description: 'Returns an object with data about the sync status or false.',
38 | web3: calls.web3.default.eth_syncing,
39 | ethers: calls.ethers.default.eth_syncing,
40 | },
41 | eth_coinbase: {
42 | description: 'Returns the client coinbase address.',
43 | web3: calls.web3.default.eth_coinbase,
44 | ethers: calls.ethers.default.eth_coinbase,
45 | },
46 | eth_mining: {
47 | description: 'Returns `true` if client is actively mining new blocks.',
48 | web3: calls.web3.default.eth_mining,
49 | ethers: calls.ethers.default.eth_mining,
50 | },
51 | eth_hashrate: {
52 | description:
53 | 'Returns the number of hashes per second that the node is mining with.',
54 | web3: calls.web3.default.eth_hashrate,
55 | ethers: calls.ethers.default.eth_hashrate,
56 | },
57 | eth_gasPrice: {
58 | description: 'Returns the current price per gas in wei.',
59 | web3: calls.web3.default.eth_gasPrice,
60 | ethers: calls.ethers.default.eth_gasPrice,
61 | },
62 | eth_accounts: {
63 | description: 'Returns a list of addresses owned by client.',
64 | web3: calls.web3.default.eth_accounts,
65 | ethers: calls.ethers.default.eth_accounts,
66 | },
67 | eth_blockNumber: {
68 | description: 'Returns the number of most recent block.',
69 | web3: calls.web3.default.eth_blockNumber,
70 | ethers: calls.ethers.default.eth_blockNumber,
71 | },
72 | eth_getBalance: {
73 | description: 'Returns the balance of the account of given address.',
74 | web3: calls.web3.default.eth_getBalance,
75 | ethers: calls.ethers.default.eth_getBalance,
76 | },
77 | eth_getStorageAt: {
78 | description:
79 | 'Returns the value from a storage position at a given address.',
80 | web3: calls.web3.default.eth_getStorageAt,
81 | ethers: calls.ethers.default.eth_getStorageAt,
82 | },
83 | eth_getTransactionCount: {
84 | description: 'Returns the number of transactions sent from an address.',
85 | web3: calls.web3.default.eth_getTransactionCount,
86 | ethers: calls.ethers.default.eth_getTransactionCount,
87 | },
88 | eth_getBlockTransactionCountByHash: {
89 | description:
90 | 'Returns the number of transactions in a block from a block matching the given block hash.',
91 | web3: calls.web3.default.eth_getBlockTransactionCountByHash,
92 | ethers: calls.ethers.default.eth_getBlockTransactionCountByHash,
93 | },
94 | eth_getBlockTransactionCountByNumber: {
95 | description:
96 | 'Returns the number of transactions in a block matching the given block number.',
97 | web3: calls.web3.default.eth_getBlockTransactionCountByNumber,
98 | ethers: calls.ethers.default.eth_getBlockTransactionCountByNumber,
99 | },
100 | eth_getUncleCountByBlockHash: {
101 | description:
102 | 'Returns the number of uncles in a block from a block matching the given block hash.',
103 | web3: calls.web3.default.eth_getUncleCountByBlockHash,
104 | ethers: calls.ethers.default.eth_getUncleCountByBlockHash,
105 | },
106 | eth_getUncleCountByBlockNumber: {
107 | description:
108 | 'Returns the number of uncles in a block from a block matching the given block number.',
109 | web3: calls.web3.default.eth_getUncleCountByBlockNumber,
110 | ethers: calls.ethers.default.eth_getUncleCountByBlockNumber,
111 | },
112 | eth_getCode: {
113 | description: 'Returns code at a given address.',
114 | web3: calls.web3.default.eth_getCode,
115 | ethers: calls.ethers.default.eth_getCode,
116 | },
117 | eth_sign: {
118 | disabled: true,
119 | description: '🚫 This method is not supported in EtherFlow!',
120 | web3: calls.web3.default.eth_sign,
121 | ethers: calls.ethers.default.eth_sign,
122 | },
123 | eth_signTransaction: {
124 | disabled: true,
125 | description: '🚫 This method is not supported in EtherFlow!',
126 | web3: calls.web3.default.eth_signTransaction,
127 | ethers: calls.ethers.default.eth_signTransaction,
128 | },
129 | eth_sendTransaction: {
130 | disabled: true,
131 | description: '🚫 This method is not supported in EtherFlow!',
132 | web3: calls.web3.default.eth_sendTransaction,
133 | ethers: calls.ethers.default.eth_sendTransaction,
134 | },
135 | eth_sendRawTransaction: {
136 | description:
137 | 'Creates new message call transaction or a contract creation for signed transactions.',
138 | web3: calls.web3.default.eth_sendRawTransaction,
139 | ethers: calls.ethers.default.eth_sendRawTransaction,
140 | },
141 | eth_call: {
142 | description: 'Call any read-only function on a deployed contract',
143 | web3: calls.web3.default.eth_call,
144 | ethers: calls.ethers.default.eth_call,
145 | },
146 | eth_estimateGas: {
147 | disabled: true,
148 | description: '🚫 This method is not YET supported in EtherFlow!',
149 | web3: calls.web3.default.eth_estimateGas,
150 | ethers: calls.ethers.default.eth_estimateGas,
151 | },
152 | eth_getBlockByHash: {
153 | description: 'Returns information about a block by hash.',
154 | web3: calls.web3.default.eth_getBlockByHash,
155 | ethers: calls.ethers.default.eth_getBlockByHash,
156 | },
157 | eth_getBlockByNumber: {
158 | description: 'Returns information about a block by block number.',
159 | web3: calls.web3.default.eth_getBlockByNumber,
160 | ethers: calls.ethers.default.eth_getBlockByNumber,
161 | },
162 | eth_getTransactionByHash: {
163 | description:
164 | 'Returns the information about a transaction requested by transaction hash.',
165 | web3: calls.web3.default.eth_getTransactionByHash,
166 | ethers: calls.ethers.default.eth_getTransactionByHash,
167 | },
168 | eth_getTransactionByBlockHashAndIndex: {
169 | description:
170 | 'Returns information about a transaction by block hash and transaction index position.',
171 | web3: calls.web3.default.eth_getTransactionByBlockHashAndIndex,
172 | ethers: calls.ethers.default.eth_getTransactionByBlockHashAndIndex,
173 | },
174 | eth_getTransactionByBlockNumberAndIndex: {
175 | description:
176 | 'Returns information about a transaction by block number and transaction index position.',
177 | web3: calls.web3.default.eth_getTransactionByBlockNumberAndIndex,
178 | ethers: calls.ethers.default.eth_getTransactionByBlockNumberAndIndex,
179 | },
180 | eth_getTransactionReceipt: {
181 | description: 'Returns the receipt of a transaction by transaction hash.',
182 | web3: calls.web3.default.eth_getTransactionReceipt,
183 | ethers: calls.ethers.default.eth_getTransactionReceipt,
184 | },
185 | eth_getUncleByBlockHashAndIndex: {
186 | description:
187 | 'Returns information about a uncle of a block by hash and uncle index position.',
188 | web3: calls.web3.default.eth_getUncleByBlockHashAndIndex,
189 | ethers: calls.ethers.default.eth_getUncleByBlockHashAndIndex,
190 | },
191 | eth_getUncleByBlockNumberAndIndex: {
192 | description:
193 | 'Returns information about a uncle of a block by number and uncle index position.',
194 | web3: calls.web3.default.eth_getUncleByBlockNumberAndIndex,
195 | ethers: calls.ethers.default.eth_getUncleByBlockNumberAndIndex,
196 | },
197 | eth_getCompilers: {
198 | description: 'Returns a list of available compilers in the client.',
199 | web3: calls.web3.default.eth_getCompilers,
200 | ethers: calls.ethers.default.eth_getCompilers,
201 | },
202 | eth_compileSolidity: {
203 | description: 'Returns compiled solidity code + ABI.',
204 | web3: calls.web3.default.eth_compileSolidity,
205 | ethers: calls.ethers.default.eth_compileSolidity,
206 | },
207 | eth_compileSerpent: {
208 | description: 'Returns compiled serpent code.',
209 | web3: calls.web3.default.eth_compileSerpent,
210 | ethers: calls.ethers.default.eth_compileSerpent,
211 | },
212 | eth_newFilter: {
213 | description:
214 | 'Creates a filter object, based on filter options, to notify when the state changes (logs). The resulting value from the filter is immediately returned using `eth_getFilterChanges`.',
215 | web3: calls.web3.default.eth_newFilter,
216 | ethers: calls.ethers.default.eth_newFilter,
217 | },
218 | eth_newBlockFilter: {
219 | description:
220 | 'Creates a filter in the node, to notify when a new block arrives. The resulting value from the filter is immediately returned using `eth_getFilterChanges`.',
221 | web3: calls.web3.default.eth_newBlockFilter,
222 | ethers: calls.ethers.default.eth_newBlockFilter,
223 | },
224 | eth_newPendingTransactionFilter: {
225 | description:
226 | 'Creates a filter in the node, to notify when new pending transactions arrive. The resulting value from the filter is immediately returned using `eth_getFilterChanges`.',
227 | web3: calls.web3.default.eth_newPendingTransactionFilter,
228 | ethers: calls.ethers.default.eth_newPendingTransactionFilter,
229 | },
230 | eth_uninstallFilter: {
231 | disabled: true,
232 | description: '🚫 This method is not YET supported in EtherFlow!',
233 | web3: calls.web3.default.eth_uninstallFilter,
234 | ethers: calls.ethers.default.eth_uninstallFilter,
235 | },
236 | eth_getFilterChanges: {
237 | disabled: true,
238 | description:
239 | 'This method is covered by eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.',
240 | web3: calls.web3.default.eth_getFilterChanges,
241 | ethers: calls.ethers.default.eth_getFilterChanges,
242 | },
243 | eth_getFilterLogs: {
244 | disabled: true,
245 | description:
246 | 'This method is covered by eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.',
247 | web3: calls.web3.default.eth_getFilterLogs,
248 | ethers: calls.ethers.default.eth_getFilterLogs,
249 | },
250 | eth_getLogs: {
251 | disabled: true,
252 | description:
253 | 'This method is covered by eth_newFilter, eth_newBlockFilter and eth_newPendingTransactionFilter.',
254 | web3: calls.web3.default.eth_getLogs,
255 | ethers: calls.ethers.default.eth_getLogs,
256 | },
257 | eth_getWork: {
258 | description:
259 | 'Returns the hash of the current block, the seedHash, and the boundary condition to be met (“target”).',
260 | web3: calls.web3.default.eth_getWork,
261 | ethers: calls.ethers.default.eth_getWork,
262 | },
263 | trace_block: {
264 | description:
265 | 'Returns traces created at given block (OpenEthereum or Parity only).',
266 | web3: calls.web3.default.trace_block,
267 | ethers: calls.ethers.default.trace_block,
268 | },
269 | trace_transaction: {
270 | description:
271 | 'Returns all traces of given transaction (OpenEthereum or Parity only).',
272 | web3: calls.web3.default.trace_transaction,
273 | ethers: calls.ethers.default.trace_transaction,
274 | },
275 | trace_get: {
276 | description:
277 | 'Returns trace at given position (OpenEthereum or Parity only).',
278 | web3: calls.web3.default.trace_get,
279 | ethers: calls.ethers.default.trace_get,
280 | },
281 | trace_rawTransaction: {
282 | description:
283 | 'Traces a call to `eth_sendRawTransaction` without making the call, returning the traces.',
284 | web3: calls.web3.default.trace_rawTransaction,
285 | ethers: calls.ethers.default.trace_rawTransaction,
286 | },
287 | trace_replayBlockTransactions: {
288 | description:
289 | 'Replays all transactions in a block returning the requested traces for each transaction.',
290 | web3: calls.web3.default.trace_replayBlockTransactions,
291 | ethers: calls.ethers.default.trace_replayBlockTransactions,
292 | },
293 | trace_replayTransaction: {
294 | description: 'Replays a transaction, returning the traces.',
295 | web3: calls.web3.default.trace_replayTransaction,
296 | ethers: calls.ethers.default.trace_replayTransaction,
297 | },
298 | trace_filter: {
299 | description: 'Returns traces matching given filter.',
300 | web3: calls.web3.default.trace_filter,
301 | ethers: calls.ethers.default.trace_filter,
302 | },
303 | trace_call: {
304 | description:
305 | 'Executes the given call and returns a number of possible traces for it.',
306 | web3: calls.web3.default.trace_call,
307 | ethers: calls.ethers.default.trace_call,
308 | },
309 | };
310 |
311 | export default Web3RpcCalls;
312 |
--------------------------------------------------------------------------------
/src/helpers/web3State.js:
--------------------------------------------------------------------------------
1 | import { ethers } from 'ethers';
2 |
3 | const web3State = async (url) => {
4 | if (!url) {
5 | return {
6 | web3Version: 'Unknown',
7 | lastBlock: 0,
8 | wssConnects: null,
9 | httpConnects: null,
10 | };
11 | }
12 |
13 | // try WSS connection
14 | let sockConnect, httpConnect, blockNum, version;
15 | try {
16 | const sock = new WebSocket(url);
17 | sock.onopen = () => sock.send('test');
18 | const provider = new ethers.providers.WebSocketProvider(url);
19 | blockNum = await provider.getBlockNumber();
20 | version = await provider.send('web3_clientVersion');
21 | sockConnect = true;
22 | } catch (e) {
23 | sockConnect = false;
24 | }
25 | // try HTTP connection
26 | try {
27 | fetch(url)
28 | .then(() => (httpConnect = true))
29 | .catch(() => (httpConnect = false));
30 | const provider = new ethers.providers.JsonRpcProvider(url);
31 | blockNum = await provider.getBlockNumber();
32 | version = await provider.send('web3_clientVersion');
33 | httpConnect = true;
34 | } catch (e) {
35 | httpConnect = false;
36 | }
37 |
38 | return {
39 | web3Version: `${version?.split('/')[0].replace('/', '')} ${
40 | (version?.split('/')[1] || version?.split('//')[1])?.split('-')[0]
41 | }`,
42 | lastBlock: blockNum,
43 | wssConnects: sockConnect,
44 | httpConnects: httpConnect,
45 | };
46 | };
47 |
48 | export default web3State;
49 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {
4 | CodeSampleContainer,
5 | LogsContainer,
6 | MethodCallContainer,
7 | StatusBarContainer,
8 | NavBarContainer,
9 | Web3MenuContainer,
10 | SponsoredAdContainer,
11 | } from './containers';
12 | import { AppProvider } from './context';
13 | import { Router } from '@reach/router';
14 |
15 | import './tailwind.output.css';
16 |
17 | const Wrapper = () => (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 |
35 | const App = () => (
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | );
44 |
45 | ReactDOM.render( , document.querySelector('#root'));
46 |
--------------------------------------------------------------------------------
/src/tailwind.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: [require("@tailwindcss/ui")],
3 | };
4 |
--------------------------------------------------------------------------------