Merge pull request #9160 from MetaMask/Version-v8.0.7
Version v8.0.7 RCfeature/default_network_editable
commit
1a5218ce8e
@ -1,20 +1,16 @@ |
||||
import { getBackgroundMetaMetricState } from '../../../ui/app/selectors' |
||||
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util' |
||||
|
||||
const inDevelopment = process.env.NODE_ENV === 'development' |
||||
export default function backgroundMetaMetricsEvent (metaMaskState, eventData) { |
||||
|
||||
const METAMETRICS_TRACKING_URL = inDevelopment |
||||
? 'http://www.metamask.io/metametrics' |
||||
: 'http://www.metamask.io/metametrics-prod' |
||||
eventData.eventOpts['category'] = 'Background' |
||||
|
||||
export default function backEndMetaMetricsEvent (metaMaskState, eventData) { |
||||
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState }) |
||||
|
||||
if (stateEventData.participateInMetaMetrics) { |
||||
sendMetaMetricsEvent({ |
||||
...stateEventData, |
||||
...eventData, |
||||
url: METAMETRICS_TRACKING_URL + '/backend', |
||||
currentPath: '/background', |
||||
}) |
||||
} |
||||
} |
@ -0,0 +1,32 @@ |
||||
/** |
||||
* Returns a middleware that implements the following RPC methods: |
||||
* - metamask_logInjectedWeb3Usage |
||||
* |
||||
* @param {Object} opts - The middleware options |
||||
* @param {string} opts.origin - The origin for the middleware stack |
||||
* @param {Function} opts.sendMetrics - A function for sending a metrics event |
||||
* @returns {(req: any, res: any, next: Function, end: Function) => void} |
||||
*/ |
||||
export default function createMethodMiddleware ({ origin, sendMetrics }) { |
||||
return function methodMiddleware (req, res, next, end) { |
||||
switch (req.method) { |
||||
|
||||
case 'metamask_logInjectedWeb3Usage': |
||||
|
||||
const { action, name } = req.params[0] |
||||
|
||||
sendMetrics({ |
||||
action, |
||||
name, |
||||
customVariables: { origin }, |
||||
}) |
||||
|
||||
res.result = true |
||||
break |
||||
|
||||
default: |
||||
return next() |
||||
} |
||||
return end() |
||||
} |
||||
} |
@ -1,13 +0,0 @@ |
||||
#!/usr/bin/env bash |
||||
|
||||
set -e |
||||
set -u |
||||
set -o pipefail |
||||
|
||||
export PATH="$PATH:./node_modules/.bin" |
||||
|
||||
concurrently --kill-others \ |
||||
--names 'dapp,e2e' \ |
||||
--prefix '[{time}][{name}]' \ |
||||
'node development/static-server.js test/web3 --port 8080' \ |
||||
'sleep 5 && mocha test/e2e/web3.spec' |
@ -1,288 +0,0 @@ |
||||
const assert = require('assert') |
||||
const webdriver = require('selenium-webdriver') |
||||
|
||||
const { By } = webdriver |
||||
const { |
||||
regularDelayMs, |
||||
largeDelayMs, |
||||
} = require('./helpers') |
||||
const { buildWebDriver } = require('./webdriver') |
||||
const enLocaleMessages = require('../../app/_locales/en/messages.json') |
||||
|
||||
describe('Using MetaMask with an existing account', function () { |
||||
let driver |
||||
|
||||
const testSeedPhrase = 'forum vessel pink push lonely enact gentle tail admit parrot grunt dress' |
||||
|
||||
const button = async (x) => { |
||||
const buttoncheck = x |
||||
await buttoncheck.click() |
||||
await driver.delay(largeDelayMs) |
||||
const [results] = await driver.findElements(By.css('#results')) |
||||
const resulttext = await results.getText() |
||||
const parsedData = JSON.parse(resulttext) |
||||
|
||||
return (parsedData) |
||||
|
||||
} |
||||
|
||||
this.timeout(0) |
||||
this.bail(true) |
||||
|
||||
before(async function () { |
||||
const result = await buildWebDriver() |
||||
driver = result.driver |
||||
}) |
||||
|
||||
afterEach(async function () { |
||||
if (process.env.SELENIUM_BROWSER === 'chrome') { |
||||
const errors = await driver.checkBrowserForConsoleErrors(driver) |
||||
if (errors.length) { |
||||
const errorReports = errors.map((err) => err.message) |
||||
const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}` |
||||
console.error(new Error(errorMessage)) |
||||
} |
||||
} |
||||
if (this.currentTest.state === 'failed') { |
||||
await driver.verboseReportOnFailure(this.currentTest.title) |
||||
} |
||||
}) |
||||
|
||||
after(async function () { |
||||
await driver.quit() |
||||
}) |
||||
|
||||
describe('First time flow starting from an existing seed phrase', function () { |
||||
it('clicks the continue button on the welcome screen', async function () { |
||||
await driver.findElement(By.css('.welcome-page__header')) |
||||
await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.getStarted.message}')]`)) |
||||
await driver.delay(largeDelayMs) |
||||
}) |
||||
|
||||
it('clicks the "Import Wallet" option', async function () { |
||||
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import wallet')]`)) |
||||
await driver.delay(largeDelayMs) |
||||
}) |
||||
|
||||
it('clicks the "No thanks" option on the metametrics opt-in screen', async function () { |
||||
await driver.clickElement(By.css('.btn-default')) |
||||
await driver.delay(largeDelayMs) |
||||
}) |
||||
|
||||
it('imports a seed phrase', async function () { |
||||
const [seedTextArea] = await driver.findElements(By.css('input[placeholder="Paste seed phrase from clipboard"]')) |
||||
await seedTextArea.sendKeys(testSeedPhrase) |
||||
await driver.delay(regularDelayMs) |
||||
|
||||
const [password] = await driver.findElements(By.id('password')) |
||||
await password.sendKeys('correct horse battery staple') |
||||
const [confirmPassword] = await driver.findElements(By.id('confirm-password')) |
||||
confirmPassword.sendKeys('correct horse battery staple') |
||||
|
||||
await driver.clickElement(By.css('.first-time-flow__terms')) |
||||
|
||||
await driver.clickElement(By.xpath(`//button[contains(text(), 'Import')]`)) |
||||
await driver.delay(regularDelayMs) |
||||
}) |
||||
|
||||
it('clicks through the success screen', async function () { |
||||
await driver.findElement(By.xpath(`//div[contains(text(), 'Congratulations')]`)) |
||||
await driver.clickElement(By.xpath(`//button[contains(text(), '${enLocaleMessages.endOfFlowMessage10.message}')]`)) |
||||
await driver.delay(regularDelayMs) |
||||
}) |
||||
}) |
||||
|
||||
|
||||
describe('opens dapp', function () { |
||||
|
||||
it('switches to mainnet', async function () { |
||||
await driver.clickElement(By.css('.network-name')) |
||||
await driver.delay(regularDelayMs) |
||||
|
||||
await driver.clickElement(By.xpath(`//span[contains(text(), 'Main Ethereum Network')]`)) |
||||
await driver.delay(largeDelayMs * 2) |
||||
}) |
||||
|
||||
it('connects to dapp', async function () { |
||||
await driver.openNewPage('http://127.0.0.1:8080/') |
||||
await driver.delay(regularDelayMs) |
||||
|
||||
await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) |
||||
|
||||
await driver.delay(regularDelayMs) |
||||
|
||||
await driver.waitUntilXWindowHandles(3) |
||||
const windowHandles = await driver.getAllWindowHandles() |
||||
|
||||
const extension = windowHandles[0] |
||||
const popup = await driver.switchToWindowWithTitle('MetaMask Notification', windowHandles) |
||||
const dapp = windowHandles.find((handle) => handle !== extension && handle !== popup) |
||||
|
||||
await driver.delay(regularDelayMs) |
||||
await driver.clickElement(By.xpath(`//button[contains(text(), 'Connect')]`)) |
||||
|
||||
await driver.switchToWindow(dapp) |
||||
await driver.delay(regularDelayMs) |
||||
}) |
||||
}) |
||||
|
||||
describe('testing web3 methods', function () { |
||||
|
||||
|
||||
it('testing hexa methods', async function () { |
||||
|
||||
|
||||
const List = await driver.findClickableElements(By.className('hexaNumberMethods')) |
||||
|
||||
for (let i = 0; i < List.length; i++) { |
||||
try { |
||||
|
||||
const parsedData = await button(List[i]) |
||||
console.log(parsedData) |
||||
const result = parseInt(parsedData.result, 16) |
||||
|
||||
assert.equal((typeof result === 'number'), true) |
||||
await driver.delay(regularDelayMs) |
||||
} catch (err) { |
||||
console.log(err) |
||||
assert(false) |
||||
|
||||
} |
||||
} |
||||
}) |
||||
|
||||
it('testing booleanMethods', async function () { |
||||
|
||||
const List = await driver.findClickableElement(By.className('booleanMethods')) |
||||
|
||||
for (let i = 0; i < List.length; i++) { |
||||
try { |
||||
|
||||
const parsedData = await button(List[i]) |
||||
console.log(parsedData) |
||||
const result = parsedData.result |
||||
|
||||
assert.equal(result, false) |
||||
await driver.delay(regularDelayMs) |
||||
} catch (err) { |
||||
console.log(err) |
||||
assert(false) |
||||
|
||||
|
||||
} |
||||
} |
||||
|
||||
}) |
||||
|
||||
it('testing transactionMethods', async function () { |
||||
|
||||
const List = await driver.findClickableElement(By.className('transactionMethods')) |
||||
|
||||
for (let i = 0; i < List.length; i++) { |
||||
try { |
||||
|
||||
const parsedData = await button(List[i]) |
||||
|
||||
console.log(parsedData.result.blockHash) |
||||
|
||||
const result = [] |
||||
result.push(parseInt(parsedData.result.blockHash, 16)) |
||||
result.push(parseInt(parsedData.result.blockNumber, 16)) |
||||
result.push(parseInt(parsedData.result.gas, 16)) |
||||
result.push(parseInt(parsedData.result.gasPrice, 16)) |
||||
result.push(parseInt(parsedData.result.hash, 16)) |
||||
result.push(parseInt(parsedData.result.input, 16)) |
||||
result.push(parseInt(parsedData.result.nonce, 16)) |
||||
result.push(parseInt(parsedData.result.r, 16)) |
||||
result.push(parseInt(parsedData.result.s, 16)) |
||||
result.push(parseInt(parsedData.result.v, 16)) |
||||
result.push(parseInt(parsedData.result.to, 16)) |
||||
result.push(parseInt(parsedData.result.value, 16)) |
||||
|
||||
|
||||
result.forEach((value) => { |
||||
assert.equal((typeof value === 'number'), true) |
||||
}) |
||||
|
||||
|
||||
} catch (err) { |
||||
|
||||
console.log(err) |
||||
assert(false) |
||||
|
||||
|
||||
} |
||||
} |
||||
|
||||
}) |
||||
|
||||
it('testing blockMethods', async function () { |
||||
|
||||
const List = await driver.findClickableElement(By.className('blockMethods')) |
||||
|
||||
for (let i = 0; i < List.length; i++) { |
||||
try { |
||||
|
||||
const parsedData = await button(List[i]) |
||||
console.log(JSON.stringify(parsedData) + i) |
||||
|
||||
console.log(parsedData.result.parentHash) |
||||
|
||||
const result = parseInt(parsedData.result.parentHash, 16) |
||||
|
||||
assert.equal((typeof result === 'number'), true) |
||||
await driver.delay(regularDelayMs) |
||||
} catch (err) { |
||||
|
||||
console.log(err) |
||||
assert(false) |
||||
|
||||
|
||||
} |
||||
} |
||||
}) |
||||
|
||||
it('testing methods', async function () { |
||||
|
||||
const List = await driver.findClickableElement(By.className('methods')) |
||||
let parsedData |
||||
let result |
||||
|
||||
for (let i = 0; i < List.length; i++) { |
||||
try { |
||||
|
||||
if (i === 2) { |
||||
|
||||
parsedData = await button(List[i]) |
||||
console.log(parsedData.result.blockHash) |
||||
|
||||
result = parseInt(parsedData.result.blockHash, 16) |
||||
|
||||
assert.equal((typeof result === 'number' || (result === 0)), true) |
||||
await driver.delay(regularDelayMs) |
||||
} else { |
||||
parsedData = await button(List[i]) |
||||
console.log(parsedData.result) |
||||
|
||||
result = parseInt(parsedData.result, 16) |
||||
|
||||
assert.equal((typeof result === 'number' || (result === 0)), true) |
||||
await driver.delay(regularDelayMs) |
||||
} |
||||
|
||||
|
||||
} catch (err) { |
||||
|
||||
console.log(err) |
||||
assert(false) |
||||
|
||||
|
||||
} |
||||
} |
||||
}) |
||||
|
||||
|
||||
}) |
||||
|
||||
|
||||
}) |
@ -1,105 +0,0 @@ |
||||
<html> |
||||
<head> |
||||
<title>Web3 Test Dapp</title> |
||||
</head> |
||||
<body> |
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div style="display: flex; font-size: 1.25rem;">hexaNumberMethods</div> |
||||
<div style="display: flex;"> |
||||
<button id="eth_blockNumber" class="hexaNumberMethods">eth_blockNumber</button> |
||||
|
||||
<button id="eth_gasPrice" class="hexaNumberMethods">eth_gasPrice</button> |
||||
<button id="eth_newBlockFilter" class="hexaNumberMethods">eth_newBlockFilter</button> |
||||
<button id="eth_newPendingTransactionFilter" class="hexaNumberMethods"> |
||||
eth_newPendingTransactionFilter |
||||
</button> |
||||
<button id="eth_getUncleCountByBlockHash" class="hexaNumberMethods"> |
||||
eth_getUncleCountByBlockHash |
||||
</button> |
||||
<button id="eth_getBlockTransactionCountByHash" class="hexaNumberMethods"> |
||||
getBlockTransactionCountByHash |
||||
</button> |
||||
</div> |
||||
<div style="display: flex ;"> |
||||
<button id="eth_getTransactionCount" class="hexaNumberMethods">eth_getTransactionCount</button> |
||||
<button id="eth_getBalance" class="hexaNumberMethods">eth_getBalance</button> |
||||
<button id="eth_estimateGas" class="hexaNumberMethods">eth_estimateGas</button> |
||||
</div> |
||||
<div style="display: flex ;"> |
||||
|
||||
<button id="eth_getUncleCountByBlockNumber" class="hexaNumberMethods"> |
||||
eth_getUncleCountByBlockNumber |
||||
</button> |
||||
<button id='eth_getBlockTransactionCountByNumber' class="hexaNumberMethods"> |
||||
eth_getBlockTransactionCountByNumber |
||||
</button> |
||||
<button id="eth_protocolVersion" class="hexaNumberMethods">eth_protocolVersion</button> |
||||
|
||||
<button id="eth_getCode" class="hexaNumberMethods">eth_getCode</button> |
||||
</div> |
||||
</div> |
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div style="display: flex; font-size: 1.25rem;">booleanMethods</div> |
||||
<div style="display: flex ;"> |
||||
<button id="eth_uninstallFilter" class = 'booleanMethods'>eth_uninstallFilter</button> |
||||
<button id="eth_mining" class = 'booleanMethods'>eth_mining</button> |
||||
<button id="eth_syncing" class = 'booleanMethods'>eth_syncing</button> |
||||
</div> |
||||
</div> |
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div style="display: flex; font-size: 1.25rem;" >transactionMethods</div> |
||||
<div style="display: flex ;"> |
||||
<button id="eth_getTransactionByHash" class='transactionMethods'>eth_getTransactionByHash</button> |
||||
<button id="eth_getTransactionByBlockHashAndIndex" class = 'transactionMethods'> |
||||
eth_getTransactionByBlockHashAndIndex |
||||
</button> |
||||
<button id="eth_getTransactionByBlockNumberAndIndex" class="transactionMethods"> |
||||
eth_getTransactionByBlockNumberAndIndex |
||||
</button> |
||||
|
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div style="display: flex; font-size: 1.25rem;">blockMethods</div> |
||||
|
||||
<div style="display: flex ;"> |
||||
|
||||
|
||||
<button id="eth_getUncleByBlockHashAndIndex" class="blockMethods"> |
||||
eth_getUncleByBlockHashAndIndex |
||||
</button> |
||||
<button id="eth_getBlockByHash" class="blockMethods">eth_getBlockByHash</button> |
||||
</div> |
||||
<div style="display: flex ;"> |
||||
<button id="eth_getBlockByNumber" class="blockMethods">eth_getBlockByNumber</button> |
||||
|
||||
|
||||
</div> |
||||
</div> |
||||
|
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div style="display: flex; font-size: 1.25rem;">Methods</div> |
||||
<div style="display: flex ;"> |
||||
<button id="eth_call" class = 'methods'>eth_call</button> |
||||
<button id="eth_getStorageAt" class="methods">eth_getStorageAt</button> |
||||
<button id="eth_getTransactionReceipt" class="methods"> |
||||
eth_getTransactionReceipt |
||||
</button> |
||||
|
||||
</div> |
||||
</div> |
||||
<div style="display: flex; flex-flow: column;"> |
||||
<div id='results'></div> |
||||
</div> |
||||
|
||||
|
||||
|
||||
|
||||
</div> |
||||
<script src="schema.js"></script> |
||||
<script src="web3.js"></script> |
||||
|
||||
</body> |
||||
</html> |
@ -1,209 +0,0 @@ |
||||
/* eslint no-unused-vars: 0 */ |
||||
|
||||
const params = { |
||||
// diffrent params used in the methods
|
||||
param: [], |
||||
blockHashParams: '0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35', |
||||
filterParams: ['0xfe704947a3cd3ca12541458a4321c869'], |
||||
transactionHashParams: [ |
||||
'0xbb3a336e3f823ec18197f1e13ee875700f08f03e2cab75f0d0b118dabb44cba0', |
||||
], |
||||
blockHashAndIndexParams: [ |
||||
'0xb3b20624f8f0f86eb50dd04688409e5cea4bd02d700bf6e79e9384d47d6a5a35', |
||||
'0x0', |
||||
], |
||||
uncleByBlockNumberAndIndexParams: ['0x29c', '0x0'], |
||||
blockParameterParams: '0x5bad55', |
||||
data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', |
||||
addressParams: '0xc94770007dda54cF92009BFF0dE90c06F603a09f', |
||||
getStorageAtParams: [ |
||||
'0x295a70b2de5e3953354a6a8344e616ed314d7251', |
||||
'0x6661e9d6d8b923d5bbaab1b96e1dd51ff6ea2a93520fdc9eb75d059238b8c5e9', |
||||
'0x65a8db', |
||||
], |
||||
getCodeParams: ['0x06012c8cf97bead5deae237070f9587f8e7a266d', '0x65a8db'], |
||||
estimateTransaction: { |
||||
from: '0xb60e8dd61c5d32be8058bb8eb970870f07233155', |
||||
to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567', |
||||
gas: '0x76c0', |
||||
gasPrice: '0x9184e72a000', |
||||
value: '0x9184e72a', |
||||
data: '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', |
||||
}, |
||||
filterGetLogs: [{ 'blockHash': '0x7c5a35e9cb3e8ae0e221ab470abae9d446c3a5626ce6689fc777dcffcab52c70', 'topics': ['0x241ea03ca20251805084d27d4440371c34a0b85ff108f6bb5611248f73818b80'] }], |
||||
block: { |
||||
__required: [], |
||||
number: 'Q', |
||||
hash: 'D32', |
||||
parentHash: 'D32', |
||||
nonce: 'D', |
||||
sha3Uncles: 'D', |
||||
logsBloom: 'D', |
||||
transactionsRoot: 'D', |
||||
stateRoot: 'D', |
||||
receiptsRoot: 'D', |
||||
miner: 'D', |
||||
difficulty: 'Q', |
||||
totalDifficulty: 'Q', |
||||
extraData: 'D', |
||||
size: 'Q', |
||||
gasLimit: 'Q', |
||||
gasUsed: 'Q', |
||||
timestamp: 'Q', |
||||
transactions: ['DATA|Transaction'], |
||||
uncles: ['D'], |
||||
}, |
||||
transaction: { |
||||
__required: [], |
||||
hash: 'D32', |
||||
nonce: 'Q', |
||||
blockHash: 'D32', |
||||
blockNumber: 'Q', |
||||
transactionIndex: 'Q', |
||||
from: 'D20', |
||||
to: 'D20', |
||||
value: 'Q', |
||||
gasPrice: 'Q', |
||||
gas: 'Q', |
||||
input: 'D', |
||||
}, |
||||
receipt: { |
||||
__required: [], |
||||
transactionHash: 'D32', |
||||
transactionIndex: 'Q', |
||||
blockHash: 'D32', |
||||
blockNumber: 'Q', |
||||
cumulativeGasUsed: 'Q', |
||||
gasUsed: 'Q', |
||||
contractAddress: 'D20', |
||||
logs: ['FilterChange'], |
||||
}, |
||||
|
||||
filterChange: { |
||||
__required: [], |
||||
removed: 'B', |
||||
logIndex: 'Q', |
||||
transactionIndex: 'Q', |
||||
transactionHash: 'D32', |
||||
blockHash: 'D32', |
||||
blockNumber: 'Q', |
||||
address: 'D20', |
||||
data: 'Array|DATA', |
||||
topics: ['D'], |
||||
}, |
||||
} |
||||
|
||||
const methods = { |
||||
hexaNumberMethods: { |
||||
// these are the methods which have output in the form of hexa decimal numbers
|
||||
eth_blockNumber: ['eth_blockNumber', params.param, 'Q'], |
||||
eth_gasPrice: ['eth_gasPrice', params.param, 'Q'], |
||||
eth_newBlockFilter: ['eth_newBlockFilter', params.param, 'Q'], |
||||
eth_newPendingTransactionFilter: [ |
||||
'eth_newPendingTransactionFilter', |
||||
params.param, |
||||
'Q', |
||||
], |
||||
eth_getUncleCountByBlockHash: [ |
||||
'eth_getUncleCountByBlockHash', |
||||
[params.blockHashParams], |
||||
'Q', |
||||
1, |
||||
], |
||||
eth_getBlockTransactionCountByHash: [ |
||||
'eth_getBlockTransactionCountByHash', |
||||
[params.blockHashParams], |
||||
'Q', |
||||
1, |
||||
], |
||||
eth_getTransactionCount: [ |
||||
'eth_getTransactionCount', |
||||
[params.addressParams, params.blockParameterParams], |
||||
'Q', |
||||
1, |
||||
2, |
||||
], |
||||
eth_getBalance: ['eth_getBalance', [params.addressParams, 'latest'], 'Q', 1, 2], |
||||
eth_estimateGas: ['eth_estimateGas', [params.estimateTransaction], 'Q', 1], |
||||
eth_getUncleCountByBlockNumber: [ |
||||
'eth_getUncleCountByBlockNumber', |
||||
[params.blockParameterParams], |
||||
'Q', |
||||
1, |
||||
], |
||||
eth_getBlockTransactionCountByNumber: [ |
||||
'eth_getBlockTransactionCountByNumber', |
||||
['latest'], |
||||
'Q', |
||||
1, |
||||
], |
||||
eth_protocolVersion: ['eth_protocolVersion', params.param, 'S'], |
||||
eth_getCode: ['eth_getCode', params.getCodeParams, 'D', 1, 2], |
||||
}, |
||||
booleanMethods: { |
||||
// these are the methods which have output in the form of boolean
|
||||
eth_uninstallFilter: ['eth_uninstallFilter', params.filterParams, 'B', 1], |
||||
eth_mining: ['eth_mining', params.param, 'B'], |
||||
eth_syncing: ['eth_syncing', params.param, 'B|EthSyncing'], |
||||
}, |
||||
transactionMethods: { |
||||
// these are the methods which have output in the form of transaction object
|
||||
eth_getTransactionByHash: [ |
||||
'eth_getTransactionByHash', |
||||
params.transactionHashParams, |
||||
params.transaction, |
||||
1, |
||||
], |
||||
eth_getTransactionByBlockHashAndIndex: [ |
||||
'eth_getTransactionByBlockHashAndIndex', |
||||
params.blockHashAndIndexParams, |
||||
params.transaction, |
||||
2, |
||||
], |
||||
eth_getTransactionByBlockNumberAndIndex: [ |
||||
'eth_getTransactionByBlockNumberAndIndex', |
||||
[params.blockParameterParams, '0x0'], |
||||
params.transaction, |
||||
2, |
||||
], |
||||
|
||||
}, |
||||
blockMethods: { |
||||
// these are the methods which have output in the form of a block
|
||||
|
||||
eth_getUncleByBlockNumberAndIndex: [ |
||||
'eth_getUncleByBlockNumberAndIndex', |
||||
params.uncleByBlockNumberAndIndexParams, |
||||
params.block, |
||||
2, |
||||
], |
||||
eth_getBlockByHash: [ |
||||
'eth_getBlockByHash', |
||||
[params.params, false], |
||||
params.block, |
||||
2, |
||||
], |
||||
eth_getBlockByNumber: [ |
||||
'eth_getBlockByNumber', |
||||
[params.blockParameterParams, false], |
||||
params.block, |
||||
2, |
||||
], |
||||
}, |
||||
|
||||
methods: { |
||||
// these are the methods which have output in the form of bytes data
|
||||
|
||||
eth_call: ['eth_call', [params.estimateTransaction, 'latest'], 'D', 1, 2], |
||||
eth_getStorageAt: ['eth_getStorageAt', params.getStorageAtParams, 'D', 2, 2], |
||||
eth_getTransactionReceipt: [ |
||||
'eth_getTransactionReceipt', |
||||
params.transactionHashParams, |
||||
params.receipt, |
||||
1, |
||||
], |
||||
|
||||
}, |
||||
|
||||
} |
||||
|
@ -1,34 +0,0 @@ |
||||
/* eslint no-undef: 0 */ |
||||
|
||||
const json = methods |
||||
|
||||
web3.currentProvider.enable().then(() => { |
||||
|
||||
Object.keys(json).forEach((methodGroupKey) => { |
||||
|
||||
console.log(methodGroupKey) |
||||
const methodGroup = json[methodGroupKey] |
||||
console.log(methodGroup) |
||||
Object.keys(methodGroup).forEach((methodKey) => { |
||||
|
||||
const methodButton = document.getElementById(methodKey) |
||||
methodButton.addEventListener('click', () => { |
||||
|
||||
window.ethereum.sendAsync({ |
||||
method: methodKey, |
||||
params: methodGroup[methodKey][1], |
||||
}, (err, result) => { |
||||
if (err) { |
||||
console.log(err) |
||||
console.log(methodKey) |
||||
} else { |
||||
document.getElementById('results').innerHTML = JSON.stringify(result) |
||||
} |
||||
}) |
||||
}) |
||||
|
||||
}) |
||||
|
||||
}) |
||||
}) |
||||
|
@ -1,52 +1,47 @@ |
||||
import React, { Component } from 'react' |
||||
import React from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
import { exportAsFile } from '../../../helpers/utils/util' |
||||
import Copy from '../icon/copy-icon.component' |
||||
import { useI18nContext } from '../../../hooks/useI18nContext' |
||||
import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard' |
||||
|
||||
class ExportTextContainer extends Component { |
||||
render () { |
||||
const { text = '' } = this.props |
||||
const { t } = this.context |
||||
function ExportTextContainer ({ text = '' }) { |
||||
const t = useI18nContext() |
||||
const [copied, handleCopy] = useCopyToClipboard() |
||||
|
||||
return ( |
||||
<div className="export-text-container"> |
||||
<div className="export-text-container__text-container"> |
||||
<div className="export-text-container__text notranslate"> |
||||
{text} |
||||
return ( |
||||
<div className="export-text-container"> |
||||
<div className="export-text-container__text-container"> |
||||
<div className="export-text-container__text notranslate">{text}</div> |
||||
</div> |
||||
<div className="export-text-container__buttons-container"> |
||||
<div |
||||
className="export-text-container__button export-text-container__button--copy" |
||||
onClick={() => { |
||||
handleCopy(text) |
||||
}} |
||||
> |
||||
<Copy size={17} color="#3098DC" /> |
||||
<div className="export-text-container__button-text"> |
||||
{copied ? t('copiedExclamation') : t('copyToClipboard')} |
||||
</div> |
||||
</div> |
||||
<div className="export-text-container__buttons-container"> |
||||
<div |
||||
className="export-text-container__button export-text-container__button--copy" |
||||
onClick={() => copyToClipboard(text)} |
||||
> |
||||
<Copy size={17} color="#3098DC" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('copyToClipboard')} |
||||
</div> |
||||
</div> |
||||
<div |
||||
className="export-text-container__button" |
||||
onClick={() => exportAsFile('', text)} |
||||
> |
||||
<img src="images/download.svg" alt="" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('saveAsCsvFile')} |
||||
</div> |
||||
<div |
||||
className="export-text-container__button" |
||||
onClick={() => exportAsFile('', text)} |
||||
> |
||||
<img src="images/download.svg" alt="" /> |
||||
<div className="export-text-container__button-text"> |
||||
{t('saveAsCsvFile')} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
ExportTextContainer.propTypes = { |
||||
text: PropTypes.string, |
||||
} |
||||
|
||||
ExportTextContainer.contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
|
||||
export default ExportTextContainer |
||||
export default React.memo(ExportTextContainer) |
||||
|
@ -0,0 +1,28 @@ |
||||
import { useState, useCallback } from 'react' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
import { useTimeout } from './useTimeout' |
||||
|
||||
/** |
||||
* useCopyToClipboard |
||||
* |
||||
* @param {number} [delay=3000] - delay in ms |
||||
* |
||||
* @return {[boolean, Function]} |
||||
*/ |
||||
const DEFAULT_DELAY = 3000 |
||||
|
||||
export function useCopyToClipboard (delay = DEFAULT_DELAY) { |
||||
const [copied, setCopied] = useState(false) |
||||
const startTimeout = useTimeout(() => setCopied(false), delay, false) |
||||
|
||||
const handleCopy = useCallback( |
||||
(text) => { |
||||
setCopied(true) |
||||
startTimeout() |
||||
copyToClipboard(text) |
||||
}, |
||||
[startTimeout], |
||||
) |
||||
|
||||
return [copied, handleCopy] |
||||
} |
@ -0,0 +1,46 @@ |
||||
import { useState, useEffect, useRef, useCallback } from 'react' |
||||
|
||||
/** |
||||
* useTimeout |
||||
* |
||||
* @param {Function} cb - callback function inside setTimeout |
||||
* @param {number} delay - delay in ms |
||||
* @param {boolean} [immediate] - determines whether the timeout is invoked immediately |
||||
* |
||||
* @return {Function} |
||||
*/ |
||||
export function useTimeout (cb, delay, immediate = true) { |
||||
const saveCb = useRef() |
||||
const [timeoutId, setTimeoutId] = useState(null) |
||||
|
||||
useEffect(() => { |
||||
saveCb.current = cb |
||||
}, [cb]) |
||||
|
||||
useEffect(() => { |
||||
if (timeoutId !== 'start') { |
||||
return |
||||
} |
||||
|
||||
const id = setTimeout(() => { |
||||
saveCb.current() |
||||
}, delay) |
||||
|
||||
setTimeoutId(id) |
||||
|
||||
return () => { |
||||
clearTimeout(timeoutId) |
||||
} |
||||
}, [delay, timeoutId]) |
||||
|
||||
const startTimeout = useCallback(() => { |
||||
clearTimeout(timeoutId) |
||||
setTimeoutId('start') |
||||
}, [timeoutId]) |
||||
|
||||
if (immediate) { |
||||
startTimeout() |
||||
} |
||||
|
||||
return startTimeout |
||||
} |
@ -1,85 +1,102 @@ |
||||
import React, { PureComponent } from 'react' |
||||
import React from 'react' |
||||
import PropTypes from 'prop-types' |
||||
import { Redirect } from 'react-router-dom' |
||||
|
||||
import Identicon from '../../../../components/ui/identicon' |
||||
import Copy from '../../../../components/ui/icon/copy-icon.component' |
||||
import Button from '../../../../components/ui/button/button.component' |
||||
import copyToClipboard from 'copy-to-clipboard' |
||||
|
||||
import Tooltip from '../../../../components/ui/tooltip-v2' |
||||
import { useI18nContext } from '../../../../hooks/useI18nContext' |
||||
import { useCopyToClipboard } from '../../../../hooks/useCopyToClipboard' |
||||
|
||||
function quadSplit (address) { |
||||
return '0x ' + address.slice(2).match(/.{1,4}/g).join(' ') |
||||
return ( |
||||
'0x ' + |
||||
address |
||||
.slice(2) |
||||
.match(/.{1,4}/g) |
||||
.join(' ') |
||||
) |
||||
} |
||||
|
||||
export default class ViewContact extends PureComponent { |
||||
|
||||
static contextTypes = { |
||||
t: PropTypes.func, |
||||
} |
||||
function ViewContact ({ |
||||
history, |
||||
name, |
||||
address, |
||||
checkSummedAddress, |
||||
memo, |
||||
editRoute, |
||||
listRoute, |
||||
}) { |
||||
const t = useI18nContext() |
||||
const [copied, handleCopy] = useCopyToClipboard() |
||||
|
||||
static propTypes = { |
||||
name: PropTypes.string, |
||||
address: PropTypes.string, |
||||
history: PropTypes.object, |
||||
checkSummedAddress: PropTypes.string, |
||||
memo: PropTypes.string, |
||||
editRoute: PropTypes.string, |
||||
listRoute: PropTypes.string.isRequired, |
||||
if (!address) { |
||||
return <Redirect to={{ pathname: listRoute }} /> |
||||
} |
||||
|
||||
render () { |
||||
const { t } = this.context |
||||
const { history, name, address, checkSummedAddress, memo, editRoute, listRoute } = this.props |
||||
|
||||
if (!address) { |
||||
return <Redirect to={{ pathname: listRoute }} /> |
||||
} |
||||
|
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__header address-book__header"> |
||||
<Identicon address={address} diameter={60} /> |
||||
<div className="address-book__header__name">{ name }</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<Button |
||||
type="secondary" |
||||
onClick={() => { |
||||
history.push(`${editRoute}/${address}`) |
||||
}} |
||||
> |
||||
{t('edit')} |
||||
</Button> |
||||
return ( |
||||
<div className="settings-page__content-row"> |
||||
<div className="settings-page__content-item"> |
||||
<div className="settings-page__header address-book__header"> |
||||
<Identicon address={address} diameter={60} /> |
||||
<div className="address-book__header__name">{name}</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<Button |
||||
type="secondary" |
||||
onClick={() => { |
||||
history.push(`${editRoute}/${address}`) |
||||
}} |
||||
> |
||||
{t('edit')} |
||||
</Button> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label"> |
||||
{t('ethereumPublicAddress')} |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label"> |
||||
{ t('ethereumPublicAddress') } |
||||
<div className="address-book__view-contact__group__value"> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{quadSplit(checkSummedAddress)} |
||||
</div> |
||||
<div className="address-book__view-contact__group__value"> |
||||
<div |
||||
className="address-book__view-contact__group__static-address" |
||||
> |
||||
{ quadSplit(checkSummedAddress) } |
||||
</div> |
||||
<Tooltip |
||||
position="bottom" |
||||
title={copied ? t('copiedExclamation') : t('copyToClipboard')} |
||||
> |
||||
<button |
||||
className="address-book__view-contact__group__static-address--copy-icon" |
||||
onClick={() => copyToClipboard(checkSummedAddress)} |
||||
onClick={() => { |
||||
handleCopy(checkSummedAddress) |
||||
}} |
||||
> |
||||
<Copy size={20} color="#3098DC" /> |
||||
</button> |
||||
</div> |
||||
</Tooltip> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label--capitalized"> |
||||
{ t('memo') } |
||||
</div> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{ memo } |
||||
</div> |
||||
</div> |
||||
<div className="address-book__view-contact__group"> |
||||
<div className="address-book__view-contact__group__label--capitalized"> |
||||
{t('memo')} |
||||
</div> |
||||
<div className="address-book__view-contact__group__static-address"> |
||||
{memo} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
||||
</div> |
||||
) |
||||
} |
||||
|
||||
ViewContact.propTypes = { |
||||
name: PropTypes.string, |
||||
address: PropTypes.string, |
||||
history: PropTypes.object, |
||||
checkSummedAddress: PropTypes.string, |
||||
memo: PropTypes.string, |
||||
editRoute: PropTypes.string, |
||||
listRoute: PropTypes.string.isRequired, |
||||
} |
||||
|
||||
export default React.memo(ViewContact) |
||||
|
Loading…
Reference in new issue