Configured Prettier (#60)
* Apply prettier fixes for UI * Integrate prettier into linting. Remove duplicate .prettierrc. * Common .eslintignore. Removed reduntant prettier check * Apply prettier on ui script * Correct linting * Duplicate plugin * Common plugin
This commit is contained in:
parent
19a3314c42
commit
6dc4fc6acd
@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
submodules
|
||||
coverage
|
||||
lib
|
22
.eslintrc
Normal file
22
.eslintrc
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"extends": [
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"plugins": ["prettier"],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"arrow-body-style": "off",
|
||||
"func-names": "off",
|
||||
"no-await-in-loop": "off",
|
||||
"no-console": "off",
|
||||
"no-else-return": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"no-shadow": "off",
|
||||
"no-use-before-define": ["error", { "functions": false }],
|
||||
"import/no-dynamic-require": "off",
|
||||
"prefer-template": "off",
|
||||
"no-underscore-dangle": "off"
|
||||
}
|
||||
}
|
@ -1,21 +1,11 @@
|
||||
{
|
||||
"plugins": ["node", "prettier"],
|
||||
"plugins": ["node"],
|
||||
"extends": [
|
||||
"plugin:node/recommended",
|
||||
"airbnb-base",
|
||||
"plugin:prettier/recommended"
|
||||
"../.eslintrc"
|
||||
],
|
||||
"rules": {
|
||||
"prettier/prettier": "error",
|
||||
"arrow-body-style": "off",
|
||||
"no-await-in-loop": "off",
|
||||
"no-console": "off",
|
||||
"no-else-return": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"no-shadow": "off",
|
||||
"prefer-template": "off",
|
||||
"no-use-before-define": "off",
|
||||
"no-underscore-dangle": "off"
|
||||
"no-use-before-define": "off"
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||
"lint:fix": "eslint . --fix"
|
||||
},
|
||||
"author": "",
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"extends": "../.eslintrc",
|
||||
"globals": {
|
||||
"describe": false,
|
||||
"it": false
|
||||
}
|
||||
}
|
@ -2,20 +2,8 @@
|
||||
"extends": [
|
||||
"plugin:node/recommended",
|
||||
"airbnb-base",
|
||||
"plugin:prettier/recommended"
|
||||
"../.eslintrc"
|
||||
],
|
||||
"plugins": ["node"],
|
||||
"rules": {
|
||||
"arrow-body-style": "off",
|
||||
"func-names": "off",
|
||||
"no-await-in-loop": "off",
|
||||
"no-console": "off",
|
||||
"no-else-return": "off",
|
||||
"no-param-reassign": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-restricted-syntax": "off",
|
||||
"no-shadow": "off",
|
||||
"no-use-before-define": ["error", { "functions": false }],
|
||||
"import/no-dynamic-require": "off"
|
||||
}
|
||||
"rules": {}
|
||||
}
|
||||
|
@ -1,5 +0,0 @@
|
||||
{
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||
"watcher:signature-request": "./scripts/start-worker.sh watcher signature-request-watcher",
|
||||
"watcher:collected-signatures": "./scripts/start-worker.sh watcher collected-signatures-watcher",
|
||||
"watcher:affirmation-request": "./scripts/start-worker.sh watcher affirmation-request-watcher",
|
||||
|
@ -1,4 +0,0 @@
|
||||
node_modules
|
||||
submodules
|
||||
coverage
|
||||
e2e-script
|
@ -1,5 +1,11 @@
|
||||
{
|
||||
"extends": "react-app",
|
||||
"extends": [
|
||||
"react-app",
|
||||
"../.eslintrc"
|
||||
],
|
||||
"rules": {
|
||||
"no-use-before-define": "off"
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"legacyDecorators": true
|
||||
|
@ -1,10 +1,3 @@
|
||||
const {
|
||||
addDecoratorsLegacy,
|
||||
disableEsLint,
|
||||
override
|
||||
} = require("customize-cra");
|
||||
const { addDecoratorsLegacy, disableEsLint, override } = require('customize-cra')
|
||||
|
||||
module.exports = override(
|
||||
addDecoratorsLegacy(),
|
||||
disableEsLint()
|
||||
);
|
||||
module.exports = override(addDecoratorsLegacy(), disableEsLint())
|
||||
|
@ -32,7 +32,7 @@
|
||||
"web3-utils": "1.0.0-beta.30"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"lint": "eslint . --ignore-path ../.eslintignore",
|
||||
"select-css-theme": "node scripts/selectTheme.js",
|
||||
"build-css": "node-sass-chokidar src/assets/stylesheets -o src/assets/stylesheets --output-style=compressed -m application*.css",
|
||||
"watch-css": "nodemon -e scss -x \"npm run build-css\"",
|
||||
|
@ -1,17 +1,17 @@
|
||||
const path = require('path');
|
||||
const path = require('path')
|
||||
require('dotenv').config({
|
||||
path: path.resolve(__dirname, '..', '.env')
|
||||
});
|
||||
const fs = require('fs');
|
||||
path: path.resolve(__dirname, '..', '.env')
|
||||
})
|
||||
const fs = require('fs')
|
||||
|
||||
const stylePath = path.resolve(__dirname, '..', 'src', 'assets', 'stylesheets');
|
||||
const destinationFilename = 'application.css';
|
||||
let filename;
|
||||
const stylePath = path.resolve(__dirname, '..', 'src', 'assets', 'stylesheets')
|
||||
const destinationFilename = 'application.css'
|
||||
let filename
|
||||
|
||||
if (process.env.APP_STYLES === 'classic') {
|
||||
filename = 'application.classic.css'
|
||||
filename = 'application.classic.css'
|
||||
} else {
|
||||
filename = 'application.core.css'
|
||||
filename = 'application.core.css'
|
||||
}
|
||||
|
||||
fs.copyFileSync(path.resolve(stylePath, filename), path.resolve(stylePath, destinationFilename));
|
||||
fs.copyFileSync(path.resolve(stylePath, filename), path.resolve(stylePath, destinationFilename))
|
||||
|
@ -1,7 +1,16 @@
|
||||
import React from 'react';
|
||||
import { Header, Bridge, RelayEvents, Footer, SweetAlert, Loading, StatusPage, StatisticsPage } from './components';
|
||||
import React from 'react'
|
||||
import {
|
||||
Header,
|
||||
Bridge,
|
||||
RelayEvents,
|
||||
Footer,
|
||||
SweetAlert,
|
||||
Loading,
|
||||
StatusPage,
|
||||
StatisticsPage
|
||||
} from './components'
|
||||
import { Route } from 'react-router-dom'
|
||||
import './assets/stylesheets/application.css';
|
||||
import './assets/stylesheets/application.css'
|
||||
import { Disclaimer } from './components'
|
||||
import { ModalContainer } from './components'
|
||||
import { NoWallet } from './components'
|
||||
@ -16,43 +25,40 @@ export class App extends React.Component {
|
||||
componentDidMount() {
|
||||
const disclaimerDisplayed = getItem(DISCLAIMER_KEY)
|
||||
|
||||
if(!disclaimerDisplayed) {
|
||||
if (!disclaimerDisplayed) {
|
||||
this.setState({ showDisclaimer: true })
|
||||
}
|
||||
}
|
||||
|
||||
closeDisclaimer = () => {
|
||||
setItem(DISCLAIMER_KEY, true)
|
||||
this.setState({showDisclaimer: false})
|
||||
this.setState({ showDisclaimer: false })
|
||||
}
|
||||
|
||||
toggleMobileMenu = () => {
|
||||
this.setState(prevState => ({ showMobileMenu: !prevState.showMobileMenu}))
|
||||
this.setState(prevState => ({ showMobileMenu: !prevState.showMobileMenu }))
|
||||
}
|
||||
|
||||
render() {
|
||||
const { showDisclaimer, showMobileMenu } = this.state
|
||||
return (
|
||||
<div className={showMobileMenu ? 'mobile-menu-is-open' : ''}>
|
||||
<Route component={Loading}/>
|
||||
<Route component={SweetAlert}/>
|
||||
<Route render={() =>
|
||||
<Header
|
||||
onMenuToggle={this.toggleMobileMenu}
|
||||
showMobileMenu={showMobileMenu}
|
||||
/>
|
||||
}/>
|
||||
<Route component={Loading} />
|
||||
<Route component={SweetAlert} />
|
||||
<Route
|
||||
render={() => (
|
||||
<Header onMenuToggle={this.toggleMobileMenu} showMobileMenu={showMobileMenu} />
|
||||
)}
|
||||
/>
|
||||
<div className="app-container">
|
||||
{showMobileMenu && <Route render={() => <div className="mobile-menu-open"/>}/>}
|
||||
<Route exact path="/" component={Bridge}/>
|
||||
<Route exact path="/events" component={RelayEvents}/>
|
||||
<Route exact path="/status" component={StatusPage}/>
|
||||
<Route exact path="/statistics" component={StatisticsPage}/>
|
||||
{showMobileMenu && <Route render={() => <div className="mobile-menu-open" />} />}
|
||||
<Route exact path="/" component={Bridge} />
|
||||
<Route exact path="/events" component={RelayEvents} />
|
||||
<Route exact path="/status" component={StatusPage} />
|
||||
<Route exact path="/statistics" component={StatisticsPage} />
|
||||
</div>
|
||||
<Route component={Footer}/>
|
||||
<ModalContainer
|
||||
showModal={showDisclaimer}
|
||||
>
|
||||
<Route component={Footer} />
|
||||
<ModalContainer showModal={showDisclaimer}>
|
||||
<Disclaimer onConfirmation={this.closeDisclaimer} />
|
||||
</ModalContainer>
|
||||
<NoWallet showModal={!showDisclaimer} />
|
||||
|
@ -2,9 +2,9 @@ import React from 'react'
|
||||
|
||||
export const Authority = ({ address, number, logoIndex }) => (
|
||||
<div className="authority">
|
||||
<span className='authority-number'>{number}</span>
|
||||
<span className="authority-number">{number}</span>
|
||||
<div className="separator" />
|
||||
<div className={`authority-logo authority-logo-${logoIndex}`} />
|
||||
<span className='authority-address'>{address}</span>
|
||||
<span className="authority-address">{address}</span>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import BN from 'bignumber.js'
|
||||
import React from 'react';
|
||||
import React from 'react'
|
||||
import { toHex } from 'web3-utils'
|
||||
import foreignLogoPurple from '../assets/images/logos/logo-poa-20-purple@2x.png'
|
||||
import homeLogoPurple from '../assets/images/logos/logo-poa-sokol-purple@2x.png'
|
||||
@ -12,15 +12,15 @@ import { ModalContainer } from './ModalContainer'
|
||||
import { NetworkDetails } from './NetworkDetails'
|
||||
import { TransferAlert } from './TransferAlert'
|
||||
import { getFeeToApply, validFee } from '../stores/utils/rewardable'
|
||||
import { inject, observer } from "mobx-react";
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { toDecimals } from '../stores/utils/decimals'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class Bridge extends React.Component {
|
||||
state = {
|
||||
reverse: false,
|
||||
amount:'',
|
||||
amount: '',
|
||||
modalData: {},
|
||||
confirmationData: {},
|
||||
showModal: false,
|
||||
@ -36,7 +36,7 @@ export class Bridge extends React.Component {
|
||||
componentDidMount() {
|
||||
const { web3Store } = this.props.RootStore
|
||||
web3Store.getWeb3Promise.then(() => {
|
||||
if(!web3Store.metamaskNet.id || !web3Store.foreignNet.id) {
|
||||
if (!web3Store.metamaskNet.id || !web3Store.foreignNet.id) {
|
||||
this.forceUpdate()
|
||||
} else {
|
||||
const reverse = web3Store.metamaskNet.id.toString() === web3Store.foreignNet.id.toString()
|
||||
@ -61,28 +61,40 @@ export class Bridge extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
async _sendToHome(amount){
|
||||
async _sendToHome(amount) {
|
||||
const { web3Store, homeStore, alertStore, txStore, bridgeMode } = this.props.RootStore
|
||||
const isErcToErcMode = bridgeMode === BRIDGE_MODES.ERC_TO_ERC
|
||||
const { isLessThan, isGreaterThan } = this
|
||||
if(web3Store.metamaskNet.id.toString() !== web3Store.homeNet.id.toString()){
|
||||
swal("Error", `Please switch wallet to ${web3Store.homeNet.name} network`, "error")
|
||||
if (web3Store.metamaskNet.id.toString() !== web3Store.homeNet.id.toString()) {
|
||||
swal('Error', `Please switch wallet to ${web3Store.homeNet.name} network`, 'error')
|
||||
return
|
||||
}
|
||||
if(isLessThan(amount, homeStore.minPerTx)){
|
||||
alertStore.pushError(`The amount is less than current minimum per transaction amount.\nThe minimum per transaction amount is: ${homeStore.minPerTx} ${homeStore.symbol}`)
|
||||
if (isLessThan(amount, homeStore.minPerTx)) {
|
||||
alertStore.pushError(
|
||||
`The amount is less than current minimum per transaction amount.\nThe minimum per transaction amount is: ${
|
||||
homeStore.minPerTx
|
||||
} ${homeStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(isGreaterThan(amount, homeStore.maxPerTx)){
|
||||
alertStore.pushError(`The amount is above current maximum per transaction limit.\nThe maximum per transaction limit is: ${homeStore.maxPerTx} ${homeStore.symbol}`)
|
||||
if (isGreaterThan(amount, homeStore.maxPerTx)) {
|
||||
alertStore.pushError(
|
||||
`The amount is above current maximum per transaction limit.\nThe maximum per transaction limit is: ${
|
||||
homeStore.maxPerTx
|
||||
} ${homeStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(isGreaterThan(amount, homeStore.maxCurrentDeposit)){
|
||||
alertStore.pushError(`The amount is above current daily limit.\nThe max deposit today: ${homeStore.maxCurrentDeposit} ${homeStore.symbol}`)
|
||||
if (isGreaterThan(amount, homeStore.maxCurrentDeposit)) {
|
||||
alertStore.pushError(
|
||||
`The amount is above current daily limit.\nThe max deposit today: ${
|
||||
homeStore.maxCurrentDeposit
|
||||
} ${homeStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(isGreaterThan(amount, homeStore.getDisplayedBalance())){
|
||||
alertStore.pushError("Insufficient balance")
|
||||
if (isGreaterThan(amount, homeStore.getDisplayedBalance())) {
|
||||
alertStore.pushError('Insufficient balance')
|
||||
} else {
|
||||
try {
|
||||
alertStore.setLoading(true)
|
||||
@ -90,12 +102,12 @@ export class Bridge extends React.Component {
|
||||
return txStore.erc677transferAndCall({
|
||||
to: homeStore.HOME_BRIDGE_ADDRESS,
|
||||
from: web3Store.defaultAccount.address,
|
||||
value: toDecimals(amount,homeStore.tokenDecimals),
|
||||
value: toDecimals(amount, homeStore.tokenDecimals),
|
||||
contract: homeStore.tokenContract,
|
||||
tokenAddress: homeStore.tokenAddress
|
||||
})
|
||||
} else {
|
||||
const value = toHex(toDecimals(amount,homeStore.tokenDecimals))
|
||||
const value = toHex(toDecimals(amount, homeStore.tokenDecimals))
|
||||
return txStore.doSend({
|
||||
to: homeStore.HOME_BRIDGE_ADDRESS,
|
||||
from: web3Store.defaultAccount.address,
|
||||
@ -110,28 +122,42 @@ export class Bridge extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
async _sendToForeign(amount){
|
||||
async _sendToForeign(amount) {
|
||||
const { web3Store, foreignStore, alertStore, txStore } = this.props.RootStore
|
||||
const isExternalErc20 = foreignStore.tokenType === ERC_TYPES.ERC20
|
||||
const { isLessThan, isGreaterThan } = this
|
||||
if(web3Store.metamaskNet.id.toString() !== web3Store.foreignNet.id.toString()){
|
||||
swal("Error", `Please switch wallet to ${web3Store.foreignNet.name} network`, "error")
|
||||
if (web3Store.metamaskNet.id.toString() !== web3Store.foreignNet.id.toString()) {
|
||||
swal('Error', `Please switch wallet to ${web3Store.foreignNet.name} network`, 'error')
|
||||
return
|
||||
}
|
||||
if(!isExternalErc20 && isLessThan(amount, foreignStore.minPerTx)){
|
||||
alertStore.pushError(`The amount is less than minimum amount per transaction.\nThe min per transaction is: ${foreignStore.minPerTx} ${foreignStore.symbol}`)
|
||||
if (!isExternalErc20 && isLessThan(amount, foreignStore.minPerTx)) {
|
||||
alertStore.pushError(
|
||||
`The amount is less than minimum amount per transaction.\nThe min per transaction is: ${
|
||||
foreignStore.minPerTx
|
||||
} ${foreignStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(!isExternalErc20 && isGreaterThan(amount, foreignStore.maxPerTx)){
|
||||
alertStore.pushError(`The amount is above maximum amount per transaction.\nThe max per transaction is: ${foreignStore.maxPerTx} ${foreignStore.symbol}`)
|
||||
if (!isExternalErc20 && isGreaterThan(amount, foreignStore.maxPerTx)) {
|
||||
alertStore.pushError(
|
||||
`The amount is above maximum amount per transaction.\nThe max per transaction is: ${
|
||||
foreignStore.maxPerTx
|
||||
} ${foreignStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(!isExternalErc20 && isGreaterThan(amount, foreignStore.maxCurrentDeposit)){
|
||||
alertStore.pushError(`The amount is above current daily limit.\nThe max withdrawal today: ${foreignStore.maxCurrentDeposit} ${foreignStore.symbol}`)
|
||||
if (!isExternalErc20 && isGreaterThan(amount, foreignStore.maxCurrentDeposit)) {
|
||||
alertStore.pushError(
|
||||
`The amount is above current daily limit.\nThe max withdrawal today: ${
|
||||
foreignStore.maxCurrentDeposit
|
||||
} ${foreignStore.symbol}`
|
||||
)
|
||||
return
|
||||
}
|
||||
if(isGreaterThan(amount, foreignStore.balance)){
|
||||
alertStore.pushError(`Insufficient token balance. Your balance is ${foreignStore.balance} ${foreignStore.symbol}`)
|
||||
if (isGreaterThan(amount, foreignStore.balance)) {
|
||||
alertStore.pushError(
|
||||
`Insufficient token balance. Your balance is ${foreignStore.balance} ${foreignStore.symbol}`
|
||||
)
|
||||
} else {
|
||||
try {
|
||||
alertStore.setLoading(true)
|
||||
@ -139,18 +165,18 @@ export class Bridge extends React.Component {
|
||||
return await txStore.erc20transfer({
|
||||
to: foreignStore.FOREIGN_BRIDGE_ADDRESS,
|
||||
from: web3Store.defaultAccount.address,
|
||||
value: toDecimals(amount,foreignStore.tokenDecimals)
|
||||
value: toDecimals(amount, foreignStore.tokenDecimals)
|
||||
})
|
||||
} else {
|
||||
return await txStore.erc677transferAndCall({
|
||||
to: foreignStore.FOREIGN_BRIDGE_ADDRESS,
|
||||
from: web3Store.defaultAccount.address,
|
||||
value: toHex(toDecimals(amount,foreignStore.tokenDecimals)),
|
||||
value: toHex(toDecimals(amount, foreignStore.tokenDecimals)),
|
||||
contract: foreignStore.tokenContract,
|
||||
tokenAddress: foreignStore.tokenAddress
|
||||
})
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -160,19 +186,21 @@ export class Bridge extends React.Component {
|
||||
|
||||
isGreaterThan = (amount, base) => new BN(amount).gt(new BN(base))
|
||||
|
||||
onTransfer = async (e) => {
|
||||
onTransfer = async e => {
|
||||
e.preventDefault()
|
||||
|
||||
const amount = this.state.amount.trim();
|
||||
if(!amount){
|
||||
swal("Error", "Please specify amount", "error")
|
||||
const amount = this.state.amount.trim()
|
||||
if (!amount) {
|
||||
swal('Error', 'Please specify amount', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
const { foreignStore, web3Store, homeStore } = this.props.RootStore
|
||||
|
||||
if((web3Store.metamaskNotSetted && web3Store.metamaskNet.name === '')
|
||||
|| web3Store.defaultAccount.address === undefined) {
|
||||
if (
|
||||
(web3Store.metamaskNotSetted && web3Store.metamaskNet.name === '') ||
|
||||
web3Store.defaultAccount.address === undefined
|
||||
) {
|
||||
web3Store.showInstallMetamaskAlert()
|
||||
return
|
||||
}
|
||||
@ -185,7 +213,7 @@ export class Bridge extends React.Component {
|
||||
let finalAmount = new BN(amount)
|
||||
const feeToApply = getFeeToApply(homeStore.feeManager, foreignStore.feeManager, !reverse)
|
||||
|
||||
if(validFee(feeToApply)) {
|
||||
if (validFee(feeToApply)) {
|
||||
fee = feeToApply.multipliedBy(100)
|
||||
finalAmount = finalAmount.multipliedBy(1 - feeToApply)
|
||||
}
|
||||
@ -201,28 +229,31 @@ export class Bridge extends React.Component {
|
||||
reverse
|
||||
}
|
||||
|
||||
this.setState({ showConfirmation: true, confirmationData})
|
||||
this.setState({ showConfirmation: true, confirmationData })
|
||||
}
|
||||
|
||||
onTransferConfirmation = async () => {
|
||||
const { alertStore } = this.props.RootStore
|
||||
const { reverse } = this.state
|
||||
|
||||
this.setState({showConfirmation: false, confirmationData: {}})
|
||||
const amount = this.state.amount.trim();
|
||||
if(!amount){
|
||||
swal("Error", "Please specify amount", "error")
|
||||
this.setState({ showConfirmation: false, confirmationData: {} })
|
||||
const amount = this.state.amount.trim()
|
||||
if (!amount) {
|
||||
swal('Error', 'Please specify amount', 'error')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
if(reverse){
|
||||
if (reverse) {
|
||||
await this._sendToForeign(amount)
|
||||
} else {
|
||||
await this._sendToHome(amount)
|
||||
}
|
||||
} catch(e) {
|
||||
if(!e.message.includes('not mined within 50 blocks') && !e.message.includes('Failed to subscribe to new newBlockHeaders')) {
|
||||
} catch (e) {
|
||||
if (
|
||||
!e.message.includes('not mined within 50 blocks') &&
|
||||
!e.message.includes('Failed to subscribe to new newBlockHeaders')
|
||||
) {
|
||||
alertStore.setLoading(false)
|
||||
}
|
||||
}
|
||||
@ -231,7 +262,8 @@ export class Bridge extends React.Component {
|
||||
loadHomeDetails = () => {
|
||||
const { web3Store, homeStore, bridgeMode } = this.props.RootStore
|
||||
const isErcToErcMode = bridgeMode === BRIDGE_MODES.ERC_TO_ERC
|
||||
const isExternalErc20 = bridgeMode === BRIDGE_MODES.ERC_TO_ERC || bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE
|
||||
const isExternalErc20 =
|
||||
bridgeMode === BRIDGE_MODES.ERC_TO_ERC || bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE
|
||||
|
||||
const modalData = {
|
||||
isHome: true,
|
||||
@ -284,28 +316,24 @@ export class Bridge extends React.Component {
|
||||
this.setState({ modalData, showModal: true })
|
||||
}
|
||||
|
||||
getNetworkTitle = (networkName) => {
|
||||
|
||||
const index = networkName.indexOf(" ")
|
||||
getNetworkTitle = networkName => {
|
||||
const index = networkName.indexOf(' ')
|
||||
|
||||
if (index === -1) {
|
||||
return networkName
|
||||
}
|
||||
|
||||
return networkName.substring(0, index)
|
||||
|
||||
}
|
||||
|
||||
getNetworkSubTitle = (networkName) => {
|
||||
|
||||
const index = networkName.indexOf(" ")
|
||||
getNetworkSubTitle = networkName => {
|
||||
const index = networkName.indexOf(' ')
|
||||
|
||||
if (index === -1) {
|
||||
return false
|
||||
}
|
||||
|
||||
return networkName.substring(index + 1, networkName.length)
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -313,11 +341,11 @@ export class Bridge extends React.Component {
|
||||
const { reverse, showModal, modalData, showConfirmation, confirmationData } = this.state
|
||||
const formCurrency = reverse ? foreignStore.symbol : homeStore.symbol
|
||||
|
||||
if(showModal && Object.keys(modalData).length !== 0) {
|
||||
if(modalData.isHome && modalData.balance !== homeStore.getDisplayedBalance()) {
|
||||
if (showModal && Object.keys(modalData).length !== 0) {
|
||||
if (modalData.isHome && modalData.balance !== homeStore.getDisplayedBalance()) {
|
||||
modalData.balance = homeStore.getDisplayedBalance()
|
||||
} else if(!modalData.isHome && modalData.balance !== foreignStore.balance) {
|
||||
modalData.balance= foreignStore.balance
|
||||
} else if (!modalData.isHome && modalData.balance !== foreignStore.balance) {
|
||||
modalData.balance = foreignStore.balance
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,13 +354,10 @@ export class Bridge extends React.Component {
|
||||
const foreignNetworkName = this.getNetworkTitle(foreignStore.networkName)
|
||||
const foreignNetworkSubtitle = this.getNetworkSubTitle(foreignStore.networkName)
|
||||
|
||||
return(
|
||||
return (
|
||||
<div className="bridge-container">
|
||||
<div className="bridge">
|
||||
<BridgeAddress
|
||||
isHome={true}
|
||||
reverse={reverse}
|
||||
/>
|
||||
<BridgeAddress isHome={true} reverse={reverse} />
|
||||
<div className="bridge-transfer">
|
||||
<div className="left-image-wrapper">
|
||||
<div className="left-image" />
|
||||
@ -370,23 +395,23 @@ export class Bridge extends React.Component {
|
||||
<div className="right-image" />
|
||||
</div>
|
||||
</div>
|
||||
<BridgeAddress
|
||||
isHome={false}
|
||||
reverse={reverse}
|
||||
/>
|
||||
<BridgeAddress isHome={false} reverse={reverse} />
|
||||
<ModalContainer
|
||||
hideModal={() => {this.setState({showModal: false})}}
|
||||
hideModal={() => {
|
||||
this.setState({ showModal: false })
|
||||
}}
|
||||
showModal={showModal}
|
||||
>
|
||||
<NetworkDetails {...modalData}/>
|
||||
<NetworkDetails {...modalData} />
|
||||
</ModalContainer>
|
||||
<ModalContainer
|
||||
showModal={showConfirmation}
|
||||
>
|
||||
<ModalContainer showModal={showConfirmation}>
|
||||
<TransferAlert
|
||||
onConfirmation={this.onTransferConfirmation}
|
||||
onCancel={() => {this.setState({showConfirmation: false, confirmationData: {}})}}
|
||||
{...confirmationData} />
|
||||
onCancel={() => {
|
||||
this.setState({ showConfirmation: false, confirmationData: {} })
|
||||
}}
|
||||
{...confirmationData}
|
||||
/>
|
||||
</ModalContainer>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,27 +1,30 @@
|
||||
import React from 'react'
|
||||
|
||||
export const BridgeAddress = ({ isHome, reverse }) => {
|
||||
const getAddress = () => isHome ?
|
||||
(<div className="home-address-container" />)
|
||||
:
|
||||
(<div className="foreign-address-container" />)
|
||||
const getAddress = () =>
|
||||
isHome ? (
|
||||
<div className="home-address-container" />
|
||||
) : (
|
||||
<div className="foreign-address-container" />
|
||||
)
|
||||
|
||||
return isHome ?
|
||||
(<div className="bridge-home">
|
||||
return isHome ? (
|
||||
<div className="bridge-home">
|
||||
<div className="bridge-home-container">
|
||||
<div className="home-logo-container">
|
||||
<div className={reverse ? 'foreign-logo' : 'home-logo'} />
|
||||
</div>
|
||||
</div>
|
||||
{getAddress()}
|
||||
</div>)
|
||||
:
|
||||
(<div className="bridge-foreign">
|
||||
</div>
|
||||
) : (
|
||||
<div className="bridge-foreign">
|
||||
{getAddress()}
|
||||
<div className="bridge-foreign-container">
|
||||
<div className="foreign-logo-container">
|
||||
<div className={reverse ? 'home-logo' : 'foreign-logo'} />
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,22 +1,27 @@
|
||||
import React from 'react'
|
||||
|
||||
export const BridgeForm = ({ reverse, currency, onTransfer, onInputChange, displayArrow}) => (
|
||||
<div className={`form-container ${displayArrow ? 'transfer-right' : ''}` }>
|
||||
export const BridgeForm = ({ reverse, currency, onTransfer, onInputChange, displayArrow }) => (
|
||||
<div className={`form-container ${displayArrow ? 'transfer-right' : ''}`}>
|
||||
<form className="bridge-form" onSubmit={onTransfer} autoComplete="off">
|
||||
<div className="bridge-form-controls">
|
||||
<div className="bridge-form-input-container">
|
||||
<input
|
||||
onChange={onInputChange}
|
||||
name='amount'
|
||||
pattern="[0-9]+([.][0-9]{1,18})?"
|
||||
type="text"
|
||||
className="bridge-form-input"
|
||||
id="amount"
|
||||
placeholder="0" />
|
||||
<label htmlFor="amount" className="bridge-form-label">{currency}</label>
|
||||
onChange={onInputChange}
|
||||
name="amount"
|
||||
pattern="[0-9]+([.][0-9]{1,18})?"
|
||||
type="text"
|
||||
className="bridge-form-input"
|
||||
id="amount"
|
||||
placeholder="0"
|
||||
/>
|
||||
<label htmlFor="amount" className="bridge-form-label">
|
||||
{currency}
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" className="bridge-form-button">Transfer</button>
|
||||
<button type="submit" className="bridge-form-button">
|
||||
Transfer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -16,28 +16,37 @@ export const BridgeNetwork = ({
|
||||
? numeral(0).format('0,0.00', Math.floor)
|
||||
: numeral(balance).format('0,0.00', Math.floor)
|
||||
|
||||
const showMore = () => isHome ?
|
||||
(<div className="bridge-network-data" onClick={showModal}>
|
||||
<span className="info-icon info-icon-left"><InfoIcon /></span>
|
||||
<span className="network-show-more">Show More</span>
|
||||
</div>)
|
||||
:
|
||||
(<div className="bridge-network-data" onClick={showModal}>
|
||||
<span className="network-show-more">Show More</span>
|
||||
<span className="info-icon info-icon-right"><InfoIcon /></span>
|
||||
</div>)
|
||||
const showMore = () =>
|
||||
isHome ? (
|
||||
<div className="bridge-network-data" onClick={showModal}>
|
||||
<span className="info-icon info-icon-left">
|
||||
<InfoIcon />
|
||||
</span>
|
||||
<span className="network-show-more">Show More</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="bridge-network-data" onClick={showModal}>
|
||||
<span className="network-show-more">Show More</span>
|
||||
<span className="info-icon info-icon-right">
|
||||
<InfoIcon />
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={`network-container-${containerName}`}>
|
||||
<p className={`${ side ? `text-${side}` : ''}`}>
|
||||
<p className={`${side ? `text-${side}` : ''}`}>
|
||||
<span className="network-title">{networkTitle}</span>
|
||||
{networkSubtitle ? <span className="network-name">{networkSubtitle}</span> : null}
|
||||
</p>
|
||||
<p>
|
||||
<span className="network-basic-label">Balance:</span>
|
||||
<span className="network-balance"> {formattedBalance} {currency}</span>
|
||||
<span className="network-balance">
|
||||
{' '}
|
||||
{formattedBalance} {currency}
|
||||
</span>
|
||||
</p>
|
||||
{showMore()}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -2,13 +2,17 @@ import React from 'react'
|
||||
import numeral from 'numeral'
|
||||
import { DataBlock } from './DataBlock'
|
||||
|
||||
export const BridgeStatistics = ({ users, totalBridged, homeBalance, homeNativeSupplyTitle, foreignSupply, homeSymbol, foreignSymbol }) => (
|
||||
export const BridgeStatistics = ({
|
||||
users,
|
||||
totalBridged,
|
||||
homeBalance,
|
||||
homeNativeSupplyTitle,
|
||||
foreignSupply,
|
||||
homeSymbol,
|
||||
foreignSymbol
|
||||
}) => (
|
||||
<div className="statistics-bridge-data">
|
||||
<DataBlock
|
||||
description="Users"
|
||||
value={numeral(users).format('0,0')}
|
||||
type=''
|
||||
/>
|
||||
<DataBlock description="Users" value={numeral(users).format('0,0')} type="" />
|
||||
<div className="separator" />
|
||||
<DataBlock
|
||||
description={`Total ${foreignSymbol} Bridged`}
|
||||
@ -28,4 +32,4 @@ export const BridgeStatistics = ({ users, totalBridged, homeBalance, homeNativeS
|
||||
type={foreignSymbol}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -2,34 +2,34 @@ import React from 'react'
|
||||
import numeral from 'numeral'
|
||||
import { DataBlock } from './DataBlock'
|
||||
|
||||
export const Configuration = ({ requiredSignatures, authorities, symbol, maxSingleDeposit, maxTotalBalance }) => (
|
||||
export const Configuration = ({
|
||||
requiredSignatures,
|
||||
authorities,
|
||||
symbol,
|
||||
maxSingleDeposit,
|
||||
maxTotalBalance
|
||||
}) => (
|
||||
<div className="status-configuration-data">
|
||||
<DataBlock
|
||||
description="Required Signatures"
|
||||
value={numeral(requiredSignatures).format('0')}
|
||||
type=''
|
||||
type=""
|
||||
/>
|
||||
<div className="separator" />
|
||||
<DataBlock
|
||||
description="Authorities"
|
||||
value={numeral(authorities).format('0')}
|
||||
type=''
|
||||
/>
|
||||
{maxSingleDeposit && maxSingleDeposit !== '0'
|
||||
&& <div className="separator" />
|
||||
&& <DataBlock
|
||||
<DataBlock description="Authorities" value={numeral(authorities).format('0')} type="" />
|
||||
{maxSingleDeposit && maxSingleDeposit !== '0' && <div className="separator" /> && (
|
||||
<DataBlock
|
||||
description="Max Single Deposit"
|
||||
value={numeral(maxSingleDeposit).format('0.00 a', Math.floor)}
|
||||
type={symbol}
|
||||
/>
|
||||
}
|
||||
{maxSingleDeposit && maxSingleDeposit !== '0'
|
||||
&& <div className="separator" />
|
||||
&& <DataBlock
|
||||
)}
|
||||
{maxSingleDeposit && maxSingleDeposit !== '0' && <div className="separator" /> && (
|
||||
<DataBlock
|
||||
description={`Remaining Daily ${symbol} Quota`}
|
||||
value={numeral(maxTotalBalance).format('0.00 a', Math.floor)}
|
||||
type={symbol}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -1,9 +1,8 @@
|
||||
import React from 'react'
|
||||
import { inject, observer } from "mobx-react"
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import numeral from 'numeral'
|
||||
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class DailyQuotaModal extends React.Component {
|
||||
state = {
|
||||
@ -17,11 +16,11 @@ export class DailyQuotaModal extends React.Component {
|
||||
|
||||
getPosition = () => {
|
||||
const offsetsElement = document.getElementsByClassName('header-wallet')
|
||||
if(offsetsElement.length > 0) {
|
||||
const offsets = offsetsElement[0].getBoundingClientRect();
|
||||
const height = offsets.height;
|
||||
const left = offsets.left;
|
||||
this.setState({left, top: height + 20})
|
||||
if (offsetsElement.length > 0) {
|
||||
const offsets = offsetsElement[0].getBoundingClientRect()
|
||||
const height = offsets.height
|
||||
const left = offsets.left
|
||||
this.setState({ left, top: height + 20 })
|
||||
} else {
|
||||
setTimeout(this.getPosition, 100)
|
||||
}
|
||||
@ -38,18 +37,18 @@ export class DailyQuotaModal extends React.Component {
|
||||
const to = isHome ? foreignStore.symbol : homeStore.symbol
|
||||
const networkNameFrom = isHome ? homeStore.networkName : foreignStore.networkName
|
||||
const networkNameTo = isHome ? foreignStore.networkName : homeStore.networkName
|
||||
const description = limit && limit !== '0' ? `${numeral(value).format('0,0.0', Math.floor)} ${from} on ${networkNameFrom + ' '}
|
||||
const description =
|
||||
limit && limit !== '0'
|
||||
? `${numeral(value).format('0,0.0', Math.floor)} ${from} on ${networkNameFrom + ' '}
|
||||
remaining for transfer to ${to + ' '}
|
||||
on ${networkNameTo}`
|
||||
: `No limit configured`
|
||||
: `No limit configured`
|
||||
return (
|
||||
<div className="daily-quota-modal-container">
|
||||
<div className="daily-quota-modal" style={{left, top}}>
|
||||
<div className='modal-container'>
|
||||
<div className="daily-quota-modal" style={{ left, top }}>
|
||||
<div className="modal-container">
|
||||
<span className="daily-quota-title">Daily Quota</span>
|
||||
<span className="daily-quota-description">
|
||||
{description}
|
||||
</span>
|
||||
<span className="daily-quota-description">{description}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4,8 +4,8 @@ export const DataBlock = ({ description, value, type, dataTestid }) => (
|
||||
<div className="datablock-container" data-testid={dataTestid}>
|
||||
<p>
|
||||
<span className="datablock-value">{value}</span>
|
||||
<span className={ type ? "datablock-type" : ""}>{type}</span>
|
||||
<span className={type ? 'datablock-type' : ''}>{type}</span>
|
||||
</p>
|
||||
<p className="datablock-description">{description}</p>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -4,33 +4,45 @@ import disclaimerIcon from '../assets/images/disclaimer-modal/disclaimer@2x.png'
|
||||
export const Disclaimer = ({ onConfirmation }) => (
|
||||
<div className="disclaimer-alert">
|
||||
<div className="image-container">
|
||||
<img className="disclaimer-icon" src={disclaimerIcon} alt="disclaimer icon"/>
|
||||
<img className="disclaimer-icon" src={disclaimerIcon} alt="disclaimer icon" />
|
||||
</div>
|
||||
<div className="alert-container">
|
||||
<span className="disclaimer-title">Welcome to the<br/> TokenBridge UI App Beta+</span>
|
||||
<span className="disclaimer-title">
|
||||
Welcome to the
|
||||
<br /> TokenBridge UI App Beta+
|
||||
</span>
|
||||
<p className="disclaimer-description">
|
||||
We’re launching our TokenBridge and our UI App on a beta-testing basis. While we’ve
|
||||
worked long and hard to develop the core features of the software, we expect that our
|
||||
users may detect bugs and other issues. Help us improve by posting any difficulties to our
|
||||
<a href="https://forum.poa.network/c/support/tokenbridge-support" target="_blank"
|
||||
rel="noopener noreferrer"> support page</a>.
|
||||
<br/>
|
||||
<br/>
|
||||
Use of this app and the TokenBridge is at your own risk. Users may experience
|
||||
unexpected delays, unexpected visual artifacts, unexpected loss of tokens or funds from
|
||||
improper app configuration, or other negative outcomes.
|
||||
<br/>
|
||||
<br/>
|
||||
We’re launching our TokenBridge and our UI App on a beta-testing basis. While we’ve worked
|
||||
long and hard to develop the core features of the software, we expect that our users may
|
||||
detect bugs and other issues. Help us improve by posting any difficulties to our
|
||||
<a
|
||||
href="https://forum.poa.network/c/support/tokenbridge-support"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{' '}
|
||||
support page
|
||||
</a>
|
||||
.
|
||||
<br />
|
||||
<br />
|
||||
Use of this app and the TokenBridge is at your own risk. Users may experience unexpected
|
||||
delays, unexpected visual artifacts, unexpected loss of tokens or funds from improper app
|
||||
configuration, or other negative outcomes.
|
||||
<br />
|
||||
<br />
|
||||
By hitting the "continue" button, you are representing that you’ve read our
|
||||
<a
|
||||
href="https://forum.poa.network/t/end-user-licensing-agreement-and-terms-of-service/2197"
|
||||
target="_blank" rel="noopener noreferrer">Terms of
|
||||
Service</a> in full, and that you agree to be legally bound by them.
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Terms of Service
|
||||
</a>{' '}
|
||||
in full, and that you agree to be legally bound by them.
|
||||
</p>
|
||||
<div className="disclaimer-buttons">
|
||||
<button
|
||||
className="disclaimer-confirm"
|
||||
onClick={onConfirmation}>
|
||||
<button className="disclaimer-confirm" onClick={onConfirmation}>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,11 +1,26 @@
|
||||
import React from 'react'
|
||||
|
||||
export const EventsListHeader = ({selected, homeName, homeValue, foreignName, foreignValue, onChangeList, handleChange, handleKeyDown}) => (
|
||||
export const EventsListHeader = ({
|
||||
selected,
|
||||
homeName,
|
||||
homeValue,
|
||||
foreignName,
|
||||
foreignValue,
|
||||
onChangeList,
|
||||
handleChange,
|
||||
handleKeyDown
|
||||
}) => (
|
||||
<div>
|
||||
<div className="events-header">
|
||||
<span className="events-header-title">Events</span>
|
||||
<div className="events-filter-container">
|
||||
<input onChange={handleChange} onKeyDown={handleKeyDown} type="text" className="events-filter" placeholder="Tx Hash or Block Number..." />
|
||||
<input
|
||||
onChange={handleChange}
|
||||
onKeyDown={handleKeyDown}
|
||||
type="text"
|
||||
className="events-filter"
|
||||
placeholder="Tx Hash or Block Number..."
|
||||
/>
|
||||
<span className="events-filter-icon" />
|
||||
<select value={selected} onChange={onChangeList} className="events-select">
|
||||
<option value={homeValue}>{homeName}</option>
|
||||
|
@ -2,11 +2,7 @@ import React from 'react'
|
||||
import { CSSTransition } from 'react-transition-group'
|
||||
|
||||
export const Fade = ({ children, ...props }) => (
|
||||
<CSSTransition
|
||||
{...props}
|
||||
timeout={1000}
|
||||
classNames="fade"
|
||||
>
|
||||
<CSSTransition {...props} timeout={1000} classNames="fade">
|
||||
{children}
|
||||
</CSSTransition>
|
||||
)
|
||||
|
@ -3,35 +3,30 @@ import numeral from 'numeral'
|
||||
import { DataBlock } from './DataBlock'
|
||||
|
||||
export const FeeStatistics = ({ depositFeeCollected, withdrawFeeCollected }) => (
|
||||
<div className='statistics-fee-container' data-testid="fee-statistics">
|
||||
{
|
||||
(depositFeeCollected.shouldDisplay || withdrawFeeCollected.shouldDisplay)
|
||||
&& <span className='statistics-bridge-title statistics-title'>Fee Statistics</span>
|
||||
}
|
||||
<div className="statistics-fee-container" data-testid="fee-statistics">
|
||||
{(depositFeeCollected.shouldDisplay || withdrawFeeCollected.shouldDisplay) && (
|
||||
<span className="statistics-bridge-title statistics-title">Fee Statistics</span>
|
||||
)}
|
||||
<div className="statistics-fee-data" data-testid="fee-statistics-data">
|
||||
{
|
||||
depositFeeCollected.shouldDisplay &&
|
||||
{depositFeeCollected.shouldDisplay && (
|
||||
<DataBlock
|
||||
description="Deposit Fees"
|
||||
value={numeral(depositFeeCollected.value).format('0,0.00 a', Math.floor)}
|
||||
type={depositFeeCollected.type}
|
||||
dataTestid="deposit-fees-block"
|
||||
/>
|
||||
}
|
||||
{
|
||||
depositFeeCollected.shouldDisplay &&
|
||||
withdrawFeeCollected.shouldDisplay &&
|
||||
)}
|
||||
{depositFeeCollected.shouldDisplay && withdrawFeeCollected.shouldDisplay && (
|
||||
<div className="separator" />
|
||||
}
|
||||
{
|
||||
withdrawFeeCollected.shouldDisplay &&
|
||||
)}
|
||||
{withdrawFeeCollected.shouldDisplay && (
|
||||
<DataBlock
|
||||
description="Withdrawal Fees"
|
||||
value={numeral(withdrawFeeCollected.value).format('0,0.00 a', Math.floor)}
|
||||
type={withdrawFeeCollected.type}
|
||||
dataTestid="withdrawal-fees-block"
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { SocialIcons } from './SocialIcons'
|
||||
|
||||
export const Footer = () => (
|
||||
|
@ -2,28 +2,38 @@ import React from 'react'
|
||||
import yn from './utils/yn'
|
||||
import { DailyQuotaModal } from './DailyQuotaModal'
|
||||
import { HeaderMenu } from './HeaderMenu'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { MobileMenu } from './MobileMenu'
|
||||
import { MobileMenuButton } from './MobileMenuButton'
|
||||
import { inject, observer } from 'mobx-react/index'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class Header extends React.Component {
|
||||
render () {
|
||||
const { showMobileMenu, onMenuToggle, RootStore: { alertStore, web3Store } } = this.props
|
||||
const { REACT_APP_HOME_WITHOUT_EVENTS: HOME, REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
|
||||
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
export class Header extends React.Component {
|
||||
render() {
|
||||
const {
|
||||
showMobileMenu,
|
||||
onMenuToggle,
|
||||
RootStore: { alertStore, web3Store }
|
||||
} = this.props
|
||||
const {
|
||||
REACT_APP_HOME_WITHOUT_EVENTS: HOME,
|
||||
REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN
|
||||
} = process.env
|
||||
const withoutEvents =
|
||||
web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
|
||||
return (
|
||||
<header className="header">
|
||||
{showMobileMenu ? <MobileMenu withoutEvents={withoutEvents} onMenuToggle={onMenuToggle} /> : null}
|
||||
{showMobileMenu ? (
|
||||
<MobileMenu withoutEvents={withoutEvents} onMenuToggle={onMenuToggle} />
|
||||
) : null}
|
||||
<div className="container">
|
||||
<Link to="/" onClick={showMobileMenu ? onMenuToggle : null} className="header-logo" />
|
||||
<HeaderMenu withoutEvents={withoutEvents} onMenuToggle={onMenuToggle} />
|
||||
<MobileMenuButton onMenuToggle={onMenuToggle} showMobileMenu={showMobileMenu} />
|
||||
</div>
|
||||
{alertStore && alertStore.showDailyQuotaInfo && <DailyQuotaModal/>}
|
||||
{alertStore && alertStore.showDailyQuotaInfo && <DailyQuotaModal />}
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { MenuItems } from "./MenuItems";
|
||||
import React from 'react'
|
||||
import { MenuItems } from './MenuItems'
|
||||
import { Wallet } from './Wallet'
|
||||
|
||||
export const HeaderMenu = ({ withoutEvents }) => (
|
||||
@ -7,4 +7,4 @@ export const HeaderMenu = ({ withoutEvents }) => (
|
||||
<MenuItems withoutEvents={withoutEvents} />
|
||||
<Wallet />
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -1,29 +1,36 @@
|
||||
import React from 'react';
|
||||
import { inject, observer } from "mobx-react";
|
||||
import React from 'react'
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { ProgressRing } from './ProgressRing'
|
||||
import { PreventExit } from './PreventExit'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class Loading extends React.Component {
|
||||
render() {
|
||||
const { alertStore } = this.props.RootStore
|
||||
const { loadingStepIndex, loadingSteps, blockConfirmations } = alertStore
|
||||
const style = alertStore.showLoading ? {display: 'flex'} : {display: 'none'}
|
||||
const progress = loadingStepIndex === 3 ? 100 : (loadingStepIndex) * 25 + blockConfirmations * 4
|
||||
const style = alertStore.showLoading ? { display: 'flex' } : { display: 'none' }
|
||||
const progress = loadingStepIndex === 3 ? 100 : loadingStepIndex * 25 + blockConfirmations * 4
|
||||
|
||||
return (
|
||||
<div className={`loading-container ${loadingStepIndex > 0 ? 'mobile-container' : ''}`} style={style}>
|
||||
{loadingStepIndex > 0 && <ProgressRing
|
||||
confirmationNumber={blockConfirmations}
|
||||
hideConfirmationNumber={loadingStepIndex > 1}
|
||||
progress={progress}
|
||||
radius={ 40 }
|
||||
stroke={ 4 }
|
||||
/>}
|
||||
{loadingStepIndex === 0 && (<div className="loading-logo" />)}
|
||||
<div
|
||||
className={`loading-container ${loadingStepIndex > 0 ? 'mobile-container' : ''}`}
|
||||
style={style}
|
||||
>
|
||||
{loadingStepIndex > 0 && (
|
||||
<ProgressRing
|
||||
confirmationNumber={blockConfirmations}
|
||||
hideConfirmationNumber={loadingStepIndex > 1}
|
||||
progress={progress}
|
||||
radius={40}
|
||||
stroke={4}
|
||||
/>
|
||||
)}
|
||||
{loadingStepIndex === 0 && <div className="loading-logo" />}
|
||||
{loadingStepIndex === 0 && <div className="loading-i" />}
|
||||
{loadingStepIndex > 0 && (<div className="loading-text">{loadingSteps[loadingStepIndex]}</div>)}
|
||||
{loadingStepIndex > 0 && (
|
||||
<div className="loading-text">{loadingSteps[loadingStepIndex]}</div>
|
||||
)}
|
||||
{alertStore.showLoading && <PreventExit />}
|
||||
</div>
|
||||
)
|
||||
|
@ -1,26 +1,26 @@
|
||||
import React from "react"
|
||||
import { EventsIcon, StatusIcon, StatisticsIcon } from "./menu-icons"
|
||||
import { Link } from "react-router-dom"
|
||||
import React from 'react'
|
||||
import { EventsIcon, StatusIcon, StatisticsIcon } from './menu-icons'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
export const MenuItems = ({ onMenuToggle = null, withoutEvents }) => {
|
||||
const menuItems = [
|
||||
{
|
||||
hide: withoutEvents,
|
||||
icon: <EventsIcon />,
|
||||
link: "/events",
|
||||
text: "Events"
|
||||
link: '/events',
|
||||
text: 'Events'
|
||||
},
|
||||
{
|
||||
hide: false,
|
||||
icon: <StatusIcon />,
|
||||
link: "/status",
|
||||
text: "Status"
|
||||
link: '/status',
|
||||
text: 'Status'
|
||||
},
|
||||
{
|
||||
hide: withoutEvents,
|
||||
icon: <StatisticsIcon />,
|
||||
link: "/statistics",
|
||||
text: "Statistics"
|
||||
link: '/statistics',
|
||||
text: 'Statistics'
|
||||
}
|
||||
]
|
||||
|
||||
@ -30,6 +30,6 @@ export const MenuItems = ({ onMenuToggle = null, withoutEvents }) => {
|
||||
<span className="menu-items-icon">{item.icon}</span>
|
||||
<span className="menu-items-text">{item.text}</span>
|
||||
</Link>
|
||||
);
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { MenuItems } from "./MenuItems";
|
||||
import React from 'react'
|
||||
import { MenuItems } from './MenuItems'
|
||||
|
||||
export const MobileMenu = ({ onMenuToggle, withoutEvents }) => (
|
||||
<div className="mobile-menu">
|
||||
@ -7,4 +7,4 @@ export const MobileMenu = ({ onMenuToggle, withoutEvents }) => (
|
||||
<MenuItems withoutEvents={withoutEvents} onMenuToggle={onMenuToggle} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
|
@ -4,7 +4,7 @@ import { MobileMenuCloseIcon } from './menu-icons/MobileMenuCloseIcon'
|
||||
|
||||
export const MobileMenuButton = ({ showMobileMenu, onMenuToggle }) => {
|
||||
return (
|
||||
<div className='mobile-menu-button' onClick={onMenuToggle}>
|
||||
<div className="mobile-menu-button" onClick={onMenuToggle}>
|
||||
{showMobileMenu ? <MobileMenuCloseIcon /> : <MobileMenuIcon />}
|
||||
</div>
|
||||
)
|
||||
|
@ -1,23 +1,30 @@
|
||||
import React from 'react'
|
||||
|
||||
export const ModalContainer = (props) => {
|
||||
export const ModalContainer = props => {
|
||||
if (props.showModal)
|
||||
return (
|
||||
<div className="network-modal loading-container"
|
||||
onClick={props.hideModal
|
||||
? (e) => {
|
||||
if(e.target.classList.contains('network-details') || e.target.classList.contains('loading-container')) {
|
||||
props.hideModal()
|
||||
<div
|
||||
className="network-modal loading-container"
|
||||
onClick={
|
||||
props.hideModal
|
||||
? e => {
|
||||
if (
|
||||
e.target.classList.contains('network-details') ||
|
||||
e.target.classList.contains('loading-container')
|
||||
) {
|
||||
props.hideModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
: () => {}}
|
||||
: () => {}
|
||||
}
|
||||
>
|
||||
<div className='modal'>
|
||||
<div className="modal">
|
||||
{props.children}
|
||||
{props.hideModal
|
||||
? <div className='close-button' onClick={() => props.hideModal()}><i className="icon"/></div>
|
||||
: null
|
||||
}
|
||||
{props.hideModal ? (
|
||||
<div className="close-button" onClick={() => props.hideModal()}>
|
||||
<i className="icon" />
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -22,11 +22,13 @@ export const NetworkDetails = ({
|
||||
nativeSupplyTitle,
|
||||
tokenName,
|
||||
getExplorerAddressUrl
|
||||
}) => {
|
||||
}) => {
|
||||
const networkTitle = isHome ? 'Bridge Home' : 'Bridge Foreign'
|
||||
const logoClass = isHome ? 'home-logo home-logo-modal' : 'foreign-logo foreign-logo-modal'
|
||||
const totalTitle = isHome
|
||||
? nativeSupplyTitle ? `Native Coins Amount` : `Totally minted by the bridge`
|
||||
? nativeSupplyTitle
|
||||
? `Native Coins Amount`
|
||||
: `Totally minted by the bridge`
|
||||
: `${currency} Tokens Amount`
|
||||
const totalAmount = isHome ? totalBalance : totalSupply
|
||||
const formattedBalance = isNaN(numeral(balance).format('0.00', Math.floor))
|
||||
@ -35,8 +37,8 @@ export const NetworkDetails = ({
|
||||
|
||||
return (
|
||||
<div className="network-details" data-testid="network-details">
|
||||
<div className="details-logo-container">
|
||||
<div className={logoClass} />
|
||||
<div className="details-logo-container">
|
||||
<div className={logoClass} />
|
||||
</div>
|
||||
<div className="details-body">
|
||||
<p className="details-data-container">
|
||||
@ -45,36 +47,60 @@ export const NetworkDetails = ({
|
||||
</p>
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">{networkTitle} Address</span>
|
||||
<span className="details-description details-copy">
|
||||
<a className="details-description" href={getExplorerAddressUrl(address)} target="_blank" >
|
||||
{address.slice(0,27).concat('...')}
|
||||
</a>
|
||||
<CopyToClipboard text={address}>
|
||||
<span className="copy-icon copy-icon-right"><CopyIcon /></span>
|
||||
</CopyToClipboard>
|
||||
</span>
|
||||
<span className="details-description details-copy">
|
||||
<a
|
||||
className="details-description"
|
||||
href={getExplorerAddressUrl(address)}
|
||||
target="_blank"
|
||||
>
|
||||
{address.slice(0, 27).concat('...')}
|
||||
</a>
|
||||
<CopyToClipboard text={address}>
|
||||
<span className="copy-icon copy-icon-right">
|
||||
<CopyIcon />
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</span>
|
||||
</p>
|
||||
{displayBridgeLimits && <p className="details-data-container">
|
||||
<span className="details-label">Remaining Daily {currency} Quota</span>
|
||||
<span className="details-description-black">{numeral(maxCurrentLimit).format('0,0.0', Math.floor)} {currency}</span>
|
||||
</p>}
|
||||
{displayBridgeLimits && <p className="details-data-container">
|
||||
<span className="details-label">Maximum Amount Per Transaction</span>
|
||||
<span className="details-description-black">{numeral(maxPerTx).format('0,0.0', Math.floor)} {currency}</span>
|
||||
</p>}
|
||||
{displayBridgeLimits && <p className="details-data-container">
|
||||
<span className="details-label">Minimum Amount Per Transaction</span>
|
||||
<span className="details-description-black">{numeral(minPerTx).format('0,0.000', Math.floor)} {currency}</span>
|
||||
</p>}
|
||||
{displayBridgeLimits && (
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">Remaining Daily {currency} Quota</span>
|
||||
<span className="details-description-black">
|
||||
{numeral(maxCurrentLimit).format('0,0.0', Math.floor)} {currency}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
{displayBridgeLimits && (
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">Maximum Amount Per Transaction</span>
|
||||
<span className="details-description-black">
|
||||
{numeral(maxPerTx).format('0,0.0', Math.floor)} {currency}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
{displayBridgeLimits && (
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">Minimum Amount Per Transaction</span>
|
||||
<span className="details-description-black">
|
||||
{numeral(minPerTx).format('0,0.000', Math.floor)} {currency}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
{displayTokenAddress && (
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">Token Address</span>
|
||||
<span className="details-description details-copy">
|
||||
<a className="details-description" href={getExplorerAddressUrl(tokenAddress)} target="_blank" >
|
||||
{tokenAddress.slice(0,27).concat('...')}
|
||||
<a
|
||||
className="details-description"
|
||||
href={getExplorerAddressUrl(tokenAddress)}
|
||||
target="_blank"
|
||||
>
|
||||
{tokenAddress.slice(0, 27).concat('...')}
|
||||
</a>
|
||||
<CopyToClipboard text={tokenAddress}>
|
||||
<span className="copy-icon copy-icon-right"><CopyIcon /></span>
|
||||
<span className="copy-icon copy-icon-right">
|
||||
<CopyIcon />
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</span>
|
||||
</p>
|
||||
@ -87,11 +113,15 @@ export const NetworkDetails = ({
|
||||
)}
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">{totalTitle}</span>
|
||||
<span className="details-description-black">{numeral(totalAmount).format('0,0.000', Math.floor)} {currency}</span>
|
||||
<span className="details-description-black">
|
||||
{numeral(totalAmount).format('0,0.000', Math.floor)} {currency}
|
||||
</span>
|
||||
</p>
|
||||
<p className="details-data-container">
|
||||
<span className="details-label">Your {currency} Balance</span>
|
||||
<span className="details-description-black">{formattedBalance} {currency}</span>
|
||||
<span className="details-description-black">
|
||||
{formattedBalance} {currency}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -15,7 +15,12 @@ export class NoWallet extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { RootStore: { web3Store: { walletInstalled } }, showModal: showNoWallet } = this.props
|
||||
const {
|
||||
RootStore: {
|
||||
web3Store: { walletInstalled }
|
||||
},
|
||||
showModal: showNoWallet
|
||||
} = this.props
|
||||
const showModal = showNoWallet && !walletInstalled
|
||||
|
||||
if (!showModal || !this.state.showModal) return null
|
||||
@ -24,14 +29,18 @@ export class NoWallet extends Component {
|
||||
<ModalContainer showModal={showModal && this.state.showModal}>
|
||||
<div className="noWallet-alert">
|
||||
<div className="noWallet-image-container">
|
||||
<img className="noWallet-icon" src={noWalletIcon} alt="no wallet icon"/>
|
||||
<img className="noWallet-icon" src={noWalletIcon} alt="no wallet icon" />
|
||||
</div>
|
||||
<div className="noWallet-alert-container">
|
||||
<h2 className="noWallet-title">Wallet not found</h2>
|
||||
<p className="noWallet-description">A wallet is not installed. Before continue, please install one (AlphaWallet, Metamask
|
||||
or Nifty Wallet) and return to this page to continue using the application.</p>
|
||||
<p className="noWallet-description">For further information on how to install any of both wallets, please
|
||||
click the buttons below.</p>
|
||||
<p className="noWallet-description">
|
||||
A wallet is not installed. Before continue, please install one (AlphaWallet, Metamask
|
||||
or Nifty Wallet) and return to this page to continue using the application.
|
||||
</p>
|
||||
<p className="noWallet-description">
|
||||
For further information on how to install any of both wallets, please click the
|
||||
buttons below.
|
||||
</p>
|
||||
<div className="noWallet-buttons">
|
||||
<a
|
||||
className="noWallet-metamask"
|
||||
@ -50,14 +59,16 @@ export class NoWallet extends Component {
|
||||
Nifty Wallet
|
||||
</a>
|
||||
<a
|
||||
className="noWallet-alphawallet"
|
||||
href="https://alphawallet.github.io/AlphaWallet-Download-Page/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
className="noWallet-alphawallet"
|
||||
href="https://alphawallet.github.io/AlphaWallet-Download-Page/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
>
|
||||
AlphaWallet
|
||||
AlphaWallet
|
||||
</a>
|
||||
<button className="noWallet-cancel" onClick={this.handleCancel}>Cancel</button>
|
||||
<button className="noWallet-cancel" onClick={this.handleCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,19 +1,19 @@
|
||||
import React, {Component} from 'react'
|
||||
import React, { Component } from 'react'
|
||||
|
||||
export class PreventExit extends Component {
|
||||
onUnload = (e) => {
|
||||
e.returnValue = "Are you sure?"
|
||||
onUnload = e => {
|
||||
e.returnValue = 'Are you sure?'
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
componentDidMount() {
|
||||
window.addEventListener('beforeunload', this.onUnload)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('beforeunload', this.onUnload)
|
||||
}
|
||||
|
||||
render () {
|
||||
render() {
|
||||
return <div />
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { Component } from 'react'
|
||||
|
||||
export class ProgressRing extends Component {
|
||||
state = {
|
||||
@ -9,37 +9,34 @@ export class ProgressRing extends Component {
|
||||
render() {
|
||||
const { radius, stroke, progress, confirmationNumber, hideConfirmationNumber } = this.props
|
||||
const { circumference, normalizedRadius } = this.state
|
||||
const strokeDashoffset = circumference - progress / 100 * circumference
|
||||
const strokeDashoffset = circumference - (progress / 100) * circumference
|
||||
const confirmations = hideConfirmationNumber ? '' : `${confirmationNumber}/8`
|
||||
return (
|
||||
<svg
|
||||
height={radius * 2}
|
||||
width={radius * 2}
|
||||
>
|
||||
<svg height={radius * 2} width={radius * 2}>
|
||||
<circle
|
||||
stroke="#7b5ab2"
|
||||
fill="transparent"
|
||||
strokeWidth={ stroke }
|
||||
strokeDasharray={ circumference + ' ' + circumference }
|
||||
style={ { strokeDashoffset: 0 } }
|
||||
r={ normalizedRadius }
|
||||
cx={ radius }
|
||||
cy={ radius }
|
||||
strokeWidth={stroke}
|
||||
strokeDasharray={circumference + ' ' + circumference}
|
||||
style={{ strokeDashoffset: 0 }}
|
||||
r={normalizedRadius}
|
||||
cx={radius}
|
||||
cy={radius}
|
||||
/>
|
||||
<circle
|
||||
stroke="#60dc97"
|
||||
fill="transparent"
|
||||
strokeWidth={ stroke }
|
||||
strokeDasharray={ circumference + ' ' + circumference }
|
||||
style={ { strokeDashoffset } }
|
||||
r={ normalizedRadius }
|
||||
cx={ radius }
|
||||
cy={ radius }
|
||||
strokeWidth={stroke}
|
||||
strokeDasharray={circumference + ' ' + circumference}
|
||||
style={{ strokeDashoffset }}
|
||||
r={normalizedRadius}
|
||||
cx={radius}
|
||||
cy={radius}
|
||||
/>
|
||||
<text x="28" y="47" fontFamily="Nunito" fontSize="18" fill="white">
|
||||
{confirmations}
|
||||
</text>
|
||||
</svg>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +1,27 @@
|
||||
import React from 'react';
|
||||
import { inject, observer } from "mobx-react";
|
||||
import React from 'react'
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { EventsListHeader } from './index'
|
||||
import { Event } from './index'
|
||||
import yn from './utils/yn'
|
||||
import { Redirect } from 'react-router'
|
||||
|
||||
const WAIT_INTERVAL = 700
|
||||
const ENTER_KEY = 13
|
||||
|
||||
const WAIT_INTERVAL = 700;
|
||||
const ENTER_KEY = 13;
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class RelayEvents extends React.Component {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.timer = null;
|
||||
this.timer = null
|
||||
this.colors = {
|
||||
'UserRequestForSignature': 'green',
|
||||
'RelayedMessage': 'green',
|
||||
'UserRequestForAffirmation': 'red',
|
||||
'AffirmationCompleted': 'red',
|
||||
'SignedForUserRequest': 'purple',
|
||||
'SignedForAffirmation': 'purple',
|
||||
'CollectedSignatures': 'blue'
|
||||
UserRequestForSignature: 'green',
|
||||
RelayedMessage: 'green',
|
||||
UserRequestForAffirmation: 'red',
|
||||
AffirmationCompleted: 'red',
|
||||
SignedForUserRequest: 'purple',
|
||||
SignedForAffirmation: 'purple',
|
||||
CollectedSignatures: 'blue'
|
||||
}
|
||||
this.homeValue = '0'
|
||||
this.foreingValue = '1'
|
||||
@ -31,15 +30,15 @@ export class RelayEvents extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
onHomeBlockFilter = async (value) => {
|
||||
onHomeBlockFilter = async value => {
|
||||
const { alertStore, homeStore, foreignStore } = this.props.RootStore
|
||||
alertStore.setLoading(true)
|
||||
if(value.substr(0,2) === "0x"){
|
||||
if (value.substr(0, 2) === '0x') {
|
||||
homeStore.setFilter(true)
|
||||
foreignStore.setFilter(true)
|
||||
await homeStore.filterByTxHash(value)
|
||||
} else {
|
||||
if(Number(value) > 0){
|
||||
if (Number(value) > 0) {
|
||||
homeStore.setFilter(true)
|
||||
foreignStore.setFilter(true)
|
||||
await homeStore.setBlockFilter(value)
|
||||
@ -53,15 +52,15 @@ export class RelayEvents extends React.Component {
|
||||
alertStore.setLoading(false)
|
||||
}
|
||||
|
||||
onForeignBlockFilter = async (value) => {
|
||||
onForeignBlockFilter = async value => {
|
||||
const { alertStore, homeStore, foreignStore } = this.props.RootStore
|
||||
alertStore.setLoading(true)
|
||||
if(value.substr(0,2) === "0x"){
|
||||
if (value.substr(0, 2) === '0x') {
|
||||
homeStore.setFilter(true)
|
||||
foreignStore.setFilter(true)
|
||||
await foreignStore.filterByTxHash(value)
|
||||
} else {
|
||||
if(Number(value) > 0){
|
||||
if (Number(value) > 0) {
|
||||
homeStore.setFilter(true)
|
||||
foreignStore.setFilter(true)
|
||||
await foreignStore.setBlockFilter(value)
|
||||
@ -75,37 +74,42 @@ export class RelayEvents extends React.Component {
|
||||
alertStore.setLoading(false)
|
||||
}
|
||||
|
||||
handleChangeHome = async (e) => {
|
||||
const value = e.target.value;
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {this.onHomeBlockFilter(value)}, WAIT_INTERVAL);
|
||||
handleChangeHome = async e => {
|
||||
const value = e.target.value
|
||||
window.clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.onHomeBlockFilter(value)
|
||||
}, WAIT_INTERVAL)
|
||||
}
|
||||
|
||||
handleChangeForeign = async (e) => {
|
||||
const value = e.target.value;
|
||||
window.clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {this.onForeignBlockFilter(value)}, WAIT_INTERVAL);
|
||||
handleChangeForeign = async e => {
|
||||
const value = e.target.value
|
||||
window.clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
this.onForeignBlockFilter(value)
|
||||
}, WAIT_INTERVAL)
|
||||
}
|
||||
|
||||
handleKeyDownHome = (e) => {
|
||||
const value = e.target.value;
|
||||
window.clearTimeout(this.timer);
|
||||
handleKeyDownHome = e => {
|
||||
const value = e.target.value
|
||||
window.clearTimeout(this.timer)
|
||||
if (e.keyCode === ENTER_KEY && value) {
|
||||
this.onHomeBlockFilter(value);
|
||||
this.onHomeBlockFilter(value)
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyDownForeign = (e) => {
|
||||
const value = e.target.value;
|
||||
window.clearTimeout(this.timer);
|
||||
handleKeyDownForeign = e => {
|
||||
const value = e.target.value
|
||||
window.clearTimeout(this.timer)
|
||||
if (e.keyCode === ENTER_KEY && value) {
|
||||
this.onForeignBlockFilter(value);
|
||||
this.onForeignBlockFilter(value)
|
||||
}
|
||||
}
|
||||
|
||||
getHomeEvents = (homeStore) => {
|
||||
return homeStore.events.slice().map(({event, transactionHash, blockNumber, returnValues}) =>
|
||||
({
|
||||
getHomeEvents = homeStore => {
|
||||
return homeStore.events
|
||||
.slice()
|
||||
.map(({ event, transactionHash, blockNumber, returnValues }) => ({
|
||||
color: this.colors[event],
|
||||
eventName: event,
|
||||
transactionHash,
|
||||
@ -115,60 +119,76 @@ export class RelayEvents extends React.Component {
|
||||
}))
|
||||
}
|
||||
|
||||
getForeignEvents = (foreignStore) => {
|
||||
return foreignStore.events.slice()
|
||||
.map(({ event, transactionHash, signedTxHash, blockNumber, returnValues}) => {
|
||||
return ({
|
||||
getForeignEvents = foreignStore => {
|
||||
return foreignStore.events
|
||||
.slice()
|
||||
.map(({ event, transactionHash, signedTxHash, blockNumber, returnValues }) => {
|
||||
return {
|
||||
color: this.colors[event],
|
||||
eventName: event,
|
||||
transactionHash,
|
||||
recipient: returnValues.recipient,
|
||||
value: returnValues.value,
|
||||
blockNumber
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
onChangeList = (e) => {
|
||||
this.setState({selectedList: e.target.value})
|
||||
onChangeList = e => {
|
||||
this.setState({ selectedList: e.target.value })
|
||||
}
|
||||
|
||||
render(){
|
||||
render() {
|
||||
const { homeStore, foreignStore, web3Store } = this.props.RootStore
|
||||
const { selectedList } = this.state
|
||||
const home = this.getHomeEvents(homeStore, foreignStore)
|
||||
const foreign = this.getForeignEvents(foreignStore, homeStore)
|
||||
const { REACT_APP_HOME_WITHOUT_EVENTS: HOME, REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
|
||||
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
const {
|
||||
REACT_APP_HOME_WITHOUT_EVENTS: HOME,
|
||||
REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN
|
||||
} = process.env
|
||||
const withoutEvents =
|
||||
web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
|
||||
return withoutEvents ? (<Redirect to="/" />) : (
|
||||
return withoutEvents ? (
|
||||
<Redirect to="/" />
|
||||
) : (
|
||||
<div className="events-page">
|
||||
<div className="events-container">
|
||||
<EventsListHeader
|
||||
handleChange={selectedList === this.homeValue ? this.handleChangeHome : this.handleChangeForeign}
|
||||
handleKeyDown={selectedList === this.homeValue ? this.handleKeyDownHome : this.handleKeyDownForeign}
|
||||
handleChange={
|
||||
selectedList === this.homeValue ? this.handleChangeHome : this.handleChangeForeign
|
||||
}
|
||||
handleKeyDown={
|
||||
selectedList === this.homeValue ? this.handleKeyDownHome : this.handleKeyDownForeign
|
||||
}
|
||||
onChangeList={this.onChangeList}
|
||||
selected={selectedList}
|
||||
homeName={homeStore.networkName}
|
||||
homeValue={this.homeValue}
|
||||
foreignName={foreignStore.networkName}
|
||||
foreignValue={this.foreingValue} />
|
||||
{selectedList === this.homeValue
|
||||
&& home.map(event =>
|
||||
<Event
|
||||
txUrl={homeStore.getExplorerTxUrl(event.transactionHash)}
|
||||
accountUrl={homeStore.getExplorerAddressUrl(event.recipient)}
|
||||
key={event.transactionHash+event.eventName}
|
||||
{...event} />)}
|
||||
{selectedList === this.foreingValue
|
||||
&& foreign.map(event =>
|
||||
<Event
|
||||
txUrl={foreignStore.getExplorerTxUrl(event.transactionHash)}
|
||||
accountUrl={foreignStore.getExplorerAddressUrl(event.recipient)}
|
||||
key={event.transactionHash+event.eventName}
|
||||
{...event} />)}
|
||||
foreignValue={this.foreingValue}
|
||||
/>
|
||||
{selectedList === this.homeValue &&
|
||||
home.map(event => (
|
||||
<Event
|
||||
txUrl={homeStore.getExplorerTxUrl(event.transactionHash)}
|
||||
accountUrl={homeStore.getExplorerAddressUrl(event.recipient)}
|
||||
key={event.transactionHash + event.eventName}
|
||||
{...event}
|
||||
/>
|
||||
))}
|
||||
{selectedList === this.foreingValue &&
|
||||
foreign.map(event => (
|
||||
<Event
|
||||
txUrl={foreignStore.getExplorerTxUrl(event.transactionHash)}
|
||||
accountUrl={foreignStore.getExplorerAddressUrl(event.recipient)}
|
||||
key={event.transactionHash + event.eventName}
|
||||
{...event}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
import React from "react"
|
||||
import { IconGithub, IconPOA, IconTelegram, IconTwitter } from "./social-icons"
|
||||
import React from 'react'
|
||||
import { IconGithub, IconPOA, IconTelegram, IconTwitter } from './social-icons'
|
||||
|
||||
export const SocialIcons = () => {
|
||||
const socialItems = [
|
||||
{
|
||||
icon: <IconPOA />,
|
||||
link: "https://poa.network",
|
||||
link: 'https://poa.network'
|
||||
},
|
||||
{
|
||||
icon: <IconTwitter />,
|
||||
link: "https://twitter.com/poanetwork",
|
||||
link: 'https://twitter.com/poanetwork'
|
||||
},
|
||||
{
|
||||
icon: <IconTelegram />,
|
||||
link: "https://t.me/poa_network",
|
||||
link: 'https://t.me/poa_network'
|
||||
},
|
||||
{
|
||||
icon: <IconGithub />,
|
||||
link: "https://github.com/poanetwork/token-bridge",
|
||||
},
|
||||
link: 'https://github.com/poanetwork/token-bridge'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
|
@ -4,63 +4,75 @@ import { BRIDGE_MODES } from '../stores/utils/bridgeMode'
|
||||
import { BridgeStatistics } from './index'
|
||||
import { Redirect } from 'react-router'
|
||||
import { TransactionsStatistics } from './TransactionsStatistics'
|
||||
import { inject, observer } from "mobx-react"
|
||||
import { FeeStatistics } from "./FeeStatistics"
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { FeeStatistics } from './FeeStatistics'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class StatisticsPage extends React.Component {
|
||||
|
||||
render(){
|
||||
render() {
|
||||
const { homeStore, foreignStore, bridgeMode, web3Store } = this.props.RootStore
|
||||
const isNativeToErc = bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC
|
||||
const leftTitle = isNativeToErc ? 'Deposits' : 'Withdraws'
|
||||
const rightTitle = isNativeToErc ? 'Withdraws' : 'Deposits'
|
||||
const { REACT_APP_HOME_WITHOUT_EVENTS: HOME, REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
|
||||
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
const {
|
||||
REACT_APP_HOME_WITHOUT_EVENTS: HOME,
|
||||
REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN
|
||||
} = process.env
|
||||
const withoutEvents =
|
||||
web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
|
||||
return withoutEvents ? ( <Redirect to="/" />) : (
|
||||
return withoutEvents ? (
|
||||
<Redirect to="/" />
|
||||
) : (
|
||||
<div className="statistics-page">
|
||||
<div className='statistics-left-container' />
|
||||
<div className='statistics-page-container'>
|
||||
<div className='statistics-bridge-container'>
|
||||
<span className='statistics-bridge-title statistics-title'>Bridge Statistics</span>
|
||||
<div className="statistics-left-container" />
|
||||
<div className="statistics-page-container">
|
||||
<div className="statistics-bridge-container">
|
||||
<span className="statistics-bridge-title statistics-title">Bridge Statistics</span>
|
||||
<BridgeStatistics
|
||||
users={homeStore.statistics.finished ? homeStore.statistics.users.size : ''}
|
||||
totalBridged={homeStore.statistics.finished ? homeStore.statistics.totalBridged.toString() : ''}
|
||||
totalBridged={
|
||||
homeStore.statistics.finished ? homeStore.statistics.totalBridged.toString() : ''
|
||||
}
|
||||
homeBalance={homeStore.balance}
|
||||
homeSymbol={homeStore.symbol}
|
||||
homeNativeSupplyTitle={isNativeToErc}
|
||||
foreignSymbol={foreignStore.symbol}
|
||||
foreignSupply={foreignStore.totalSupply} />
|
||||
foreignSupply={foreignStore.totalSupply}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
homeStore.depositFeeCollected.finished
|
||||
&& homeStore.withdrawFeeCollected.finished
|
||||
&& (homeStore.depositFeeCollected.shouldDisplay || homeStore.withdrawFeeCollected.shouldDisplay)
|
||||
&& <FeeStatistics
|
||||
{homeStore.depositFeeCollected.finished &&
|
||||
homeStore.withdrawFeeCollected.finished &&
|
||||
(homeStore.depositFeeCollected.shouldDisplay ||
|
||||
homeStore.withdrawFeeCollected.shouldDisplay) && (
|
||||
<FeeStatistics
|
||||
depositFeeCollected={homeStore.depositFeeCollected}
|
||||
withdrawFeeCollected={homeStore.withdrawFeeCollected}
|
||||
/>
|
||||
}
|
||||
<div className='statistics-transaction-container'>
|
||||
<div className='statistics-deposit-container'>
|
||||
<span className='statistics-deposit-title statistics-title'>Tokens {leftTitle}</span>
|
||||
)}
|
||||
<div className="statistics-transaction-container">
|
||||
<div className="statistics-deposit-container">
|
||||
<span className="statistics-deposit-title statistics-title">Tokens {leftTitle}</span>
|
||||
<TransactionsStatistics
|
||||
txNumber={homeStore.statistics.finished ? homeStore.statistics.deposits : ''}
|
||||
type={foreignStore.symbol}
|
||||
value={homeStore.statistics.finished ? homeStore.statistics.depositsValue : ''} />
|
||||
value={homeStore.statistics.finished ? homeStore.statistics.depositsValue : ''}
|
||||
/>
|
||||
</div>
|
||||
<div className='statistics-withdraw-container'>
|
||||
<span className='statistics-withdraw-title statistics-title'>Tokens {rightTitle}</span>
|
||||
<div className="statistics-withdraw-container">
|
||||
<span className="statistics-withdraw-title statistics-title">
|
||||
Tokens {rightTitle}
|
||||
</span>
|
||||
<TransactionsStatistics
|
||||
txNumber={homeStore.statistics.finished ? homeStore.statistics.withdraws : ''}
|
||||
type={foreignStore.symbol}
|
||||
value={homeStore.statistics.finished ? homeStore.statistics.withdrawsValue : ''} />
|
||||
value={homeStore.statistics.finished ? homeStore.statistics.withdrawsValue : ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='pattern-background'>
|
||||
<div className="pattern-background">
|
||||
<div className="pattern-background-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -2,50 +2,55 @@ import React from 'react'
|
||||
import yn from './utils/yn'
|
||||
import { Authority } from './Authority'
|
||||
import { Configuration } from './Configuration'
|
||||
import { inject, observer } from "mobx-react"
|
||||
import { inject, observer } from 'mobx-react'
|
||||
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class StatusPage extends React.Component {
|
||||
|
||||
render() {
|
||||
const { homeStore, foreignStore, web3Store } = this.props.RootStore
|
||||
const isHome = web3Store.metamaskNet.id.toString() === web3Store.homeNet.id.toString()
|
||||
const requiredSignatures = isHome ? homeStore.requiredSignatures : foreignStore.requiredSignatures
|
||||
const requiredSignatures = isHome
|
||||
? homeStore.requiredSignatures
|
||||
: foreignStore.requiredSignatures
|
||||
const authorities = isHome ? homeStore.validatorsCount : foreignStore.validatorsCount
|
||||
const symbol = isHome ? homeStore.symbol : foreignStore.symbol
|
||||
const maxSingleDeposit = isHome ? homeStore.maxPerTx : foreignStore.maxPerTx
|
||||
const maxTotalBalance = isHome ? homeStore.maxCurrentDeposit : foreignStore.maxCurrentDeposit
|
||||
const validatorsList = isHome ? homeStore.validators : foreignStore.validators
|
||||
const { REACT_APP_HOME_WITHOUT_EVENTS: HOME, REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN } = process.env
|
||||
const withoutEvents = web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
const {
|
||||
REACT_APP_HOME_WITHOUT_EVENTS: HOME,
|
||||
REACT_APP_FOREIGN_WITHOUT_EVENTS: FOREIGN
|
||||
} = process.env
|
||||
const withoutEvents =
|
||||
web3Store.metamaskNet.id === web3Store.homeNet.id.toString() ? yn(HOME) : yn(FOREIGN)
|
||||
|
||||
return (
|
||||
<div className="status-page">
|
||||
<div className='status-left-container' />
|
||||
<div className='status-page-container'>
|
||||
<div className='status-configuration-container'>
|
||||
<span className='status-configuration-title status-title'>Configuration</span>
|
||||
<Configuration
|
||||
requiredSignatures={requiredSignatures}
|
||||
authorities={authorities}
|
||||
symbol={symbol}
|
||||
maxSingleDeposit={maxSingleDeposit}
|
||||
maxTotalBalance={maxTotalBalance} />
|
||||
<div className="status-left-container" />
|
||||
<div className="status-page-container">
|
||||
<div className="status-configuration-container">
|
||||
<span className="status-configuration-title status-title">Configuration</span>
|
||||
<Configuration
|
||||
requiredSignatures={requiredSignatures}
|
||||
authorities={authorities}
|
||||
symbol={symbol}
|
||||
maxSingleDeposit={maxSingleDeposit}
|
||||
maxTotalBalance={maxTotalBalance}
|
||||
/>
|
||||
</div>
|
||||
{withoutEvents ? null :
|
||||
<div className='status-authorities-container'>
|
||||
<span className='status-authorities-title status-title'>Authorities</span>
|
||||
<div className='status-authorities-data'>
|
||||
{validatorsList.map((validator,i) => (
|
||||
<Authority key={validator} address={validator} number={(i+1)} logoIndex={(i) % 3} />
|
||||
{withoutEvents ? null : (
|
||||
<div className="status-authorities-container">
|
||||
<span className="status-authorities-title status-title">Authorities</span>
|
||||
<div className="status-authorities-data">
|
||||
{validatorsList.map((validator, i) => (
|
||||
<Authority key={validator} address={validator} number={i + 1} logoIndex={i % 3} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
<div className='pattern-background'>
|
||||
<div className="pattern-background">
|
||||
<div className="pattern-background-image" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import swal from 'sweetalert';
|
||||
import { inject, observer } from "mobx-react";
|
||||
import React from 'react'
|
||||
import swal from 'sweetalert'
|
||||
import { inject, observer } from 'mobx-react'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class SweetAlert extends React.Component {
|
||||
componentWillReact(){
|
||||
componentWillReact() {
|
||||
const { alertStore } = this.props.RootStore
|
||||
if(alertStore.alerts.length > 0){
|
||||
if (alertStore.alerts.length > 0) {
|
||||
const alert = alertStore.alerts.slice()[0]
|
||||
swal(alert).then(() => {
|
||||
alertStore.remove(alert)
|
||||
@ -23,10 +23,8 @@ export class SweetAlert extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
render() {
|
||||
this.logErrors()
|
||||
return (
|
||||
<div style={{display: 'none'}} />
|
||||
)
|
||||
return <div style={{ display: 'none' }} />
|
||||
}
|
||||
}
|
||||
|
@ -4,11 +4,7 @@ import { DataBlock } from './DataBlock'
|
||||
|
||||
export const TransactionsStatistics = ({ txNumber, value, type }) => (
|
||||
<div className="statistics-bridge-data">
|
||||
<DataBlock
|
||||
description="Transactions"
|
||||
value={numeral(txNumber).format('0,0 a')}
|
||||
type=''
|
||||
/>
|
||||
<DataBlock description="Transactions" value={numeral(txNumber).format('0,0 a')} type="" />
|
||||
<div className="separator" />
|
||||
<DataBlock
|
||||
description="Total Value"
|
||||
|
@ -14,24 +14,27 @@ export const TransferAlert = ({
|
||||
toAmount,
|
||||
fee,
|
||||
reverse
|
||||
}) => {
|
||||
|
||||
}) => {
|
||||
const formattedFromAmount = numeral(fromAmount).format('0,0[.][000000000000000000]', Math.floor)
|
||||
const formattedToAmount = numeral(toAmount).format('0,0[.][000000000000000000]', Math.floor)
|
||||
|
||||
return (
|
||||
<div className="transfer-alert">
|
||||
<div className="image-container">
|
||||
<img className="arrows-icon" src={arrowsIcon} alt="transfer icon"/>
|
||||
<img className="arrows-icon" src={arrowsIcon} alt="transfer icon" />
|
||||
</div>
|
||||
<div className="alert-container">
|
||||
<div className="transfer-title">
|
||||
<div className="alert-logo-box">
|
||||
<div className={reverse ? 'foreign-logo' : 'home-logo'} />
|
||||
</div>
|
||||
<div><strong>{formattedFromAmount}</strong> {fromCurrency}</div>
|
||||
<div>
|
||||
<strong>{formattedFromAmount}</strong> {fromCurrency}
|
||||
</div>
|
||||
<ArrowRight />
|
||||
<div><strong>{formattedToAmount}</strong> {toCurrency}</div>
|
||||
<div>
|
||||
<strong>{formattedToAmount}</strong> {toCurrency}
|
||||
</div>
|
||||
<div className="alert-logo-box">
|
||||
<div className={reverse ? 'home-logo' : 'foreign-logo'} />
|
||||
</div>
|
||||
@ -39,11 +42,17 @@ export const TransferAlert = ({
|
||||
<p className="transfer-description" data-testid="transfer-description">
|
||||
<strong>{fee && `Fee: ${fee.toString()}%`}</strong>
|
||||
<br />
|
||||
Please confirm that you would like to send <strong>{formattedFromAmount}</strong> {fromCurrency} from {from} to receive <strong>{formattedToAmount}</strong> {toCurrency} on {to}.
|
||||
Please confirm that you would like to send <strong>{formattedFromAmount}</strong>{' '}
|
||||
{fromCurrency} from {from} to receive <strong>{formattedToAmount}</strong> {toCurrency} on{' '}
|
||||
{to}.
|
||||
</p>
|
||||
<div className="transfer-buttons">
|
||||
<button className="transfer-confirm" onClick={onConfirmation}>Continue</button>
|
||||
<button className="transfer-cancel" onClick={onCancel}>Cancel</button>
|
||||
<button className="transfer-confirm" onClick={onConfirmation}>
|
||||
Continue
|
||||
</button>
|
||||
<button className="transfer-cancel" onClick={onCancel}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,29 +1,36 @@
|
||||
import React from 'react';
|
||||
import { inject, observer } from "mobx-react";
|
||||
import React from 'react'
|
||||
import { inject, observer } from 'mobx-react'
|
||||
import { WalletIcon } from './menu-icons/WalletIcon'
|
||||
|
||||
@inject("RootStore")
|
||||
@inject('RootStore')
|
||||
@observer
|
||||
export class Wallet extends React.Component {
|
||||
render() {
|
||||
const { web3Store, homeStore, foreignStore, alertStore } = this.props.RootStore
|
||||
const isHome = web3Store.metamaskNet.id.toString() === web3Store.homeNet.id.toString()
|
||||
const address = web3Store.defaultAccount.address
|
||||
const explorerAddressUrl = isHome ? homeStore.getExplorerAddressUrl(address) : foreignStore.getExplorerAddressUrl(address)
|
||||
const completed = isHome ? homeStore.getDailyQuotaCompleted() : foreignStore.getDailyQuotaCompleted()
|
||||
const explorerAddressUrl = isHome
|
||||
? homeStore.getExplorerAddressUrl(address)
|
||||
: foreignStore.getExplorerAddressUrl(address)
|
||||
const completed = isHome
|
||||
? homeStore.getDailyQuotaCompleted()
|
||||
: foreignStore.getDailyQuotaCompleted()
|
||||
const width = `${completed}%`
|
||||
|
||||
const wallet = web3Store.defaultAccount.address !== '' && web3Store.defaultAccount.address !== undefined
|
||||
? (<a
|
||||
href={explorerAddressUrl}
|
||||
target="_blank"
|
||||
className="wallet-text wallet-link">
|
||||
{web3Store.defaultAccount.address.slice(0,17).concat('...')}
|
||||
</a>)
|
||||
: (<span className="wallet-text">Login with <span className="wallet-text-metamask">wallet</span></span>)
|
||||
const wallet =
|
||||
web3Store.defaultAccount.address !== '' && web3Store.defaultAccount.address !== undefined ? (
|
||||
<a href={explorerAddressUrl} target="_blank" className="wallet-text wallet-link">
|
||||
{web3Store.defaultAccount.address.slice(0, 17).concat('...')}
|
||||
</a>
|
||||
) : (
|
||||
<span className="wallet-text">
|
||||
Login with <span className="wallet-text-metamask">wallet</span>
|
||||
</span>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="header-wallet"
|
||||
<div
|
||||
className="header-wallet"
|
||||
onMouseEnter={() => alertStore.setShowDailyQuotaInfo(true)}
|
||||
onMouseLeave={() => alertStore.setShowDailyQuotaInfo(false)}
|
||||
>
|
||||
@ -32,7 +39,7 @@ export class Wallet extends React.Component {
|
||||
{wallet}
|
||||
</div>
|
||||
<div className="daily-quota-container">
|
||||
{web3Store.metamaskNet.id && <div className="daily-quota-progress" style={{width}} />}
|
||||
{web3Store.metamaskNet.id && <div className="daily-quota-progress" style={{ width }} />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -26,7 +26,8 @@ describe('FeeStatistics', () => {
|
||||
<FeeStatistics
|
||||
depositFeeCollected={depositFeeCollected}
|
||||
withdrawFeeCollected={withdrawFeeCollected}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('fee-statistics')
|
||||
@ -63,7 +64,8 @@ describe('FeeStatistics', () => {
|
||||
<FeeStatistics
|
||||
depositFeeCollected={depositFeeCollected}
|
||||
withdrawFeeCollected={withdrawFeeCollected}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('fee-statistics')
|
||||
@ -97,7 +99,8 @@ describe('FeeStatistics', () => {
|
||||
<FeeStatistics
|
||||
depositFeeCollected={depositFeeCollected}
|
||||
withdrawFeeCollected={withdrawFeeCollected}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('fee-statistics')
|
||||
@ -131,7 +134,8 @@ describe('FeeStatistics', () => {
|
||||
<FeeStatistics
|
||||
depositFeeCollected={depositFeeCollected}
|
||||
withdrawFeeCollected={withdrawFeeCollected}
|
||||
/>)
|
||||
/>
|
||||
)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('fee-statistics')
|
||||
|
@ -6,19 +6,19 @@ import 'jest-dom/extend-expect'
|
||||
afterEach(cleanup)
|
||||
|
||||
const baseData = {
|
||||
address: "0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26",
|
||||
balance: "99.99",
|
||||
currency: "TEST",
|
||||
address: '0xCecBE80Ed3548dE11D7d2D922a36576eA40C4c26',
|
||||
balance: '99.99',
|
||||
currency: 'TEST',
|
||||
displayTokenAddress: true,
|
||||
getExplorerAddressUrl: () => {},
|
||||
isHome: false,
|
||||
maxCurrentLimit: "20000",
|
||||
maxPerTx: "2000",
|
||||
minPerTx: "0.01",
|
||||
tokenAddress: "0xb69d9C58C258080eABF499270c778bBDE38dd6Ac",
|
||||
tokenName: "TEST",
|
||||
totalSupply: "100",
|
||||
url: "https://ropsten.infura.io"
|
||||
maxCurrentLimit: '20000',
|
||||
maxPerTx: '2000',
|
||||
minPerTx: '0.01',
|
||||
tokenAddress: '0xb69d9C58C258080eABF499270c778bBDE38dd6Ac',
|
||||
tokenName: 'TEST',
|
||||
totalSupply: '100',
|
||||
url: 'https://ropsten.infura.io'
|
||||
}
|
||||
|
||||
describe('NetworkDetails', () => {
|
||||
@ -30,7 +30,7 @@ describe('NetworkDetails', () => {
|
||||
}
|
||||
|
||||
// When
|
||||
const { queryByTestId } = render(<NetworkDetails {...data}/>)
|
||||
const { queryByTestId } = render(<NetworkDetails {...data} />)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('network-details')
|
||||
@ -46,7 +46,7 @@ describe('NetworkDetails', () => {
|
||||
}
|
||||
|
||||
// When
|
||||
const { queryByTestId } = render(<NetworkDetails {...data}/>)
|
||||
const { queryByTestId } = render(<NetworkDetails {...data} />)
|
||||
|
||||
// Then
|
||||
const container = queryByTestId('network-details')
|
||||
|
@ -6,7 +6,7 @@ import BN from 'bignumber.js'
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
describe('TransferAlert', function () {
|
||||
describe('TransferAlert', function() {
|
||||
it('does not render fee information if not provided', async () => {
|
||||
const data = {
|
||||
from: 'Sokol',
|
||||
@ -19,7 +19,7 @@ describe('TransferAlert', function () {
|
||||
reverse: false
|
||||
}
|
||||
|
||||
const { getByTestId } = render(<TransferAlert { ...data } />)
|
||||
const { getByTestId } = render(<TransferAlert {...data} />)
|
||||
|
||||
expect(getByTestId('transfer-description')).not.toHaveTextContent('Fee')
|
||||
})
|
||||
@ -40,7 +40,7 @@ describe('TransferAlert', function () {
|
||||
reverse: false
|
||||
}
|
||||
|
||||
const { getByTestId } = render(<TransferAlert { ...data } />)
|
||||
const { getByTestId } = render(<TransferAlert {...data} />)
|
||||
|
||||
expect(getByTestId('transfer-description')).toHaveTextContent('Fee')
|
||||
expect(getByTestId('transfer-description')).toHaveTextContent(fee.toString())
|
||||
|
@ -4,29 +4,44 @@ import numeral from 'numeral'
|
||||
import { CopyIcon } from '../icons/CopyIcon'
|
||||
import { CopyToClipboard } from 'react-copy-to-clipboard'
|
||||
|
||||
export const Event = ({ color, eventName, transactionHash, recipient, value, blockNumber, txUrl, accountUrl }) => (
|
||||
export const Event = ({
|
||||
color,
|
||||
eventName,
|
||||
transactionHash,
|
||||
recipient,
|
||||
value,
|
||||
blockNumber,
|
||||
txUrl,
|
||||
accountUrl
|
||||
}) => (
|
||||
<div>
|
||||
<div className="event">
|
||||
<div className="event-tx-container txhash-column">
|
||||
<span className={`event-name background-${color}`}>{eventName}</span>
|
||||
<span>
|
||||
<a href={txUrl} target="_blank" className="event-txhash">{transactionHash.slice(0,18).concat('...')}</a>
|
||||
<a href={txUrl} target="_blank" className="event-txhash">
|
||||
{transactionHash.slice(0, 18).concat('...')}
|
||||
</a>
|
||||
<CopyToClipboard text={transactionHash}>
|
||||
<span className="copy-icon copy-icon-right"><CopyIcon /></span>
|
||||
<span className="copy-icon copy-icon-right">
|
||||
<CopyIcon />
|
||||
</span>
|
||||
</CopyToClipboard>
|
||||
</span>
|
||||
</div>
|
||||
<a href={accountUrl} target="_blank" className="event-recipient recipient-column">
|
||||
{recipient ? <strong className="only-mobile event-recipient-label ">Recipient</strong> : ''}
|
||||
{recipient ? recipient.slice(0,27).concat('...') : ''}
|
||||
{recipient ? recipient.slice(0, 27).concat('...') : ''}
|
||||
</a>
|
||||
<span className="event-value value-column">
|
||||
{recipient ? <strong className="only-mobile">Value</strong> : ''}
|
||||
{value ? numeral(fromWei(value)).format('0,0.00', Math.floor) : ''}
|
||||
</span>
|
||||
<span className="event-block block-column"><strong className="only-mobile">Block</strong>{blockNumber}</span>
|
||||
<span className="event-block block-column">
|
||||
<strong className="only-mobile">Block</strong>
|
||||
{blockNumber}
|
||||
</span>
|
||||
</div>
|
||||
<div className="event-separator" />
|
||||
</div>
|
||||
|
||||
)
|
||||
|
@ -1,13 +1,11 @@
|
||||
import React from 'react';
|
||||
import React from 'react'
|
||||
|
||||
export const EventHeader = ({color, eventName, transactionHash, handleClick}) => (
|
||||
export const EventHeader = ({ color, eventName, transactionHash, handleClick }) => (
|
||||
<div className="events-i-header">
|
||||
<div className="events-i-header-title">
|
||||
<p className={`label ${color}`}>{eventName}</p>
|
||||
</div>
|
||||
<p className="description break-all">
|
||||
tx: {transactionHash}
|
||||
</p>
|
||||
<p className="description break-all">tx: {transactionHash}</p>
|
||||
<div onClick={handleClick} className="events-i-switcher" />
|
||||
</div>
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react";
|
||||
import React from 'react'
|
||||
|
||||
export const ArrowRight = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10">
|
||||
@ -7,4 +7,4 @@ export const ArrowRight = () => (
|
||||
d="M14 5c0 .01-.005.017-.005.027a.956.956 0 0 1-.28.688c-.063.063-.139.099-.213.14l-3.86 3.86a.959.959 0 1 1-1.357-1.357L10.642 6H1a1 1 0 0 1 0-2h9.642L8.285 1.642A.959.959 0 1 1 9.642.285l3.856 3.856c.076.042.153.08.217.144a.956.956 0 0 1 .279.692c0 .009.006.015.006.023z"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
)
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const CopyIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14">
|
||||
<path fillRule="evenodd" d="M13 10a1 1 0 0 1-1-1V2H5a1 1 0 0 1 0-2h8a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1zm-3-5v8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1zM8 6H2v6h6V6z"/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M13 10a1 1 0 0 1-1-1V2H5a1 1 0 0 1 0-2h8a1 1 0 0 1 1 1v8a1 1 0 0 1-1 1zm-3-5v8a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h8a1 1 0 0 1 1 1zM8 6H2v6h6V6z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const InfoIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24">
|
||||
<path fillRule="evenodd" d="M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-22C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 16a1 1 0 0 1-1-1v-6a1 1 0 0 1 2 0v6a1 1 0 0 1-1 1zm0-10a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12zm0-22C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm0 16a1 1 0 0 1-1-1v-6a1 1 0 0 1 2 0v6a1 1 0 0 1-1 1zm0-10a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
export { Header } from './Header';
|
||||
export { Bridge } from './Bridge';
|
||||
export { RelayEvents } from './RelayEvents';
|
||||
export { Footer } from './Footer';
|
||||
export { SweetAlert } from './SweetAlert';
|
||||
export { Loading } from './Loading';
|
||||
export { Header } from './Header'
|
||||
export { Bridge } from './Bridge'
|
||||
export { RelayEvents } from './RelayEvents'
|
||||
export { Footer } from './Footer'
|
||||
export { SweetAlert } from './SweetAlert'
|
||||
export { Loading } from './Loading'
|
||||
export { Fade } from './Fade'
|
||||
export { BridgeForm } from './BridgeForm'
|
||||
export { BridgeNetwork } from './BridgeNetwork'
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const EventsIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="17">
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const MobileMenuCloseIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||
<path fillRule="evenodd" d="M17.691 1.719l-3 3-4.265 4.265.019.02 4.245 4.245 3 3a1.019 1.019 0 1 1-1.441 1.441l-3-3-4.265-4.264L4.72 14.69l-3 3a1.02 1.02 0 0 1-1.442-1.441l3-3 4.265-4.265-.02-.019-4.245-4.246-3-3A1.019 1.019 0 1 1 1.719.278l3 3 4.265 4.265 4.266-4.265 3-3a1.019 1.019 0 1 1 1.441 1.441z"/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M17.691 1.719l-3 3-4.265 4.265.019.02 4.245 4.245 3 3a1.019 1.019 0 1 1-1.441 1.441l-3-3-4.265-4.264L4.72 14.69l-3 3a1.02 1.02 0 0 1-1.442-1.441l3-3 4.265-4.265-.02-.019-4.245-4.246-3-3A1.019 1.019 0 1 1 1.719.278l3 3 4.265 4.265 4.266-4.265 3-3a1.019 1.019 0 1 1 1.441 1.441z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const MobileMenuIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="14">
|
||||
<path fillRule="evenodd" d="M17 8H1a1 1 0 0 1 0-2h16a1 1 0 0 1 0 2zm0-6H1a1 1 0 0 1 0-2h16a1 1 0 0 1 0 2zM1 12h16a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M17 8H1a1 1 0 0 1 0-2h16a1 1 0 0 1 0 2zm0-6H1a1 1 0 0 1 0-2h16a1 1 0 0 1 0 2zM1 12h16a1 1 0 0 1 0 2H1a1 1 0 0 1 0-2z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const StatisticsIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const StatusIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from "react"
|
||||
import React from 'react'
|
||||
|
||||
export const WalletIcon = () => (
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18">
|
||||
<path fillRule="evenodd" d="M17 18H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3h3a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1zM12 2H2v2h10V2zm4 4H2v10h14V6zm-3 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M17 18H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3h3a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1zM12 2H2v2h10V2zm4 4H2v10h14V6zm-3 4a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
|
@ -1,5 +1,5 @@
|
||||
export * from './EventsIcon';
|
||||
export * from './MobileMenuCloseIcon';
|
||||
export * from './MobileMenuIcon';
|
||||
export * from './StatisticsIcon';
|
||||
export * from './StatusIcon';
|
||||
export * from './EventsIcon'
|
||||
export * from './MobileMenuCloseIcon'
|
||||
export * from './MobileMenuIcon'
|
||||
export * from './StatisticsIcon'
|
||||
export * from './StatusIcon'
|
||||
|
@ -2,14 +2,11 @@ import React from 'react'
|
||||
|
||||
export const IconGithub = () => {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M14.928 4.084a8.067 8.067 0 0 0-2.912-2.985A7.673 7.673 0 0 0 8-.001a7.67 7.67 0 0 0-4.016 1.1 8.06 8.06 0 0 0-2.912 2.985C.356 5.34-.001 6.712-.001 8.201c0 1.787.508 3.394 1.526 4.821 1.017 1.428 2.332 2.416 3.943 2.964.188.035.327.01.417-.075a.422.422 0 0 0 .135-.32l-.005-.577c-.003-.363-.005-.68-.005-.95l-.24.042a2.985 2.985 0 0 1-.578.038 4.418 4.418 0 0 1-.724-.075 1.6 1.6 0 0 1-.698-.32 1.359 1.359 0 0 1-.458-.657l-.105-.246a2.64 2.64 0 0 0-.328-.544c-.149-.2-.3-.335-.453-.406l-.073-.053a.78.78 0 0 1-.135-.129.572.572 0 0 1-.094-.15c-.021-.049-.004-.09.052-.122.056-.032.156-.048.302-.048l.209.032c.138.028.31.113.515.256.205.142.374.328.506.555.159.292.352.515.578.668.225.153.453.229.682.229.229 0 .427-.017.594-.053.167-.036.323-.089.469-.16.062-.477.232-.844.51-1.1a6.938 6.938 0 0 1-1.068-.193 4.188 4.188 0 0 1-.979-.416 2.828 2.828 0 0 1-.839-.716c-.222-.284-.404-.658-.547-1.121-.142-.463-.213-.997-.213-1.602 0-.862.274-1.595.823-2.2-.257-.648-.233-1.374.073-2.179.201-.064.5-.016.896.144.396.161.686.298.87.412.184.113.332.21.443.288a7.225 7.225 0 0 1 2-.278c.687 0 1.354.093 2.001.278l.395-.256a5.53 5.53 0 0 1 .959-.47c.368-.142.649-.182.844-.117.312.804.34 1.53.083 2.178.549.605.823 1.338.823 2.2 0 .605-.071 1.141-.213 1.607-.143.467-.327.84-.553 1.122a2.926 2.926 0 0 1-.843.71 4.194 4.194 0 0 1-.98.416c-.316.086-.672.15-1.068.193.362.32.542.826.542 1.516v2.253c0 .129.044.235.13.321.087.085.224.11.412.074 1.611-.548 2.926-1.536 3.943-2.963 1.018-1.427 1.526-3.035 1.526-4.822 0-1.488-.358-2.86-1.073-4.116z"
|
||||
/>
|
||||
</svg>
|
||||
<svg viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M14.928 4.084a8.067 8.067 0 0 0-2.912-2.985A7.673 7.673 0 0 0 8-.001a7.67 7.67 0 0 0-4.016 1.1 8.06 8.06 0 0 0-2.912 2.985C.356 5.34-.001 6.712-.001 8.201c0 1.787.508 3.394 1.526 4.821 1.017 1.428 2.332 2.416 3.943 2.964.188.035.327.01.417-.075a.422.422 0 0 0 .135-.32l-.005-.577c-.003-.363-.005-.68-.005-.95l-.24.042a2.985 2.985 0 0 1-.578.038 4.418 4.418 0 0 1-.724-.075 1.6 1.6 0 0 1-.698-.32 1.359 1.359 0 0 1-.458-.657l-.105-.246a2.64 2.64 0 0 0-.328-.544c-.149-.2-.3-.335-.453-.406l-.073-.053a.78.78 0 0 1-.135-.129.572.572 0 0 1-.094-.15c-.021-.049-.004-.09.052-.122.056-.032.156-.048.302-.048l.209.032c.138.028.31.113.515.256.205.142.374.328.506.555.159.292.352.515.578.668.225.153.453.229.682.229.229 0 .427-.017.594-.053.167-.036.323-.089.469-.16.062-.477.232-.844.51-1.1a6.938 6.938 0 0 1-1.068-.193 4.188 4.188 0 0 1-.979-.416 2.828 2.828 0 0 1-.839-.716c-.222-.284-.404-.658-.547-1.121-.142-.463-.213-.997-.213-1.602 0-.862.274-1.595.823-2.2-.257-.648-.233-1.374.073-2.179.201-.064.5-.016.896.144.396.161.686.298.87.412.184.113.332.21.443.288a7.225 7.225 0 0 1 2-.278c.687 0 1.354.093 2.001.278l.395-.256a5.53 5.53 0 0 1 .959-.47c.368-.142.649-.182.844-.117.312.804.34 1.53.083 2.178.549.605.823 1.338.823 2.2 0 .605-.071 1.141-.213 1.607-.143.467-.327.84-.553 1.122a2.926 2.926 0 0 1-.843.71 4.194 4.194 0 0 1-.98.416c-.316.086-.672.15-1.068.193.362.32.542.826.542 1.516v2.253c0 .129.044.235.13.321.087.085.224.11.412.074 1.611-.548 2.926-1.536 3.943-2.963 1.018-1.427 1.526-3.035 1.526-4.822 0-1.488-.358-2.86-1.073-4.116z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
@ -2,10 +2,7 @@ import React from 'react'
|
||||
|
||||
export const IconPOA = () => {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 125 40"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg viewBox="0 0 125 40" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fillRule="evenodd">
|
||||
<path d="M61.4 0C50.482 0 41.6 8.883 41.6 19.8c0 10.918 8.882 19.8 19.8 19.8 10.918 0 19.8-8.882 19.8-19.8C81.2 8.883 72.318 0 61.4 0M21.206 31.718h2.505c8.06 0 14.949-6.26 15.24-14.323C39.254 8.95 32.476 1.98 24.103 1.98H3.127C2.504 1.98 2 2.485 2 3.108v34.044c0 .622.504 1.128 1.127 1.128H18.88c.615 0 1.117-.494 1.127-1.11l.073-4.343a1.127 1.127 0 0 1 1.126-1.109M98.002 1.271l-21.295 34.65c-.388.745.16 1.629 1.014 1.632l17.47.067 25.129-.067c.852-.003 1.401-.887 1.013-1.632l-21.294-34.65c-.425-.815-1.612-.815-2.037 0" />
|
||||
</g>
|
||||
|
@ -2,10 +2,7 @@ import React from 'react'
|
||||
|
||||
export const IconTelegram = () => {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
clipRule="evenodd"
|
||||
d="M18.384,22.779c0.322,0.228 0.737,0.285 1.107,0.145c0.37,-0.141 0.642,-0.457 0.724,-0.84c0.869,-4.084 2.977,-14.421 3.768,-18.136c0.06,-0.28 -0.04,-0.571 -0.26,-0.758c-0.22,-0.187 -0.525,-0.241 -0.797,-0.14c-4.193,1.552 -17.106,6.397 -22.384,8.35c-0.335,0.124 -0.553,0.446 -0.542,0.799c0.012,0.354 0.25,0.661 0.593,0.764c2.367,0.708 5.474,1.693 5.474,1.693c0,0 1.452,4.385 2.209,6.615c0.095,0.28 0.314,0.5 0.603,0.576c0.288,0.075 0.596,-0.004 0.811,-0.207c1.216,-1.148 3.096,-2.923 3.096,-2.923c0,0 3.572,2.619 5.598,4.062Zm-11.01,-8.677l1.679,5.538l0.373,-3.507c0,0 6.487,-5.851 10.185,-9.186c0.108,-0.098 0.123,-0.262 0.033,-0.377c-0.089,-0.115 -0.253,-0.142 -0.376,-0.064c-4.286,2.737 -11.894,7.596 -11.894,7.596Z"
|
||||
|
@ -2,10 +2,7 @@ import React from 'react'
|
||||
|
||||
export const IconTwitter = () => {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 16 12"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg viewBox="0 0 16 12" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M15.086.222a6.236 6.236 0 0 1-1.955.735A3.089 3.089 0 0 0 10.885 0c-1.7 0-3.077 1.357-3.077 3.03 0 .237.027.469.079.69A8.781 8.781 0 0 1 1.545.554a2.974 2.974 0 0 0-.416 1.523c0 1.052.544 1.979 1.368 2.522a3.117 3.117 0 0 1-1.393-.381v.038c0 1.468 1.061 2.692 2.468 2.972a3.18 3.18 0 0 1-1.39.051 3.074 3.074 0 0 0 2.874 2.105 6.24 6.24 0 0 1-3.822 1.296c-.248 0-.493-.014-.734-.041A8.814 8.814 0 0 0 5.217 12c5.66 0 8.755-4.617 8.755-8.621l-.01-.393A6.153 6.153 0 0 0 15.5 1.42a6.246 6.246 0 0 1-1.767.477A3.048 3.048 0 0 0 15.086.222z"
|
||||
fillRule="evenodd"
|
||||
|
@ -1,4 +1,4 @@
|
||||
export * from './IconGithub';
|
||||
export * from './IconPOA';
|
||||
export * from './IconTelegram';
|
||||
export * from './IconTwitter';
|
||||
export * from './IconGithub'
|
||||
export * from './IconPOA'
|
||||
export * from './IconTelegram'
|
||||
export * from './IconTwitter'
|
||||
|
@ -4,6 +4,6 @@ export const setItem = (key, data) => {
|
||||
localStorage.setItem(key, data)
|
||||
}
|
||||
|
||||
export const getItem = (key) => {
|
||||
export const getItem = key => {
|
||||
return localStorage.getItem(key)
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
const yn = input => {
|
||||
input = String(input).trim();
|
||||
input = String(input).trim()
|
||||
|
||||
if (/^(?:y|yes|true|1)$/i.test(input)) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
if (/^(?:n|no|false|0)$/i.test(input)) {
|
||||
return false;
|
||||
return false
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
return false
|
||||
}
|
||||
|
||||
export default yn
|
||||
|
@ -1,14 +1,15 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { App } from './App';
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { App } from './App'
|
||||
import { BrowserRouter } from 'react-router-dom'
|
||||
import { Provider } from "mobx-react";
|
||||
import RootStore from './stores/RootStore';
|
||||
import { Provider } from 'mobx-react'
|
||||
import RootStore from './stores/RootStore'
|
||||
|
||||
ReactDOM.render((
|
||||
ReactDOM.render(
|
||||
<Provider RootStore={RootStore}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
), document.getElementById('root'));
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { action, observable } from "mobx";
|
||||
import { action, observable } from 'mobx'
|
||||
|
||||
class AlertStore {
|
||||
@observable alerts = [];
|
||||
@observable showLoading = false;
|
||||
@observable loadingStepIndex = -1;
|
||||
@observable alerts = []
|
||||
@observable showLoading = false
|
||||
@observable loadingStepIndex = -1
|
||||
@observable blockConfirmations = 0
|
||||
@observable showDailyQuotaInfo = false
|
||||
homeConnectionErrorSended = false
|
||||
@ -14,39 +14,39 @@ class AlertStore {
|
||||
'Waiting for Block Confirmations...',
|
||||
'Validators Verifying Transaction...',
|
||||
'Transfer Complete'
|
||||
];
|
||||
]
|
||||
HOME_CONNECTION_ERROR = 'Home Connection Error'
|
||||
FOREIGN_CONNECTION_ERROR = 'Foreign Connection Error'
|
||||
HOME_TRANSFER_SUCCESS = 'Home Transfer Success'
|
||||
FOREIGN_TRANSFER_SUCCESS = 'Foreign Transfer Success'
|
||||
|
||||
@action
|
||||
pushError(message, messageType){
|
||||
console.error("Error: ", message)
|
||||
pushError(message, messageType) {
|
||||
console.error('Error: ', message)
|
||||
const shouldPushError = this.checkErrorPush(messageType, messageType)
|
||||
if(shouldPushError) {
|
||||
const node = document.createElement("div")
|
||||
if (shouldPushError) {
|
||||
const node = document.createElement('div')
|
||||
node.innerHTML = message
|
||||
const error = {
|
||||
title: "Error",
|
||||
title: 'Error',
|
||||
content: node,
|
||||
icon: "error",
|
||||
icon: 'error',
|
||||
messageType
|
||||
}
|
||||
this.alerts.push(error)
|
||||
}
|
||||
}
|
||||
|
||||
checkErrorPush(message, messageType){
|
||||
if(messageType === this.HOME_CONNECTION_ERROR) {
|
||||
if(this.homeConnectionErrorSended) {
|
||||
checkErrorPush(message, messageType) {
|
||||
if (messageType === this.HOME_CONNECTION_ERROR) {
|
||||
if (this.homeConnectionErrorSended) {
|
||||
return false
|
||||
} else {
|
||||
this.homeConnectionErrorSended = true
|
||||
return true
|
||||
}
|
||||
} else if(messageType === this.FOREIGN_CONNECTION_ERROR) {
|
||||
if(this.foreignConnectionErrorSended) {
|
||||
} else if (messageType === this.FOREIGN_CONNECTION_ERROR) {
|
||||
if (this.foreignConnectionErrorSended) {
|
||||
return false
|
||||
} else {
|
||||
this.foreignConnectionErrorSended = true
|
||||
@ -55,31 +55,30 @@ class AlertStore {
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@action
|
||||
pushSuccess(message, messageType){
|
||||
const node = document.createElement("div")
|
||||
pushSuccess(message, messageType) {
|
||||
const node = document.createElement('div')
|
||||
node.innerHTML = message
|
||||
const success = {
|
||||
title: "Success",
|
||||
title: 'Success',
|
||||
content: node,
|
||||
icon: "success",
|
||||
icon: 'success',
|
||||
messageType
|
||||
}
|
||||
this.alerts.push(success)
|
||||
}
|
||||
|
||||
remove(value){
|
||||
const result = this.alerts.remove(value);
|
||||
remove(value) {
|
||||
const result = this.alerts.remove(value)
|
||||
console.log(result, value, this.alerts)
|
||||
}
|
||||
|
||||
@action
|
||||
setLoading(status) {
|
||||
this.showLoading = status;
|
||||
this.loadingStepIndex = 0;
|
||||
this.showLoading = status
|
||||
this.loadingStepIndex = 0
|
||||
this.blockConfirmations = 0
|
||||
}
|
||||
|
||||
@ -90,10 +89,12 @@ class AlertStore {
|
||||
|
||||
@action
|
||||
setLoadingStepIndex(index) {
|
||||
this.loadingStepIndex = index;
|
||||
this.loadingStepIndex = index
|
||||
console.log(this.loadingSteps[index])
|
||||
if(index === this.loadingSteps.length - 1) {
|
||||
setTimeout(() => { this.setLoading(false)}, 2000)
|
||||
if (index === this.loadingSteps.length - 1) {
|
||||
setTimeout(() => {
|
||||
this.setLoading(false)
|
||||
}, 2000)
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,7 +106,6 @@ class AlertStore {
|
||||
setShowDailyQuotaInfo(value) {
|
||||
this.showDailyQuotaInfo = value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AlertStore;
|
||||
export default AlertStore
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { action, observable } from 'mobx';
|
||||
import { abi as ERC677_ABI } from '../contracts/ERC677BridgeToken.json';
|
||||
import { action, observable } from 'mobx'
|
||||
import { abi as ERC677_ABI } from '../contracts/ERC677BridgeToken.json'
|
||||
import { getBlockNumber } from './utils/web3'
|
||||
import {
|
||||
getMaxPerTxLimit,
|
||||
@ -23,65 +23,71 @@ import {
|
||||
} from './utils/contract'
|
||||
import { balanceLoaded, removePendingTransaction } from './utils/testUtils'
|
||||
import sleep from './utils/sleep'
|
||||
import { getBridgeABIs, getUnit, BRIDGE_MODES, decodeFeeManagerMode, FEE_MANAGER_MODE } from './utils/bridgeMode'
|
||||
import {
|
||||
getBridgeABIs,
|
||||
getUnit,
|
||||
BRIDGE_MODES,
|
||||
decodeFeeManagerMode,
|
||||
FEE_MANAGER_MODE
|
||||
} from './utils/bridgeMode'
|
||||
import { abi as BRIDGE_VALIDATORS_ABI } from '../contracts/BridgeValidators'
|
||||
import ERC20Bytes32Abi from './utils/ERC20Bytes32.abi'
|
||||
import BN from 'bignumber.js'
|
||||
import { processLargeArrayAsync } from "./utils/array"
|
||||
import { fromDecimals } from "./utils/decimals"
|
||||
import { processLargeArrayAsync } from './utils/array'
|
||||
import { fromDecimals } from './utils/decimals'
|
||||
|
||||
class ForeignStore {
|
||||
@observable state = null;
|
||||
@observable loading = true;
|
||||
@observable events = [];
|
||||
@observable totalSupply = '';
|
||||
@observable symbol = 'NOSYM';
|
||||
@observable tokenName = '';
|
||||
@observable balance = '';
|
||||
@observable filter = false;
|
||||
@observable maxCurrentDeposit = '';
|
||||
@observable maxPerTx = '';
|
||||
@observable minPerTx = '';
|
||||
@observable latestBlockNumber = 0;
|
||||
@observable state = null
|
||||
@observable loading = true
|
||||
@observable events = []
|
||||
@observable totalSupply = ''
|
||||
@observable symbol = 'NOSYM'
|
||||
@observable tokenName = ''
|
||||
@observable balance = ''
|
||||
@observable filter = false
|
||||
@observable maxCurrentDeposit = ''
|
||||
@observable maxPerTx = ''
|
||||
@observable minPerTx = ''
|
||||
@observable latestBlockNumber = 0
|
||||
@observable validators = []
|
||||
@observable validatorsCount = 0
|
||||
@observable foreignBridgeValidators = ''
|
||||
@observable requiredSignatures = 0
|
||||
@observable dailyLimit = 0
|
||||
@observable totalSpentPerDay = 0
|
||||
@observable tokenAddress = '';
|
||||
@observable tokenAddress = ''
|
||||
@observable feeEventsFinished = false
|
||||
@observable tokenType = ''
|
||||
feeManager = {
|
||||
totalFeeDistributedFromSignatures: BN(0),
|
||||
totalFeeDistributedFromAffirmation: BN(0)
|
||||
};
|
||||
}
|
||||
networkName = process.env.REACT_APP_FOREIGN_NETWORK_NAME || 'Unknown'
|
||||
filteredBlockNumber = 0;
|
||||
foreignBridge = {};
|
||||
filteredBlockNumber = 0
|
||||
foreignBridge = {}
|
||||
tokenContract = {}
|
||||
tokenDecimals = 18;
|
||||
FOREIGN_BRIDGE_ADDRESS = process.env.REACT_APP_FOREIGN_BRIDGE_ADDRESS;
|
||||
tokenDecimals = 18
|
||||
FOREIGN_BRIDGE_ADDRESS = process.env.REACT_APP_FOREIGN_BRIDGE_ADDRESS
|
||||
explorerTxTemplate = process.env.REACT_APP_FOREIGN_EXPLORER_TX_TEMPLATE || ''
|
||||
explorerAddressTemplate = process.env.REACT_APP_FOREIGN_EXPLORER_ADDRESS_TEMPLATE || ''
|
||||
|
||||
constructor (rootStore) {
|
||||
this.web3Store = rootStore.web3Store;
|
||||
constructor(rootStore) {
|
||||
this.web3Store = rootStore.web3Store
|
||||
this.foreignWeb3 = rootStore.web3Store.foreignWeb3
|
||||
this.alertStore = rootStore.alertStore
|
||||
this.homeStore = rootStore.homeStore;
|
||||
this.homeStore = rootStore.homeStore
|
||||
this.rootStore = rootStore
|
||||
this.waitingForConfirmation = new Set()
|
||||
this.setForeign()
|
||||
}
|
||||
|
||||
async setForeign(){
|
||||
async setForeign() {
|
||||
if (!this.rootStore.bridgeModeInitialized) {
|
||||
setTimeout(() => this.setForeign(), 200)
|
||||
return
|
||||
}
|
||||
const { FOREIGN_ABI } = getBridgeABIs(this.rootStore.bridgeMode)
|
||||
this.foreignBridge = new this.foreignWeb3.eth.Contract(FOREIGN_ABI, this.FOREIGN_BRIDGE_ADDRESS);
|
||||
this.foreignBridge = new this.foreignWeb3.eth.Contract(FOREIGN_ABI, this.FOREIGN_BRIDGE_ADDRESS)
|
||||
await this.getBlockNumber()
|
||||
await this.getTokenInfo()
|
||||
this.getMinPerTxLimit()
|
||||
@ -104,65 +110,73 @@ class ForeignStore {
|
||||
async getBlockNumber() {
|
||||
try {
|
||||
this.latestBlockNumber = await getBlockNumber(this.foreignWeb3)
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getMaxPerTxLimit(){
|
||||
async getMaxPerTxLimit() {
|
||||
try {
|
||||
this.maxPerTx = await getMaxPerTxLimit(this.foreignBridge,this.tokenDecimals)
|
||||
} catch(e){
|
||||
this.maxPerTx = await getMaxPerTxLimit(this.foreignBridge, this.tokenDecimals)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getMinPerTxLimit(){
|
||||
async getMinPerTxLimit() {
|
||||
try {
|
||||
this.minPerTx = await getMinPerTxLimit(this.foreignBridge,this.tokenDecimals)
|
||||
} catch(e){
|
||||
this.minPerTx = await getMinPerTxLimit(this.foreignBridge, this.tokenDecimals)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getTokenInfo(){
|
||||
async getTokenInfo() {
|
||||
try {
|
||||
this.tokenAddress = this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC || this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE
|
||||
? await getErc20TokenAddress(this.foreignBridge)
|
||||
: await getErc677TokenAddress(this.foreignBridge)
|
||||
this.tokenContract = new this.foreignWeb3.eth.Contract(ERC677_ABI, this.tokenAddress);
|
||||
this.tokenAddress =
|
||||
this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC ||
|
||||
this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE
|
||||
? await getErc20TokenAddress(this.foreignBridge)
|
||||
: await getErc677TokenAddress(this.foreignBridge)
|
||||
this.tokenContract = new this.foreignWeb3.eth.Contract(ERC677_ABI, this.tokenAddress)
|
||||
this.tokenType = await getTokenType(this.tokenContract, this.FOREIGN_BRIDGE_ADDRESS)
|
||||
const alternativeContract = new this.foreignWeb3.eth.Contract(ERC20Bytes32Abi, this.tokenAddress);
|
||||
const alternativeContract = new this.foreignWeb3.eth.Contract(
|
||||
ERC20Bytes32Abi,
|
||||
this.tokenAddress
|
||||
)
|
||||
try {
|
||||
this.symbol =await getSymbol(this.tokenContract)
|
||||
} catch(e) {
|
||||
this.symbol = this.foreignWeb3.utils.hexToAscii(await getSymbol(alternativeContract)).replace(/\u0000*$/, '')
|
||||
this.symbol = await getSymbol(this.tokenContract)
|
||||
} catch (e) {
|
||||
this.symbol = this.foreignWeb3.utils
|
||||
.hexToAscii(await getSymbol(alternativeContract))
|
||||
.replace(/\u0000*$/, '')
|
||||
}
|
||||
try {
|
||||
this.tokenName = await getName(this.tokenContract)
|
||||
} catch(e) {
|
||||
this.tokenName = this.foreignWeb3.utils.hexToAscii(await getName(alternativeContract)).replace(/\u0000*$/, '')
|
||||
} catch (e) {
|
||||
this.tokenName = this.foreignWeb3.utils
|
||||
.hexToAscii(await getName(alternativeContract))
|
||||
.replace(/\u0000*$/, '')
|
||||
}
|
||||
|
||||
this.tokenDecimals = await getDecimals(this.tokenContract)
|
||||
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getTokenBalance(){
|
||||
async getTokenBalance() {
|
||||
try {
|
||||
this.totalSupply = await getTotalSupply(this.tokenContract)
|
||||
this.web3Store.getWeb3Promise.then(async () => {
|
||||
this.balance = await getBalanceOf(this.tokenContract, this.web3Store.defaultAccount.address)
|
||||
balanceLoaded()
|
||||
})
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -174,74 +188,88 @@ class ForeignStore {
|
||||
const feeManagerModeHash = await getFeeManagerMode(this.foreignBridge)
|
||||
this.feeManager.feeManagerMode = decodeFeeManagerMode(feeManagerModeHash)
|
||||
|
||||
if(this.feeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION) {
|
||||
this.feeManager.foreignFee = new BN(0);
|
||||
if (this.feeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION) {
|
||||
this.feeManager.foreignFee = new BN(0)
|
||||
this.feeManager.homeFee = await getHomeFee(this.foreignBridge)
|
||||
}
|
||||
} else {
|
||||
this.feeManager.feeManagerMode = FEE_MANAGER_MODE.UNDEFINED
|
||||
this.feeManager.homeFee = new BN(0);
|
||||
this.feeManager.foreignFee = new BN(0);
|
||||
this.feeManager.homeFee = new BN(0)
|
||||
this.feeManager.foreignFee = new BN(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
async getEvents(fromBlock, toBlock) {
|
||||
try {
|
||||
fromBlock = fromBlock || this.filteredBlockNumber || this.latestBlockNumber - 50
|
||||
toBlock = toBlock || this.filteredBlockNumber || "latest"
|
||||
toBlock = toBlock || this.filteredBlockNumber || 'latest'
|
||||
|
||||
if (fromBlock < 0) {
|
||||
fromBlock = 0
|
||||
}
|
||||
|
||||
let foreignEvents = await getPastEvents(this.foreignBridge, fromBlock, toBlock).catch(e => {
|
||||
console.error('Couldn\'t get events', e)
|
||||
console.error("Couldn't get events", e)
|
||||
return []
|
||||
})
|
||||
|
||||
if(!this.filter){
|
||||
this.events = foreignEvents;
|
||||
if (!this.filter) {
|
||||
this.events = foreignEvents
|
||||
}
|
||||
|
||||
if(this.waitingForConfirmation.size) {
|
||||
const confirmationEvents = foreignEvents.filter((event) => event.event === "RelayedMessage" && this.waitingForConfirmation.has(event.returnValues.transactionHash))
|
||||
if (this.waitingForConfirmation.size) {
|
||||
const confirmationEvents = foreignEvents.filter(
|
||||
event =>
|
||||
event.event === 'RelayedMessage' &&
|
||||
this.waitingForConfirmation.has(event.returnValues.transactionHash)
|
||||
)
|
||||
confirmationEvents.forEach(async event => {
|
||||
const TxReceipt = await this.getTxReceipt(event.transactionHash)
|
||||
if(TxReceipt && TxReceipt.logs && TxReceipt.logs.length > 1 && this.waitingForConfirmation.size) {
|
||||
if (
|
||||
TxReceipt &&
|
||||
TxReceipt.logs &&
|
||||
TxReceipt.logs.length > 1 &&
|
||||
this.waitingForConfirmation.size
|
||||
) {
|
||||
this.alertStore.setLoadingStepIndex(3)
|
||||
const urlExplorer = this.getExplorerTxUrl(event.transactionHash)
|
||||
const unitReceived = getUnit(this.rootStore.bridgeMode).unitForeign
|
||||
setTimeout(() => {
|
||||
this.alertStore.pushSuccess(`${unitReceived} received on ${this.networkName} on Tx
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.networkName} on Tx
|
||||
<a href='${urlExplorer}' target='blank' style="overflow-wrap: break-word;word-wrap: break-word;">
|
||||
${event.transactionHash}</a>`, this.alertStore.FOREIGN_TRANSFER_SUCCESS)}
|
||||
, 2000)
|
||||
${event.transactionHash}</a>`,
|
||||
this.alertStore.FOREIGN_TRANSFER_SUCCESS
|
||||
)
|
||||
}, 2000)
|
||||
this.waitingForConfirmation.delete(event.returnValues.transactionHash)
|
||||
}
|
||||
})
|
||||
|
||||
if(confirmationEvents.length) {
|
||||
if (confirmationEvents.length) {
|
||||
removePendingTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
return foreignEvents
|
||||
} catch(e) {
|
||||
this.alertStore.pushError(`Cannot establish connection to Foreign Network.\n
|
||||
Please make sure you have set it up in env variables`, this.alertStore.FOREIGN_CONNECTION_ERROR)
|
||||
} catch (e) {
|
||||
this.alertStore.pushError(
|
||||
`Cannot establish connection to Foreign Network.\n
|
||||
Please make sure you have set it up in env variables`,
|
||||
this.alertStore.FOREIGN_CONNECTION_ERROR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getCurrentLimit(){
|
||||
async getCurrentLimit() {
|
||||
try {
|
||||
const result = await getCurrentLimit(this.foreignBridge,this.tokenDecimals)
|
||||
const result = await getCurrentLimit(this.foreignBridge, this.tokenDecimals)
|
||||
this.maxCurrentDeposit = result.maxCurrentDeposit
|
||||
this.dailyLimit = result.dailyLimit
|
||||
this.totalSpentPerDay = result.totalSpentPerDay
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -263,22 +291,23 @@ class ForeignStore {
|
||||
const txReceipt = await this.getTxReceipt(transactionHash)
|
||||
const from = txReceipt.blockNumber - 20
|
||||
const to = txReceipt.blockNumber + 20
|
||||
const events = await this.getEvents(from, to);
|
||||
this.events = events.filter((event) => event.transactionHash === transactionHash || event.signedTxHash === transactionHash)
|
||||
const events = await this.getEvents(from, to)
|
||||
this.events = events.filter(
|
||||
event => event.transactionHash === transactionHash || event.signedTxHash === transactionHash
|
||||
)
|
||||
} catch (e) {
|
||||
this.events = []
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async setBlockFilter(blockNumber){
|
||||
async setBlockFilter(blockNumber) {
|
||||
this.filteredBlockNumber = blockNumber
|
||||
this.events = await this.getEvents()
|
||||
}
|
||||
|
||||
|
||||
@action
|
||||
setFilter(value){
|
||||
setFilter(value) {
|
||||
this.filter = value
|
||||
}
|
||||
|
||||
@ -293,7 +322,7 @@ class ForeignStore {
|
||||
}
|
||||
|
||||
getDailyQuotaCompleted() {
|
||||
return this.dailyLimit ? this.totalSpentPerDay / this.dailyLimit * 100 : 0
|
||||
return this.dailyLimit ? (this.totalSpentPerDay / this.dailyLimit) * 100 : 0
|
||||
}
|
||||
|
||||
async waitUntilProcessed(txHash) {
|
||||
@ -317,44 +346,50 @@ class ForeignStore {
|
||||
}
|
||||
|
||||
@action
|
||||
async getValidators(){
|
||||
async getValidators() {
|
||||
try {
|
||||
const foreignValidatorsAddress = await this.foreignBridge.methods.validatorContract().call()
|
||||
this.foreignBridgeValidators = new this.foreignWeb3.eth.Contract(BRIDGE_VALIDATORS_ABI, foreignValidatorsAddress);
|
||||
this.foreignBridgeValidators = new this.foreignWeb3.eth.Contract(
|
||||
BRIDGE_VALIDATORS_ABI,
|
||||
foreignValidatorsAddress
|
||||
)
|
||||
|
||||
this.requiredSignatures = await this.foreignBridgeValidators.methods.requiredSignatures().call()
|
||||
this.requiredSignatures = await this.foreignBridgeValidators.methods
|
||||
.requiredSignatures()
|
||||
.call()
|
||||
this.validatorsCount = await this.foreignBridgeValidators.methods.validatorCount().call()
|
||||
|
||||
this.validators = await getValidatorList(foreignValidatorsAddress, this.foreignWeb3.eth)
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async getFeeEvents() {
|
||||
try {
|
||||
const deployedAtBlock = await getDeployedAtBlock(this.foreignBridge);
|
||||
const deployedAtBlock = await getDeployedAtBlock(this.foreignBridge)
|
||||
const events = await getPastEvents(this.foreignBridge, deployedAtBlock, 'latest')
|
||||
|
||||
processLargeArrayAsync(
|
||||
events,
|
||||
this.processEvent,
|
||||
() => {
|
||||
this.feeEventsFinished = true
|
||||
})
|
||||
} catch(e){
|
||||
processLargeArrayAsync(events, this.processEvent, () => {
|
||||
this.feeEventsFinished = true
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.getFeeEvents()
|
||||
}
|
||||
}
|
||||
|
||||
processEvent = (event) => {
|
||||
if (event.event === "FeeDistributedFromSignatures") {
|
||||
this.feeManager.totalFeeDistributedFromSignatures = this.feeManager.totalFeeDistributedFromSignatures.plus(BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals)))
|
||||
} else if (event.event === "FeeDistributedFromAffirmation") {
|
||||
this.feeManager.totalFeeDistributedFromAffirmation = this.feeManager.totalFeeDistributedFromAffirmation.plus(BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals)))
|
||||
processEvent = event => {
|
||||
if (event.event === 'FeeDistributedFromSignatures') {
|
||||
this.feeManager.totalFeeDistributedFromSignatures = this.feeManager.totalFeeDistributedFromSignatures.plus(
|
||||
BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals))
|
||||
)
|
||||
} else if (event.event === 'FeeDistributedFromAffirmation') {
|
||||
this.feeManager.totalFeeDistributedFromAffirmation = this.feeManager.totalFeeDistributedFromAffirmation.plus(
|
||||
BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default ForeignStore;
|
||||
export default ForeignStore
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { observable, computed } from "mobx";
|
||||
import { toHex } from 'web3-utils';
|
||||
import { observable, computed } from 'mobx'
|
||||
import { toHex } from 'web3-utils'
|
||||
import { fetchGasPrice, fetchGasPriceFromOracle } from './utils/gas'
|
||||
|
||||
const HOME_GAS_PRICE_FALLBACK = process.env.REACT_APP_HOME_GAS_PRICE_FALLBACK
|
||||
@ -58,4 +58,4 @@ class GasPriceStore {
|
||||
}
|
||||
}
|
||||
|
||||
export default GasPriceStore;
|
||||
export default GasPriceStore
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { action, observable } from 'mobx';
|
||||
import { action, observable } from 'mobx'
|
||||
import { abi as BRIDGE_VALIDATORS_ABI } from '../contracts/BridgeValidators.json'
|
||||
import { abi as ERC677_ABI } from '../contracts/ERC677BridgeToken.json'
|
||||
import { abi as BLOCK_REWARD_ABI } from '../contracts/IBlockReward'
|
||||
@ -29,10 +29,16 @@ import {
|
||||
import { balanceLoaded, removePendingTransaction } from './utils/testUtils'
|
||||
import sleep from './utils/sleep'
|
||||
import BN from 'bignumber.js'
|
||||
import { getBridgeABIs, getUnit, BRIDGE_MODES, decodeFeeManagerMode, FEE_MANAGER_MODE } from './utils/bridgeMode'
|
||||
import {
|
||||
getBridgeABIs,
|
||||
getUnit,
|
||||
BRIDGE_MODES,
|
||||
decodeFeeManagerMode,
|
||||
FEE_MANAGER_MODE
|
||||
} from './utils/bridgeMode'
|
||||
import ERC20Bytes32Abi from './utils/ERC20Bytes32.abi'
|
||||
import { processLargeArrayAsync } from './utils/array'
|
||||
import { getRewardableData } from "./utils/rewardable"
|
||||
import { getRewardableData } from './utils/rewardable'
|
||||
import HomeBridgeV1Abi from './utils/HomeBridgeV1.abi'
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
@ -42,24 +48,24 @@ async function asyncForEach(array, callback) {
|
||||
}
|
||||
|
||||
class HomeStore {
|
||||
@observable state = null;
|
||||
@observable loading = true;
|
||||
@observable events = [];
|
||||
@observable errors = [];
|
||||
@observable balance = "";
|
||||
@observable filter = false;
|
||||
@observable maxCurrentDeposit = "";
|
||||
@observable maxPerTx = "";
|
||||
@observable latestBlockNumber = 0;
|
||||
@observable state = null
|
||||
@observable loading = true
|
||||
@observable events = []
|
||||
@observable errors = []
|
||||
@observable balance = ''
|
||||
@observable filter = false
|
||||
@observable maxCurrentDeposit = ''
|
||||
@observable maxPerTx = ''
|
||||
@observable latestBlockNumber = 0
|
||||
@observable validators = []
|
||||
@observable validatorsCount = 0
|
||||
@observable homeBridgeValidators = ''
|
||||
@observable requiredSignatures = 0
|
||||
@observable dailyLimit = 0
|
||||
@observable totalSpentPerDay = 0
|
||||
@observable tokenAddress = '';
|
||||
@observable symbol = process.env.REACT_APP_HOME_NATIVE_NAME || 'NONAME';
|
||||
@observable tokenName = '';
|
||||
@observable tokenAddress = ''
|
||||
@observable symbol = process.env.REACT_APP_HOME_NATIVE_NAME || 'NONAME'
|
||||
@observable tokenName = ''
|
||||
@observable userBalance = 0
|
||||
@observable statistics = {
|
||||
deposits: 0,
|
||||
@ -85,18 +91,18 @@ class HomeStore {
|
||||
feeManager = {
|
||||
totalFeeDistributedFromSignatures: BN(0),
|
||||
totalFeeDistributedFromAffirmation: BN(0)
|
||||
};
|
||||
}
|
||||
networkName = process.env.REACT_APP_HOME_NETWORK_NAME || 'Unknown'
|
||||
filteredBlockNumber = 0
|
||||
homeBridge = {};
|
||||
HOME_BRIDGE_ADDRESS = process.env.REACT_APP_HOME_BRIDGE_ADDRESS;
|
||||
homeBridge = {}
|
||||
HOME_BRIDGE_ADDRESS = process.env.REACT_APP_HOME_BRIDGE_ADDRESS
|
||||
explorerTxTemplate = process.env.REACT_APP_HOME_EXPLORER_TX_TEMPLATE || ''
|
||||
explorerAddressTemplate = process.env.REACT_APP_HOME_EXPLORER_ADDRESS_TEMPLATE || ''
|
||||
tokenContract = {}
|
||||
tokenDecimals = 18;
|
||||
tokenDecimals = 18
|
||||
blockRewardContract = {}
|
||||
|
||||
constructor (rootStore) {
|
||||
constructor(rootStore) {
|
||||
this.homeWeb3 = rootStore.web3Store.homeWeb3
|
||||
this.web3Store = rootStore.web3Store
|
||||
this.alertStore = rootStore.alertStore
|
||||
@ -105,16 +111,16 @@ class HomeStore {
|
||||
this.setHome()
|
||||
}
|
||||
|
||||
async setHome(){
|
||||
async setHome() {
|
||||
if (!this.rootStore.bridgeModeInitialized) {
|
||||
setTimeout(() => this.setHome(), 200)
|
||||
return
|
||||
}
|
||||
const { HOME_ABI } = getBridgeABIs(this.rootStore.bridgeMode)
|
||||
this.homeBridge = new this.homeWeb3.eth.Contract(HOME_ABI, this.HOME_BRIDGE_ADDRESS);
|
||||
this.homeBridge = new this.homeWeb3.eth.Contract(HOME_ABI, this.HOME_BRIDGE_ADDRESS)
|
||||
if (this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||
await this.getTokenInfo()
|
||||
} else if(this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
} else if (this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
await this.getBlockRewardContract()
|
||||
}
|
||||
await this.getBlockNumber()
|
||||
@ -139,22 +145,26 @@ class HomeStore {
|
||||
async getTokenInfo() {
|
||||
try {
|
||||
this.tokenAddress = await getErc677TokenAddress(this.homeBridge)
|
||||
this.tokenContract = new this.homeWeb3.eth.Contract(ERC677_ABI, this.tokenAddress);
|
||||
this.tokenContract = new this.homeWeb3.eth.Contract(ERC677_ABI, this.tokenAddress)
|
||||
this.symbol = await getSymbol(this.tokenContract)
|
||||
this.tokenName = await getName(this.tokenContract)
|
||||
const alternativeContract = new this.homeWeb3.eth.Contract(ERC20Bytes32Abi, this.tokenAddress);
|
||||
const alternativeContract = new this.homeWeb3.eth.Contract(ERC20Bytes32Abi, this.tokenAddress)
|
||||
try {
|
||||
this.symbol =await getSymbol(this.tokenContract)
|
||||
} catch(e) {
|
||||
this.symbol = this.homeWeb3.utils.hexToAscii(await getSymbol(alternativeContract)).replace(/\u0000*$/, '')
|
||||
this.symbol = await getSymbol(this.tokenContract)
|
||||
} catch (e) {
|
||||
this.symbol = this.homeWeb3.utils
|
||||
.hexToAscii(await getSymbol(alternativeContract))
|
||||
.replace(/\u0000*$/, '')
|
||||
}
|
||||
try {
|
||||
this.tokenName = await getName(this.tokenContract)
|
||||
} catch(e) {
|
||||
this.tokenName = this.homeWeb3.utils.hexToAscii(await getName(alternativeContract)).replace(/\u0000*$/, '')
|
||||
} catch (e) {
|
||||
this.tokenName = this.homeWeb3.utils
|
||||
.hexToAscii(await getName(alternativeContract))
|
||||
.replace(/\u0000*$/, '')
|
||||
}
|
||||
this.tokenDecimals = await getDecimals(this.tokenContract)
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -163,25 +173,25 @@ class HomeStore {
|
||||
async getBlockNumber() {
|
||||
try {
|
||||
this.latestBlockNumber = await getBlockNumber(this.homeWeb3)
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getMaxPerTxLimit(){
|
||||
async getMaxPerTxLimit() {
|
||||
try {
|
||||
this.maxPerTx = await getMaxPerTxLimit(this.homeBridge,this.tokenDecimals)
|
||||
} catch(e){
|
||||
this.maxPerTx = await getMaxPerTxLimit(this.homeBridge, this.tokenDecimals)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async getMinPerTxLimit(){
|
||||
async getMinPerTxLimit() {
|
||||
try {
|
||||
this.minPerTx = await getMinPerTxLimit(this.homeBridge,this.tokenDecimals)
|
||||
} catch(e){
|
||||
this.minPerTx = await getMinPerTxLimit(this.homeBridge, this.tokenDecimals)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -192,17 +202,20 @@ class HomeStore {
|
||||
if (this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC) {
|
||||
this.balance = await getTotalSupply(this.tokenContract)
|
||||
this.web3Store.getWeb3Promise.then(async () => {
|
||||
this.userBalance = await getBalanceOf(this.tokenContract, this.web3Store.defaultAccount.address)
|
||||
this.userBalance = await getBalanceOf(
|
||||
this.tokenContract,
|
||||
this.web3Store.defaultAccount.address
|
||||
)
|
||||
balanceLoaded()
|
||||
})
|
||||
} else if (this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_NATIVE) {
|
||||
const mintedCoins = await mintedTotally(this.blockRewardContract)
|
||||
const burntCoins = await totalBurntCoins(this.homeBridge)
|
||||
this.balance = fromDecimals(mintedCoins.minus(burntCoins).toString(10),this.tokenDecimals)
|
||||
this.balance = fromDecimals(mintedCoins.minus(burntCoins).toString(10), this.tokenDecimals)
|
||||
} else {
|
||||
this.balance = await getBalance(this.homeWeb3, this.HOME_BRIDGE_ADDRESS)
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.errors.push(e)
|
||||
}
|
||||
@ -215,17 +228,17 @@ class HomeStore {
|
||||
const feeManagerModeHash = await getFeeManagerMode(this.homeBridge)
|
||||
this.feeManager.feeManagerMode = decodeFeeManagerMode(feeManagerModeHash)
|
||||
|
||||
if(this.feeManager.feeManagerMode === FEE_MANAGER_MODE.BOTH_DIRECTIONS) {
|
||||
if (this.feeManager.feeManagerMode === FEE_MANAGER_MODE.BOTH_DIRECTIONS) {
|
||||
this.feeManager.homeFee = await getHomeFee(this.homeBridge)
|
||||
this.feeManager.foreignFee = await getForeignFee(this.homeBridge)
|
||||
} else {
|
||||
this.feeManager.homeFee = new BN(0);
|
||||
this.feeManager.homeFee = new BN(0)
|
||||
this.feeManager.foreignFee = await getForeignFee(this.homeBridge)
|
||||
}
|
||||
} else {
|
||||
this.feeManager.feeManagerMode = FEE_MANAGER_MODE.UNDEFINED
|
||||
this.feeManager.homeFee = new BN(0);
|
||||
this.feeManager.foreignFee = new BN(0);
|
||||
this.feeManager.homeFee = new BN(0)
|
||||
this.feeManager.foreignFee = new BN(0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,60 +246,70 @@ class HomeStore {
|
||||
async getEvents(fromBlock, toBlock) {
|
||||
try {
|
||||
fromBlock = fromBlock || this.filteredBlockNumber || this.latestBlockNumber - 50
|
||||
toBlock = toBlock || this.filteredBlockNumber || "latest"
|
||||
toBlock = toBlock || this.filteredBlockNumber || 'latest'
|
||||
|
||||
if (fromBlock < 0) {
|
||||
fromBlock = 0
|
||||
}
|
||||
|
||||
let events = await getPastEvents(this.homeBridge, fromBlock, toBlock).catch(e => {
|
||||
console.error('Couldn\'t get events', e)
|
||||
console.error("Couldn't get events", e)
|
||||
return []
|
||||
})
|
||||
|
||||
let homeEvents = []
|
||||
await asyncForEach(events, (async (event) => {
|
||||
if(event.event === "SignedForUserRequest" || event.event === "CollectedSignatures") {
|
||||
await asyncForEach(events, async event => {
|
||||
if (event.event === 'SignedForUserRequest' || event.event === 'CollectedSignatures') {
|
||||
event.signedTxHash = await this.getSignedTx(event.returnValues.messageHash)
|
||||
}
|
||||
homeEvents.push(event)
|
||||
}))
|
||||
})
|
||||
|
||||
if(!this.filter){
|
||||
this.events = homeEvents;
|
||||
if (!this.filter) {
|
||||
this.events = homeEvents
|
||||
}
|
||||
|
||||
if(this.waitingForConfirmation.size) {
|
||||
const confirmationEvents = homeEvents.filter((event) => event.event === "AffirmationCompleted" && this.waitingForConfirmation.has(event.returnValues.transactionHash))
|
||||
if (this.waitingForConfirmation.size) {
|
||||
const confirmationEvents = homeEvents.filter(
|
||||
event =>
|
||||
event.event === 'AffirmationCompleted' &&
|
||||
this.waitingForConfirmation.has(event.returnValues.transactionHash)
|
||||
)
|
||||
confirmationEvents.forEach(event => {
|
||||
this.alertStore.setLoadingStepIndex(3)
|
||||
const urlExplorer = this.getExplorerTxUrl(event.transactionHash)
|
||||
const unitReceived = getUnit(this.rootStore.bridgeMode).unitHome
|
||||
setTimeout(() => {
|
||||
this.alertStore.pushSuccess(`${unitReceived} received on ${this.networkName} on Tx
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.networkName} on Tx
|
||||
<a href='${urlExplorer}' target='blank' style="overflow-wrap: break-word;word-wrap: break-word;">
|
||||
${event.transactionHash}</a>`, this.alertStore.HOME_TRANSFER_SUCCESS)}
|
||||
, 2000)
|
||||
${event.transactionHash}</a>`,
|
||||
this.alertStore.HOME_TRANSFER_SUCCESS
|
||||
)
|
||||
}, 2000)
|
||||
this.waitingForConfirmation.delete(event.returnValues.transactionHash)
|
||||
})
|
||||
|
||||
if(confirmationEvents.length) {
|
||||
if (confirmationEvents.length) {
|
||||
removePendingTransaction()
|
||||
}
|
||||
}
|
||||
|
||||
return homeEvents
|
||||
} catch(e) {
|
||||
this.alertStore.pushError(`Cannot establish connection to Home Network.\n
|
||||
Please make sure you have set it up in env variables`, this.alertStore.HOME_CONNECTION_ERROR)
|
||||
} catch (e) {
|
||||
this.alertStore.pushError(
|
||||
`Cannot establish connection to Home Network.\n
|
||||
Please make sure you have set it up in env variables`,
|
||||
this.alertStore.HOME_CONNECTION_ERROR
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async getSignedTx(messageHash){
|
||||
async getSignedTx(messageHash) {
|
||||
try {
|
||||
const message = await getMessage(this.homeBridge, messageHash)
|
||||
return "0x" + message.substring(106, 170);
|
||||
} catch(e){
|
||||
return '0x' + message.substring(106, 170)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -301,37 +324,43 @@ class HomeStore {
|
||||
|
||||
@action
|
||||
async filterByTxHashInReturnValues(transactionHash) {
|
||||
const events = await this.getEvents(1,"latest");
|
||||
this.events = events.filter((event) => event.returnValues.transactionHash === transactionHash)
|
||||
const events = await this.getEvents(1, 'latest')
|
||||
this.events = events.filter(event => event.returnValues.transactionHash === transactionHash)
|
||||
}
|
||||
@action
|
||||
async filterByTxHash(transactionHash) {
|
||||
const events = await this.getEvents(1,"latest");
|
||||
this.events = events.filter((event) => event.transactionHash === transactionHash)
|
||||
if(this.events.length > 0 && this.events[0].returnValues && this.events[0].returnValues.transactionHash) {
|
||||
await this.rootStore.foreignStore.filterByTxHashInReturnValues(this.events[0].returnValues.transactionHash)
|
||||
const events = await this.getEvents(1, 'latest')
|
||||
this.events = events.filter(event => event.transactionHash === transactionHash)
|
||||
if (
|
||||
this.events.length > 0 &&
|
||||
this.events[0].returnValues &&
|
||||
this.events[0].returnValues.transactionHash
|
||||
) {
|
||||
await this.rootStore.foreignStore.filterByTxHashInReturnValues(
|
||||
this.events[0].returnValues.transactionHash
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
setFilter(value){
|
||||
setFilter(value) {
|
||||
this.filter = value
|
||||
}
|
||||
|
||||
@action
|
||||
async setBlockFilter(blockNumber){
|
||||
async setBlockFilter(blockNumber) {
|
||||
this.filteredBlockNumber = blockNumber
|
||||
this.events = await this.getEvents()
|
||||
}
|
||||
|
||||
@action
|
||||
async getCurrentLimit(){
|
||||
async getCurrentLimit() {
|
||||
try {
|
||||
const result = await getCurrentLimit(this.homeBridge,this.tokenDecimals)
|
||||
const result = await getCurrentLimit(this.homeBridge, this.tokenDecimals)
|
||||
this.maxCurrentDeposit = result.maxCurrentDeposit
|
||||
this.dailyLimit = result.dailyLimit
|
||||
this.totalSpentPerDay = result.totalSpentPerDay
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
@ -343,94 +372,114 @@ class HomeStore {
|
||||
}
|
||||
|
||||
@action
|
||||
async getValidators(){
|
||||
async getValidators() {
|
||||
try {
|
||||
const homeValidatorsAddress = await this.homeBridge.methods.validatorContract().call()
|
||||
this.homeBridgeValidators = new this.homeWeb3.eth.Contract(BRIDGE_VALIDATORS_ABI, homeValidatorsAddress);
|
||||
this.homeBridgeValidators = new this.homeWeb3.eth.Contract(
|
||||
BRIDGE_VALIDATORS_ABI,
|
||||
homeValidatorsAddress
|
||||
)
|
||||
|
||||
this.requiredSignatures = await this.homeBridgeValidators.methods.requiredSignatures().call()
|
||||
this.validatorsCount = await this.homeBridgeValidators.methods.validatorCount().call()
|
||||
|
||||
this.validators = await getValidatorList(homeValidatorsAddress, this.homeWeb3.eth)
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
async getStatistics() {
|
||||
try {
|
||||
const deployedAtBlock = await getDeployedAtBlock(this.homeBridge);
|
||||
const deployedAtBlock = await getDeployedAtBlock(this.homeBridge)
|
||||
const { HOME_ABI } = getBridgeABIs(this.rootStore.bridgeMode)
|
||||
const abi = [...HomeBridgeV1Abi, ...HOME_ABI]
|
||||
const contract = new this.homeWeb3.eth.Contract(abi, this.HOME_BRIDGE_ADDRESS);
|
||||
const contract = new this.homeWeb3.eth.Contract(abi, this.HOME_BRIDGE_ADDRESS)
|
||||
const events = await getPastEvents(contract, deployedAtBlock, 'latest')
|
||||
processLargeArrayAsync(
|
||||
events,
|
||||
this.processEvent,
|
||||
() => {
|
||||
this.statistics.finished = true
|
||||
this.statistics.totalBridged = this.statistics.depositsValue.plus(this.statistics.withdrawsValue)
|
||||
})
|
||||
} catch(e){
|
||||
processLargeArrayAsync(events, this.processEvent, () => {
|
||||
this.statistics.finished = true
|
||||
this.statistics.totalBridged = this.statistics.depositsValue.plus(
|
||||
this.statistics.withdrawsValue
|
||||
)
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
this.getStatistics()
|
||||
}
|
||||
}
|
||||
|
||||
processEvent = (event) => {
|
||||
if(event.returnValues && event.returnValues.recipient) {
|
||||
processEvent = event => {
|
||||
if (event.returnValues && event.returnValues.recipient) {
|
||||
this.statistics.users.add(event.returnValues.recipient)
|
||||
}
|
||||
if(event.event === "UserRequestForSignature" || event.event === 'Deposit') {
|
||||
if (event.event === 'UserRequestForSignature' || event.event === 'Deposit') {
|
||||
this.statistics.deposits++
|
||||
this.statistics.depositsValue = this.statistics.depositsValue.plus(BN(fromDecimals(event.returnValues.value,this.tokenDecimals)))
|
||||
} else if (event.event === "AffirmationCompleted" || event.event === 'Withdraw') {
|
||||
this.statistics.depositsValue = this.statistics.depositsValue.plus(
|
||||
BN(fromDecimals(event.returnValues.value, this.tokenDecimals))
|
||||
)
|
||||
} else if (event.event === 'AffirmationCompleted' || event.event === 'Withdraw') {
|
||||
this.statistics.withdraws++
|
||||
this.statistics.withdrawsValue = this.statistics.withdrawsValue.plus(BN(fromDecimals(event.returnValues.value,this.tokenDecimals)))
|
||||
} else if (event.event === "FeeDistributedFromSignatures") {
|
||||
this.feeManager.totalFeeDistributedFromSignatures = this.feeManager.totalFeeDistributedFromSignatures.plus(BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals)))
|
||||
} else if (event.event === "FeeDistributedFromAffirmation") {
|
||||
this.feeManager.totalFeeDistributedFromAffirmation = this.feeManager.totalFeeDistributedFromAffirmation.plus(BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals)))
|
||||
this.statistics.withdrawsValue = this.statistics.withdrawsValue.plus(
|
||||
BN(fromDecimals(event.returnValues.value, this.tokenDecimals))
|
||||
)
|
||||
} else if (event.event === 'FeeDistributedFromSignatures') {
|
||||
this.feeManager.totalFeeDistributedFromSignatures = this.feeManager.totalFeeDistributedFromSignatures.plus(
|
||||
BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals))
|
||||
)
|
||||
} else if (event.event === 'FeeDistributedFromAffirmation') {
|
||||
this.feeManager.totalFeeDistributedFromAffirmation = this.feeManager.totalFeeDistributedFromAffirmation.plus(
|
||||
BN(fromDecimals(event.returnValues.feeAmount, this.tokenDecimals))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
calculateCollectedFees() {
|
||||
if (!this.statistics.finished
|
||||
|| !this.rootStore.foreignStore.feeEventsFinished
|
||||
|| !this.feeManager.feeManagerMode
|
||||
|| !this.rootStore.foreignStore.feeManager.feeManagerMode) {
|
||||
setTimeout(() => { this.calculateCollectedFees() }, 1000)
|
||||
if (
|
||||
!this.statistics.finished ||
|
||||
!this.rootStore.foreignStore.feeEventsFinished ||
|
||||
!this.feeManager.feeManagerMode ||
|
||||
!this.rootStore.foreignStore.feeManager.feeManagerMode
|
||||
) {
|
||||
setTimeout(() => {
|
||||
this.calculateCollectedFees()
|
||||
}, 1000)
|
||||
return
|
||||
}
|
||||
|
||||
const data = getRewardableData(this.feeManager, this.rootStore.foreignStore.feeManager)
|
||||
|
||||
this.depositFeeCollected.type = data.depositSymbol === 'home' ? this.symbol : this.rootStore.foreignStore.symbol
|
||||
this.withdrawFeeCollected.type = data.withdrawSymbol === 'home' ? this.symbol : this.rootStore.foreignStore.symbol
|
||||
this.depositFeeCollected.type =
|
||||
data.depositSymbol === 'home' ? this.symbol : this.rootStore.foreignStore.symbol
|
||||
this.withdrawFeeCollected.type =
|
||||
data.withdrawSymbol === 'home' ? this.symbol : this.rootStore.foreignStore.symbol
|
||||
this.depositFeeCollected.shouldDisplay = data.displayDeposit
|
||||
this.withdrawFeeCollected.shouldDisplay = data.displayWithdraw
|
||||
|
||||
this.depositFeeCollected.value = data.depositSymbol === 'home'
|
||||
? this.feeManager.totalFeeDistributedFromSignatures
|
||||
: this.rootStore.foreignStore.feeManager.totalFeeDistributedFromSignatures
|
||||
this.depositFeeCollected.value =
|
||||
data.depositSymbol === 'home'
|
||||
? this.feeManager.totalFeeDistributedFromSignatures
|
||||
: this.rootStore.foreignStore.feeManager.totalFeeDistributedFromSignatures
|
||||
|
||||
this.withdrawFeeCollected.value = data.withdrawSymbol === 'home'
|
||||
? this.feeManager.totalFeeDistributedFromAffirmation
|
||||
: this.rootStore.foreignStore.feeManager.totalFeeDistributedFromAffirmation
|
||||
this.withdrawFeeCollected.value =
|
||||
data.withdrawSymbol === 'home'
|
||||
? this.feeManager.totalFeeDistributedFromAffirmation
|
||||
: this.rootStore.foreignStore.feeManager.totalFeeDistributedFromAffirmation
|
||||
|
||||
this.depositFeeCollected.finished = true
|
||||
this.withdrawFeeCollected.finished = true
|
||||
}
|
||||
|
||||
getDailyQuotaCompleted() {
|
||||
return this.dailyLimit ? this.totalSpentPerDay / this.dailyLimit * 100 : 0
|
||||
return this.dailyLimit ? (this.totalSpentPerDay / this.dailyLimit) * 100 : 0
|
||||
}
|
||||
|
||||
getDisplayedBalance() {
|
||||
return this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC ? this.userBalance : this.web3Store.defaultAccount.homeBalance
|
||||
return this.rootStore.bridgeMode === BRIDGE_MODES.ERC_TO_ERC
|
||||
? this.userBalance
|
||||
: this.web3Store.defaultAccount.homeBalance
|
||||
}
|
||||
|
||||
async getBlockRewardContract () {
|
||||
async getBlockRewardContract() {
|
||||
const blockRewardAddress = await this.homeBridge.methods.blockRewardContract().call()
|
||||
this.blockRewardContract = new this.homeWeb3.eth.Contract(BLOCK_REWARD_ABI, blockRewardAddress)
|
||||
}
|
||||
@ -452,4 +501,4 @@ class HomeStore {
|
||||
}
|
||||
}
|
||||
|
||||
export default HomeStore;
|
||||
export default HomeStore
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { action } from 'mobx';
|
||||
import { action } from 'mobx'
|
||||
import Web3Store from './Web3Store'
|
||||
import HomeStore from './HomeStore'
|
||||
import ForeignStore from './ForeignStore'
|
||||
@ -24,11 +24,14 @@ class RootStore {
|
||||
@action
|
||||
async setBridgeMode() {
|
||||
const homeWeb3 = getWeb3Instance(process.env.REACT_APP_HOME_HTTP_PARITY_URL)
|
||||
const homeBridge = new homeWeb3.eth.Contract(HOME_ERC_ABI, process.env.REACT_APP_HOME_BRIDGE_ADDRESS)
|
||||
const homeBridge = new homeWeb3.eth.Contract(
|
||||
HOME_ERC_ABI,
|
||||
process.env.REACT_APP_HOME_BRIDGE_ADDRESS
|
||||
)
|
||||
const bridgeModeHash = await homeBridge.methods.getBridgeMode().call()
|
||||
this.bridgeMode = decodeBridgeMode(bridgeModeHash)
|
||||
this.bridgeModeInitialized = true
|
||||
}
|
||||
}
|
||||
|
||||
export default new RootStore();
|
||||
export default new RootStore()
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { action, observable } from "mobx";
|
||||
import { action, observable } from 'mobx'
|
||||
import { estimateGas } from './utils/web3'
|
||||
import { addPendingTransaction, removePendingTransaction } from './utils/testUtils'
|
||||
import { getUnit } from './utils/bridgeMode'
|
||||
@ -17,81 +17,91 @@ class TxStore {
|
||||
}
|
||||
|
||||
@action
|
||||
async doSend({to, from, value, data, sentValue}){
|
||||
return this.web3Store.getWeb3Promise.then(async ()=> {
|
||||
if(!this.web3Store.defaultAccount){
|
||||
this.alertStore.pushError("Please unlock wallet")
|
||||
async doSend({ to, from, value, data, sentValue }) {
|
||||
return this.web3Store.getWeb3Promise.then(async () => {
|
||||
if (!this.web3Store.defaultAccount) {
|
||||
this.alertStore.pushError('Please unlock wallet')
|
||||
return
|
||||
}
|
||||
try {
|
||||
const gasPrice = this.gasPriceStore.gasPriceInHex
|
||||
const gas = await estimateGas(this.web3Store.injectedWeb3, to, gasPrice, from, value, data)
|
||||
return this.web3Store.injectedWeb3.eth.sendTransaction({
|
||||
to,
|
||||
gasPrice,
|
||||
gas,
|
||||
from,
|
||||
value,
|
||||
data,
|
||||
chainId: this.web3Store.metamaskNet.id
|
||||
}).on('transactionHash', (hash) => {
|
||||
console.log('txHash', hash)
|
||||
this.txsValues[hash] = sentValue
|
||||
this.alertStore.setLoadingStepIndex(1)
|
||||
addPendingTransaction()
|
||||
this.getTxReceipt(hash)
|
||||
}).on('error', (e) => {
|
||||
if(!e.message.includes('not mined within 50 blocks') && !e.message.includes('Failed to subscribe to new newBlockHeaders')){
|
||||
this.alertStore.setLoading(false)
|
||||
this.alertStore.pushError('Transaction rejected on wallet');
|
||||
}
|
||||
})
|
||||
} catch(e) {
|
||||
this.alertStore.pushError(e.message);
|
||||
return this.web3Store.injectedWeb3.eth
|
||||
.sendTransaction({
|
||||
to,
|
||||
gasPrice,
|
||||
gas,
|
||||
from,
|
||||
value,
|
||||
data,
|
||||
chainId: this.web3Store.metamaskNet.id
|
||||
})
|
||||
.on('transactionHash', hash => {
|
||||
console.log('txHash', hash)
|
||||
this.txsValues[hash] = sentValue
|
||||
this.alertStore.setLoadingStepIndex(1)
|
||||
addPendingTransaction()
|
||||
this.getTxReceipt(hash)
|
||||
})
|
||||
.on('error', e => {
|
||||
if (
|
||||
!e.message.includes('not mined within 50 blocks') &&
|
||||
!e.message.includes('Failed to subscribe to new newBlockHeaders')
|
||||
) {
|
||||
this.alertStore.setLoading(false)
|
||||
this.alertStore.pushError('Transaction rejected on wallet')
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
this.alertStore.pushError(e.message)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@action
|
||||
async erc677transferAndCall({to, from, value, contract, tokenAddress }){
|
||||
async erc677transferAndCall({ to, from, value, contract, tokenAddress }) {
|
||||
try {
|
||||
return this.web3Store.getWeb3Promise.then(async () => {
|
||||
if(this.web3Store.defaultAccount.address){
|
||||
const data = await contract.methods.transferAndCall(
|
||||
to, value, '0x00'
|
||||
).encodeABI()
|
||||
return this.doSend({to: tokenAddress, from, value: '0x00', data, sentValue: value})
|
||||
if (this.web3Store.defaultAccount.address) {
|
||||
const data = await contract.methods.transferAndCall(to, value, '0x00').encodeABI()
|
||||
return this.doSend({ to: tokenAddress, from, value: '0x00', data, sentValue: value })
|
||||
} else {
|
||||
this.alertStore.pushError('Please unlock wallet');
|
||||
this.alertStore.pushError('Please unlock wallet')
|
||||
}
|
||||
})
|
||||
} catch(e) {
|
||||
this.alertStore.pushError(e);
|
||||
} catch (e) {
|
||||
this.alertStore.pushError(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async erc20transfer({to, from, value}){
|
||||
async erc20transfer({ to, from, value }) {
|
||||
try {
|
||||
return this.web3Store.getWeb3Promise.then(async () => {
|
||||
if(this.web3Store.defaultAccount.address){
|
||||
const data = await this.foreignStore.tokenContract.methods.transfer(
|
||||
to, value
|
||||
).encodeABI({ from: this.web3Store.defaultAccount.address })
|
||||
return this.doSend({to: this.foreignStore.tokenAddress, from, value: '0x', data, sentValue: value})
|
||||
if (this.web3Store.defaultAccount.address) {
|
||||
const data = await this.foreignStore.tokenContract.methods
|
||||
.transfer(to, value)
|
||||
.encodeABI({ from: this.web3Store.defaultAccount.address })
|
||||
return this.doSend({
|
||||
to: this.foreignStore.tokenAddress,
|
||||
from,
|
||||
value: '0x',
|
||||
data,
|
||||
sentValue: value
|
||||
})
|
||||
} else {
|
||||
this.alertStore.pushError('Please unlock wallet');
|
||||
this.alertStore.pushError('Please unlock wallet')
|
||||
}
|
||||
})
|
||||
} catch(e) {
|
||||
this.alertStore.pushError(e);
|
||||
} catch (e) {
|
||||
this.alertStore.pushError(e)
|
||||
}
|
||||
}
|
||||
|
||||
async getTxReceipt(hash){
|
||||
const web3 = this.web3Store.injectedWeb3;
|
||||
async getTxReceipt(hash) {
|
||||
const web3 = this.web3Store.injectedWeb3
|
||||
web3.eth.getTransaction(hash, (error, res) => {
|
||||
if(res && res.blockNumber){
|
||||
if (res && res.blockNumber) {
|
||||
this.getTxStatus(hash)
|
||||
} else {
|
||||
console.log('not mined yet', hash)
|
||||
@ -103,13 +113,13 @@ class TxStore {
|
||||
}
|
||||
|
||||
async getTxStatus(hash) {
|
||||
const web3 = this.web3Store.injectedWeb3;
|
||||
const web3 = this.web3Store.injectedWeb3
|
||||
web3.eth.getTransactionReceipt(hash, (error, res) => {
|
||||
if(res && res.blockNumber){
|
||||
if(this.isStatusSuccess(res)){
|
||||
if(this.web3Store.metamaskNet.id === this.web3Store.homeNet.id) {
|
||||
if (res && res.blockNumber) {
|
||||
if (this.isStatusSuccess(res)) {
|
||||
if (this.web3Store.metamaskNet.id === this.web3Store.homeNet.id) {
|
||||
const blockConfirmations = this.homeStore.latestBlockNumber - res.blockNumber
|
||||
if(blockConfirmations >= 8) {
|
||||
if (blockConfirmations >= 8) {
|
||||
this.alertStore.setBlockConfirmations(8)
|
||||
this.alertStore.setLoadingStepIndex(2)
|
||||
|
||||
@ -118,27 +128,25 @@ class TxStore {
|
||||
this.alertStore.setLoadingStepIndex(3)
|
||||
const unitReceived = getUnit(this.rootStore.bridgeMode).unitForeign
|
||||
setTimeout(() => {
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.foreignStore.networkName}`,
|
||||
this.alertStore.FOREIGN_TRANSFER_SUCCESS
|
||||
)
|
||||
}
|
||||
, 2000)
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.foreignStore.networkName}`,
|
||||
this.alertStore.FOREIGN_TRANSFER_SUCCESS
|
||||
)
|
||||
}, 2000)
|
||||
removePendingTransaction()
|
||||
})
|
||||
} else {
|
||||
this.foreignStore.addWaitingForConfirmation(hash)
|
||||
}
|
||||
} else {
|
||||
if(blockConfirmations > 0) {
|
||||
if (blockConfirmations > 0) {
|
||||
this.alertStore.setBlockConfirmations(blockConfirmations)
|
||||
}
|
||||
this.getTxStatus(hash)
|
||||
}
|
||||
|
||||
} else {
|
||||
const blockConfirmations = this.foreignStore.latestBlockNumber - res.blockNumber
|
||||
if(blockConfirmations >= 8) {
|
||||
if (blockConfirmations >= 8) {
|
||||
this.alertStore.setBlockConfirmations(8)
|
||||
this.alertStore.setLoadingStepIndex(2)
|
||||
|
||||
@ -147,19 +155,18 @@ class TxStore {
|
||||
this.alertStore.setLoadingStepIndex(3)
|
||||
const unitReceived = getUnit(this.rootStore.bridgeMode).unitHome
|
||||
setTimeout(() => {
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.homeStore.networkName}`,
|
||||
this.alertStore.HOME_TRANSFER_SUCCESS
|
||||
)
|
||||
}
|
||||
, 2000)
|
||||
this.alertStore.pushSuccess(
|
||||
`${unitReceived} received on ${this.homeStore.networkName}`,
|
||||
this.alertStore.HOME_TRANSFER_SUCCESS
|
||||
)
|
||||
}, 2000)
|
||||
removePendingTransaction()
|
||||
})
|
||||
} else {
|
||||
this.homeStore.addWaitingForConfirmation(hash)
|
||||
}
|
||||
} else {
|
||||
if(blockConfirmations > 0) {
|
||||
if (blockConfirmations > 0) {
|
||||
this.alertStore.setBlockConfirmations(blockConfirmations)
|
||||
}
|
||||
this.getTxStatus(hash)
|
||||
@ -177,11 +184,10 @@ class TxStore {
|
||||
|
||||
isStatusSuccess(tx) {
|
||||
const { toBN } = this.web3Store.injectedWeb3.utils
|
||||
const statusSuccess = tx.status && (tx.status === true || toBN(tx.status).eq(toBN(1)))
|
||||
const statusSuccess = tx.status && (tx.status === true || toBN(tx.status).eq(toBN(1)))
|
||||
const eventEmitted = tx.logs && tx.logs.length
|
||||
return statusSuccess || eventEmitted
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TxStore;
|
||||
export default TxStore
|
||||
|
@ -1,55 +1,57 @@
|
||||
import { action, observable } from "mobx";
|
||||
import getWeb3, { getBalance, getWeb3Instance, getNetwork } from './utils/web3';
|
||||
import { action, observable } from 'mobx'
|
||||
import getWeb3, { getBalance, getWeb3Instance, getNetwork } from './utils/web3'
|
||||
import { balanceLoaded } from './utils/testUtils'
|
||||
import { BRIDGE_MODES } from './utils/bridgeMode'
|
||||
|
||||
class Web3Store {
|
||||
@observable injectedWeb3 = {};
|
||||
@observable defaultAccount = {address: '', homeBalance: ''};
|
||||
@observable injectedWeb3 = {}
|
||||
@observable defaultAccount = { address: '', homeBalance: '' }
|
||||
|
||||
@observable homeWeb3 = {};
|
||||
@observable foreignWeb3 = {};
|
||||
@observable homeWeb3 = {}
|
||||
@observable foreignWeb3 = {}
|
||||
|
||||
@observable loading = true;
|
||||
@observable errors = [];
|
||||
@observable loading = true
|
||||
@observable errors = []
|
||||
|
||||
@observable getWeb3Promise = null;
|
||||
@observable setHomeWeb3Promise = null;
|
||||
@observable metamaskNotSetted = false;
|
||||
@observable getWeb3Promise = null
|
||||
@observable setHomeWeb3Promise = null
|
||||
@observable metamaskNotSetted = false
|
||||
|
||||
@observable homeNet = {id: '', name: ''};
|
||||
@observable foreignNet = {id: '', name: ''};
|
||||
@observable metamaskNet = {id: '', name: ''};
|
||||
@observable homeNet = { id: '', name: '' }
|
||||
@observable foreignNet = { id: '', name: '' }
|
||||
@observable metamaskNet = { id: '', name: '' }
|
||||
|
||||
@observable walletInstalled = true
|
||||
|
||||
HOME_HTTP_PARITY_URL = process.env.REACT_APP_HOME_HTTP_PARITY_URL;
|
||||
FOREIGN_HTTP_PARITY_URL = process.env.REACT_APP_FOREIGN_HTTP_PARITY_URL;
|
||||
HOME_HTTP_PARITY_URL = process.env.REACT_APP_HOME_HTTP_PARITY_URL
|
||||
FOREIGN_HTTP_PARITY_URL = process.env.REACT_APP_FOREIGN_HTTP_PARITY_URL
|
||||
|
||||
constructor(rootStore) {
|
||||
this.alertStore = rootStore.alertStore;
|
||||
this.alertStore = rootStore.alertStore
|
||||
this.rootStore = rootStore
|
||||
|
||||
this.getWeb3Promise = getWeb3()
|
||||
|
||||
this.getWeb3Promise.then((web3Config) => {
|
||||
this.setWeb3State(web3Config)
|
||||
this.getBalances(false)
|
||||
setInterval(() => {
|
||||
this.getBalances(true)
|
||||
}, 3000)
|
||||
}).catch(e => {
|
||||
const error = {
|
||||
rejected: () => this.alertStore.pushError(e.message),
|
||||
unlock: () => this.alertStore.pushError(e.message),
|
||||
install: () => this.walletInstalled = false
|
||||
}[e.type]
|
||||
this.getWeb3Promise
|
||||
.then(web3Config => {
|
||||
this.setWeb3State(web3Config)
|
||||
this.getBalances(false)
|
||||
setInterval(() => {
|
||||
this.getBalances(true)
|
||||
}, 3000)
|
||||
})
|
||||
.catch(e => {
|
||||
const error = {
|
||||
rejected: () => this.alertStore.pushError(e.message),
|
||||
unlock: () => this.alertStore.pushError(e.message),
|
||||
install: () => (this.walletInstalled = false)
|
||||
}[e.type]
|
||||
|
||||
console.error(e.message, 'web3 not loaded')
|
||||
this.errors.push(e.message)
|
||||
this.metamaskNotSetted = true
|
||||
error()
|
||||
})
|
||||
console.error(e.message, 'web3 not loaded')
|
||||
this.errors.push(e.message)
|
||||
this.metamaskNotSetted = true
|
||||
error()
|
||||
})
|
||||
this.setWeb3Home()
|
||||
this.setWeb3Foreign()
|
||||
this.checkMetamaskConfig()
|
||||
@ -57,11 +59,11 @@ class Web3Store {
|
||||
|
||||
@action
|
||||
setWeb3State(web3Config) {
|
||||
const {web3Instance, defaultAccount, netIdName, netId} = web3Config;
|
||||
this.metamaskNet = {id: netId, name: netIdName};
|
||||
this.defaultAccount.address = defaultAccount;
|
||||
this.injectedWeb3 = web3Instance;
|
||||
this.loading = false;
|
||||
const { web3Instance, defaultAccount, netIdName, netId } = web3Config
|
||||
this.metamaskNet = { id: netId, name: netIdName }
|
||||
this.defaultAccount.address = defaultAccount
|
||||
this.injectedWeb3 = web3Instance
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
@action
|
||||
@ -79,42 +81,54 @@ class Web3Store {
|
||||
}
|
||||
|
||||
@action
|
||||
async getBalances(displayLoading){
|
||||
async getBalances(displayLoading) {
|
||||
try {
|
||||
const accounts = await this.injectedWeb3.eth.getAccounts()
|
||||
const Loading = this.alertStore.showLoading
|
||||
let accountUpdated = false
|
||||
if(accounts[0] !== this.defaultAccount.address) {
|
||||
if(displayLoading && !Loading && accounts[0] !== undefined) {
|
||||
if (accounts[0] !== this.defaultAccount.address) {
|
||||
if (displayLoading && !Loading && accounts[0] !== undefined) {
|
||||
this.alertStore.setLoading(true)
|
||||
accountUpdated = true
|
||||
}
|
||||
this.defaultAccount.address = accounts[0]
|
||||
}
|
||||
this.defaultAccount.homeBalance = await getBalance(this.homeWeb3, this.defaultAccount.address)
|
||||
if(accountUpdated) {
|
||||
if (accountUpdated) {
|
||||
await this.rootStore.foreignStore.getTokenBalance()
|
||||
await this.rootStore.homeStore.getBalance()
|
||||
this.alertStore.setLoading(false)
|
||||
}
|
||||
if (this.rootStore.bridgeModeInitialized && this.rootStore.bridgeMode !== BRIDGE_MODES.ERC_TO_ERC) {
|
||||
if (
|
||||
this.rootStore.bridgeModeInitialized &&
|
||||
this.rootStore.bridgeMode !== BRIDGE_MODES.ERC_TO_ERC
|
||||
) {
|
||||
balanceLoaded()
|
||||
}
|
||||
} catch(e){
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
checkMetamaskConfig() {
|
||||
if(!this.metamaskNotSetted) {
|
||||
if(this.metamaskNet.name === '' || this.homeNet.name === '' || this.foreignNet.name === '') {
|
||||
setTimeout(() => {this.checkMetamaskConfig()}, 1000)
|
||||
if (!this.metamaskNotSetted) {
|
||||
if (this.metamaskNet.name === '' || this.homeNet.name === '' || this.foreignNet.name === '') {
|
||||
setTimeout(() => {
|
||||
this.checkMetamaskConfig()
|
||||
}, 1000)
|
||||
return
|
||||
}
|
||||
if(this.metamaskNet.name !== this.homeNet.name && this.metamaskNet.name !== this.foreignNet.name) {
|
||||
if (
|
||||
this.metamaskNet.name !== this.homeNet.name &&
|
||||
this.metamaskNet.name !== this.foreignNet.name
|
||||
) {
|
||||
this.metamaskNotSetted = true
|
||||
this.alertStore.pushError(`You are on an unknown network on your wallet. Please select ${this.homeNet.name} or ${this.foreignNet.name} in order to communicate with the bridge.`)
|
||||
this.alertStore.pushError(
|
||||
`You are on an unknown network on your wallet. Please select ${this.homeNet.name} or ${
|
||||
this.foreignNet.name
|
||||
} in order to communicate with the bridge.`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,4 +140,4 @@ class Web3Store {
|
||||
}
|
||||
}
|
||||
|
||||
export default Web3Store;
|
||||
export default Web3Store
|
||||
|
@ -1,7 +1,7 @@
|
||||
import TxStore from '../TxStore'
|
||||
import Web3 from 'web3'
|
||||
|
||||
describe('TxStore', function () {
|
||||
describe('TxStore', function() {
|
||||
let txStore
|
||||
beforeEach(() => {
|
||||
const rootStore = {
|
||||
@ -11,7 +11,7 @@ describe('TxStore', function () {
|
||||
}
|
||||
txStore = new TxStore(rootStore)
|
||||
})
|
||||
describe('isStatusSuccess', function () {
|
||||
describe('isStatusSuccess', function() {
|
||||
it('should return true if status field is 0x1', () => {
|
||||
// Given
|
||||
const tx = {
|
||||
@ -60,9 +60,7 @@ describe('TxStore', function () {
|
||||
it('should return true if status field not present and logs length > 0', () => {
|
||||
// Given
|
||||
const tx = {
|
||||
logs: [
|
||||
{}
|
||||
]
|
||||
logs: [{}]
|
||||
}
|
||||
|
||||
// When
|
||||
|
@ -60,4 +60,3 @@ describe('getTokenType', () => {
|
||||
expect(type).toEqual(ERC_TYPES.ERC20)
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -30,13 +30,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.BOTH_DIRECTIONS,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0.02),
|
||||
foreignFee: new BN(0.02)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = true
|
||||
@ -53,13 +53,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.BOTH_DIRECTIONS,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0.02),
|
||||
foreignFee: new BN(0.02)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = false
|
||||
@ -76,13 +76,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0.02),
|
||||
foreignFee: new BN(0.02)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = true
|
||||
@ -99,13 +99,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0.02),
|
||||
foreignFee: new BN(0.02)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = false
|
||||
@ -122,13 +122,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = true
|
||||
@ -144,13 +144,13 @@ describe('getFeeToApply', () => {
|
||||
const homeFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
foreignFee: new BN(0)
|
||||
}
|
||||
|
||||
const homeToForeignDirection = false
|
||||
@ -173,7 +173,7 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: [{ blockNumber: 10, fee: new BN(0.02) }]
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
@ -181,7 +181,6 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: []
|
||||
}
|
||||
|
||||
|
||||
// When
|
||||
const result = getRewardableData(homeFeeManager, foreignFeeManager)
|
||||
|
||||
@ -205,7 +204,7 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: [{ blockNumber: 10, fee: new BN(0.02) }]
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0),
|
||||
@ -213,7 +212,6 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: []
|
||||
}
|
||||
|
||||
|
||||
// When
|
||||
const result = getRewardableData(homeFeeManager, foreignFeeManager)
|
||||
|
||||
@ -237,7 +235,7 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: [{ blockNumber: 10, fee: new BN(0.02) }]
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.UNDEFINED,
|
||||
homeFee: new BN(0),
|
||||
foreignFee: new BN(0),
|
||||
@ -271,7 +269,7 @@ describe('getRewardableData', () => {
|
||||
foreignHistoricFee: []
|
||||
}
|
||||
|
||||
const foreignFeeManager = {
|
||||
const foreignFeeManager = {
|
||||
feeManagerMode: FEE_MANAGER_MODE.ONE_DIRECTION,
|
||||
homeFee: new BN(0.01),
|
||||
foreignFee: new BN(0),
|
||||
|
@ -5,10 +5,8 @@ describe('parseValidatorEvent', () => {
|
||||
// Given
|
||||
const event = {
|
||||
raw: {
|
||||
data: "0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225",
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987"
|
||||
],
|
||||
data: '0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225',
|
||||
topics: ['0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987']
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
@ -23,11 +21,11 @@ describe('parseValidatorEvent', () => {
|
||||
// Given
|
||||
const event = {
|
||||
raw: {
|
||||
data: "0x",
|
||||
data: '0x',
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987",
|
||||
"0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225"
|
||||
],
|
||||
'0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987',
|
||||
'0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
@ -42,11 +40,11 @@ describe('parseValidatorEvent', () => {
|
||||
// Given
|
||||
const event = {
|
||||
raw: {
|
||||
data: "0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225",
|
||||
data: '0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225',
|
||||
topics: [
|
||||
"0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83",
|
||||
"0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225"
|
||||
],
|
||||
'0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83',
|
||||
'0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
@ -61,11 +59,11 @@ describe('parseValidatorEvent', () => {
|
||||
// Given
|
||||
const event = {
|
||||
raw: {
|
||||
data: "0x",
|
||||
data: '0x',
|
||||
topics: [
|
||||
"0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1",
|
||||
"0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225"
|
||||
],
|
||||
'0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1',
|
||||
'0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
@ -80,10 +78,8 @@ describe('parseValidatorEvent', () => {
|
||||
// Given
|
||||
const event = {
|
||||
raw: {
|
||||
data: "0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225",
|
||||
topics: [
|
||||
"0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1"
|
||||
],
|
||||
data: '0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225',
|
||||
topics: ['0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1']
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
@ -99,70 +95,71 @@ describe('processValidatorsEvents', () => {
|
||||
it('should return validator list from raw events', () => {
|
||||
// Given
|
||||
const events = [
|
||||
{ // Add v1 event
|
||||
{
|
||||
// Add v1 event
|
||||
raw: {
|
||||
data: "0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225",
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987"
|
||||
],
|
||||
data: '0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225',
|
||||
topics: ['0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987']
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Add v1 event
|
||||
{
|
||||
// Add v1 event
|
||||
raw: {
|
||||
data: "0x000000000000000000000000Cbd25A2a5708051747a052dBB1b291865Fc0e474",
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987"
|
||||
],
|
||||
data: '0x000000000000000000000000Cbd25A2a5708051747a052dBB1b291865Fc0e474',
|
||||
topics: ['0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987']
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Remove v1 event
|
||||
{
|
||||
// Remove v1 event
|
||||
raw: {
|
||||
data: "0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225",
|
||||
topics: [
|
||||
"0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1"
|
||||
],
|
||||
data: '0x000000000000000000000000cfef0c6bb765321529ffe81507f6d099693cd225',
|
||||
topics: ['0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1']
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Add event
|
||||
{
|
||||
// Add event
|
||||
raw: {
|
||||
data: "0x",
|
||||
data: '0x',
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987",
|
||||
"0x000000000000000000000000FE365A92Bc01425441dE76D8EDA48496B64446FB"
|
||||
],
|
||||
'0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987',
|
||||
'0x000000000000000000000000FE365A92Bc01425441dE76D8EDA48496B64446FB'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Add event
|
||||
{
|
||||
// Add event
|
||||
raw: {
|
||||
data: "0x",
|
||||
data: '0x',
|
||||
topics: [
|
||||
"0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987",
|
||||
"0x000000000000000000000000Bac68A86Cf596E3b124781E0bdbC47bb458bec62"
|
||||
],
|
||||
'0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987',
|
||||
'0x000000000000000000000000Bac68A86Cf596E3b124781E0bdbC47bb458bec62'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Remove event
|
||||
{
|
||||
// Remove event
|
||||
raw: {
|
||||
data: "0x",
|
||||
data: '0x',
|
||||
topics: [
|
||||
"0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1",
|
||||
"0x000000000000000000000000FE365A92Bc01425441dE76D8EDA48496B64446FB"
|
||||
],
|
||||
'0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1',
|
||||
'0x000000000000000000000000FE365A92Bc01425441dE76D8EDA48496B64446FB'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
},
|
||||
{ // Add rewardable event
|
||||
{
|
||||
// Add rewardable event
|
||||
raw: {
|
||||
data: "0x0000000000000000000000000066938BBE9b31D44DFa8e27A1d675A545DF6ed5",
|
||||
data: '0x0000000000000000000000000066938BBE9b31D44DFa8e27A1d675A545DF6ed5',
|
||||
topics: [
|
||||
"0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83",
|
||||
"0x000000000000000000000000f4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955"
|
||||
],
|
||||
'0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83',
|
||||
'0x000000000000000000000000f4BEF13F9f4f2B203FAF0C3cBbaAbe1afE056955'
|
||||
]
|
||||
},
|
||||
returnValues: {}
|
||||
}
|
||||
|
@ -1,22 +1,22 @@
|
||||
export const processLargeArrayAsync = (array, fn, endFn, maxTimePerChunk = 16) => {
|
||||
let index = 0;
|
||||
let index = 0
|
||||
|
||||
const doChunk = () => {
|
||||
const startTime = now();
|
||||
while (index < array.length && (now() - startTime) <= maxTimePerChunk) {
|
||||
fn(array[index]);
|
||||
++index;
|
||||
const startTime = now()
|
||||
while (index < array.length && now() - startTime <= maxTimePerChunk) {
|
||||
fn(array[index])
|
||||
++index
|
||||
}
|
||||
if (index < array.length) {
|
||||
setTimeout(doChunk, 0);
|
||||
} else if(endFn) {
|
||||
setTimeout(doChunk, 0)
|
||||
} else if (endFn) {
|
||||
endFn()
|
||||
}
|
||||
}
|
||||
|
||||
doChunk();
|
||||
doChunk()
|
||||
}
|
||||
|
||||
function now() {
|
||||
return new Date().getTime();
|
||||
return new Date().getTime()
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ export const ERC_TYPES = {
|
||||
ERC20: 'ERC20'
|
||||
}
|
||||
|
||||
export const getBridgeABIs = (bridgeMode) => {
|
||||
export const getBridgeABIs = bridgeMode => {
|
||||
let HOME_ABI = null
|
||||
let FOREIGN_ABI = null
|
||||
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
|
||||
@ -41,7 +41,7 @@ export const getBridgeABIs = (bridgeMode) => {
|
||||
return { HOME_ABI, FOREIGN_ABI }
|
||||
}
|
||||
|
||||
export const decodeBridgeMode = (bridgeModeHash) => {
|
||||
export const decodeBridgeMode = bridgeModeHash => {
|
||||
switch (bridgeModeHash) {
|
||||
case '0x92a8d7fe':
|
||||
return BRIDGE_MODES.NATIVE_TO_ERC
|
||||
@ -54,7 +54,7 @@ export const decodeBridgeMode = (bridgeModeHash) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const getUnit = (bridgeMode) => {
|
||||
export const getUnit = bridgeMode => {
|
||||
let unitHome = null
|
||||
let unitForeign = null
|
||||
if (bridgeMode === BRIDGE_MODES.NATIVE_TO_ERC) {
|
||||
@ -73,7 +73,7 @@ export const getUnit = (bridgeMode) => {
|
||||
return { unitHome, unitForeign }
|
||||
}
|
||||
|
||||
export const decodeFeeManagerMode = (managerModeHash) => {
|
||||
export const decodeFeeManagerMode = managerModeHash => {
|
||||
switch (managerModeHash) {
|
||||
case '0xf2aed8f7':
|
||||
return FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
|
@ -2,62 +2,63 @@ import BN from 'bignumber.js'
|
||||
import { fromDecimals } from './decimals'
|
||||
import { fromWei } from 'web3-utils'
|
||||
import { abi as rewardableValidatorsAbi } from '../../contracts/RewardableValidators'
|
||||
import { ERC_TYPES } from "./bridgeMode"
|
||||
import { ERC_TYPES } from './bridgeMode'
|
||||
|
||||
export const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
|
||||
|
||||
export const getMaxPerTxLimit = async (contract,decimals) => {
|
||||
export const getMaxPerTxLimit = async (contract, decimals) => {
|
||||
const maxPerTx = await contract.methods.maxPerTx().call()
|
||||
return fromDecimals(maxPerTx,decimals)
|
||||
return fromDecimals(maxPerTx, decimals)
|
||||
}
|
||||
|
||||
export const getMinPerTxLimit = async (contract,decimals) => {
|
||||
export const getMinPerTxLimit = async (contract, decimals) => {
|
||||
const minPerTx = await contract.methods.minPerTx().call()
|
||||
return fromDecimals(minPerTx,decimals)
|
||||
return fromDecimals(minPerTx, decimals)
|
||||
}
|
||||
|
||||
export const getCurrentLimit = async (contract,decimals) => {
|
||||
export const getCurrentLimit = async (contract, decimals) => {
|
||||
const currentDay = await contract.methods.getCurrentDay().call()
|
||||
const dailyLimit = await contract.methods.dailyLimit().call()
|
||||
const totalSpentPerDay = await contract.methods.totalSpentPerDay(currentDay).call()
|
||||
const maxCurrentDeposit = new BN(dailyLimit).minus(new BN(totalSpentPerDay)).toString(10)
|
||||
return {
|
||||
maxCurrentDeposit: fromDecimals(maxCurrentDeposit,decimals),
|
||||
dailyLimit: fromDecimals(dailyLimit,decimals),
|
||||
totalSpentPerDay: fromDecimals(totalSpentPerDay,decimals)
|
||||
maxCurrentDeposit: fromDecimals(maxCurrentDeposit, decimals),
|
||||
dailyLimit: fromDecimals(dailyLimit, decimals),
|
||||
totalSpentPerDay: fromDecimals(totalSpentPerDay, decimals)
|
||||
}
|
||||
}
|
||||
|
||||
export const getPastEvents = (contract, fromBlock, toBlock, event = 'allEvents') => contract.getPastEvents(event, { fromBlock, toBlock })
|
||||
export const getPastEvents = (contract, fromBlock, toBlock, event = 'allEvents') =>
|
||||
contract.getPastEvents(event, { fromBlock, toBlock })
|
||||
|
||||
export const getErc677TokenAddress = (contract) => contract.methods.erc677token().call()
|
||||
export const getErc677TokenAddress = contract => contract.methods.erc677token().call()
|
||||
|
||||
export const getErc20TokenAddress = (contract) => contract.methods.erc20token().call()
|
||||
export const getErc20TokenAddress = contract => contract.methods.erc20token().call()
|
||||
|
||||
export const getSymbol = (contract) => contract.methods.symbol().call()
|
||||
export const getSymbol = contract => contract.methods.symbol().call()
|
||||
|
||||
export const getDecimals= (contract) => contract.methods.decimals().call()
|
||||
export const getDecimals = contract => contract.methods.decimals().call()
|
||||
|
||||
export const getMessage = (contract, messageHash) => contract.methods.message(messageHash).call()
|
||||
|
||||
export const getTotalSupply = async (contract) => {
|
||||
export const getTotalSupply = async contract => {
|
||||
const totalSupply = await contract.methods.totalSupply().call()
|
||||
const decimals = await contract.methods.decimals().call()
|
||||
return fromDecimals(totalSupply,decimals)
|
||||
return fromDecimals(totalSupply, decimals)
|
||||
}
|
||||
|
||||
export const getBalanceOf = async (contract, address) => {
|
||||
const balance = await contract.methods.balanceOf(address).call()
|
||||
const decimals = await contract.methods.decimals().call()
|
||||
return fromDecimals(balance,decimals)
|
||||
return fromDecimals(balance, decimals)
|
||||
}
|
||||
|
||||
export const mintedTotally = async (contract) => {
|
||||
export const mintedTotally = async contract => {
|
||||
const mintedCoins = await contract.methods.mintedTotally().call()
|
||||
return new BN(mintedCoins)
|
||||
}
|
||||
|
||||
export const totalBurntCoins = async (contract) => {
|
||||
export const totalBurntCoins = async contract => {
|
||||
const burntCoins = await contract.methods.totalBurntCoins().call()
|
||||
return new BN(burntCoins)
|
||||
}
|
||||
@ -66,18 +67,20 @@ export const getValidatorList = async (address, eth) => {
|
||||
const validatorsContract = new eth.Contract(rewardableValidatorsAbi, address)
|
||||
const validators = await validatorList(validatorsContract)
|
||||
|
||||
if(validators.length) {
|
||||
if (validators.length) {
|
||||
return validators
|
||||
}
|
||||
|
||||
const deployedAtBlock = await getDeployedAtBlock(validatorsContract)
|
||||
const contract = new eth.Contract([], address)
|
||||
const validatorsEvents = await contract.getPastEvents('allEvents', { fromBlock: Number(deployedAtBlock) })
|
||||
const validatorsEvents = await contract.getPastEvents('allEvents', {
|
||||
fromBlock: Number(deployedAtBlock)
|
||||
})
|
||||
|
||||
return processValidatorsEvents(validatorsEvents)
|
||||
}
|
||||
|
||||
export const validatorList = async (contract) => {
|
||||
export const validatorList = async contract => {
|
||||
try {
|
||||
return await contract.methods.validatorList().call()
|
||||
} catch (e) {
|
||||
@ -85,35 +88,39 @@ export const validatorList = async (contract) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const processValidatorsEvents = (events) => {
|
||||
export const processValidatorsEvents = events => {
|
||||
const validatorList = new Set()
|
||||
events.forEach(event => {
|
||||
parseValidatorEvent(event)
|
||||
|
||||
if(event.event === 'ValidatorAdded') {
|
||||
if (event.event === 'ValidatorAdded') {
|
||||
validatorList.add(event.returnValues.validator)
|
||||
} else if(event.event === 'ValidatorRemoved') {
|
||||
} else if (event.event === 'ValidatorRemoved') {
|
||||
validatorList.delete(event.returnValues.validator)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return Array.from(validatorList)
|
||||
}
|
||||
|
||||
export const parseValidatorEvent = (event) => {
|
||||
if (event.event === undefined
|
||||
&& event.raw
|
||||
&& event.raw.topics
|
||||
&& (event.raw.topics[0] === '0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987'
|
||||
|| event.raw.topics[0] === '0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83')) {
|
||||
export const parseValidatorEvent = event => {
|
||||
if (
|
||||
event.event === undefined &&
|
||||
event.raw &&
|
||||
event.raw.topics &&
|
||||
(event.raw.topics[0] === '0xe366c1c0452ed8eec96861e9e54141ebff23c9ec89fe27b996b45f5ec3884987' ||
|
||||
event.raw.topics[0] === '0x8064a302796c89446a96d63470b5b036212da26bd2debe5bec73e0170a9a5e83')
|
||||
) {
|
||||
const rawAddress = event.raw.topics.length > 1 ? event.raw.topics[1] : event.raw.data
|
||||
const address = '0x' + rawAddress.slice(26)
|
||||
event.event = 'ValidatorAdded'
|
||||
event.returnValues.validator = address
|
||||
} else if (event.event === undefined
|
||||
&& event.raw
|
||||
&& event.raw.topics
|
||||
&& event.raw.topics[0] === "0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1") {
|
||||
} else if (
|
||||
event.event === undefined &&
|
||||
event.raw &&
|
||||
event.raw.topics &&
|
||||
event.raw.topics[0] === '0xe1434e25d6611e0db941968fdc97811c982ac1602e951637d206f5fdda9dd8f1'
|
||||
) {
|
||||
const rawAddress = event.raw.data === '0x' ? event.raw.topics[1] : event.raw.data
|
||||
const address = '0x' + rawAddress.slice(26)
|
||||
event.event = 'ValidatorRemoved'
|
||||
@ -121,29 +128,29 @@ export const parseValidatorEvent = (event) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const getName = (contract) => contract.methods.name().call()
|
||||
export const getName = contract => contract.methods.name().call()
|
||||
|
||||
export const getFeeManager = async (contract) => {
|
||||
try {
|
||||
return await contract.methods.feeManagerContract().call()
|
||||
} catch (e) {
|
||||
return ZERO_ADDRESS
|
||||
}
|
||||
export const getFeeManager = async contract => {
|
||||
try {
|
||||
return await contract.methods.feeManagerContract().call()
|
||||
} catch (e) {
|
||||
return ZERO_ADDRESS
|
||||
}
|
||||
}
|
||||
|
||||
export const getFeeManagerMode = (contract) => contract.methods.getFeeManagerMode().call()
|
||||
export const getFeeManagerMode = contract => contract.methods.getFeeManagerMode().call()
|
||||
|
||||
export const getHomeFee = async (contract) => {
|
||||
export const getHomeFee = async contract => {
|
||||
const feeInWei = await contract.methods.getHomeFee().call()
|
||||
return new BN(fromWei(feeInWei.toString()))
|
||||
}
|
||||
|
||||
export const getForeignFee = async (contract) => {
|
||||
export const getForeignFee = async contract => {
|
||||
const feeInWei = await contract.methods.getForeignFee().call()
|
||||
return new BN(fromWei(feeInWei.toString()))
|
||||
}
|
||||
|
||||
export const getDeployedAtBlock = async (contract) => {
|
||||
export const getDeployedAtBlock = async contract => {
|
||||
try {
|
||||
return await contract.methods.deployedAtBlock().call()
|
||||
} catch (e) {
|
||||
|
@ -1,36 +1,40 @@
|
||||
import BN from 'bignumber.js'
|
||||
export const fromDecimals = (number, decimals) => {
|
||||
if (decimals == null) {
|
||||
decimals = 18;
|
||||
decimals = 18
|
||||
}
|
||||
const returnValue = toBigNumber(number).dividedBy(Math.pow(10, decimals));
|
||||
return isBigNumber(number) ? returnValue : returnValue.toString(10);
|
||||
};
|
||||
const returnValue = toBigNumber(number).dividedBy(Math.pow(10, decimals))
|
||||
return isBigNumber(number) ? returnValue : returnValue.toString(10)
|
||||
}
|
||||
|
||||
export const toDecimals = (number, decimals) => {
|
||||
if (decimals == null) {
|
||||
decimals = 18;
|
||||
decimals = 18
|
||||
}
|
||||
const returnValue = toBigNumber(number).times(Math.pow(10, decimals));
|
||||
return isBigNumber(number) ? returnValue : returnValue.toString(10);
|
||||
};
|
||||
const returnValue = toBigNumber(number).times(Math.pow(10, decimals))
|
||||
return isBigNumber(number) ? returnValue : returnValue.toString(10)
|
||||
}
|
||||
|
||||
const isBigNumber = (object) => {
|
||||
return (object && (object instanceof BN || (object.constructor && object.constructor.name === 'BigNumber')));
|
||||
};
|
||||
const isBigNumber = object => {
|
||||
return (
|
||||
object &&
|
||||
(object instanceof BN || (object.constructor && object.constructor.name === 'BigNumber'))
|
||||
)
|
||||
}
|
||||
|
||||
const toBigNumber = (number) => {
|
||||
/*jshint maxcomplexity:5 */
|
||||
number = number || 0;
|
||||
if (isBigNumber(number))
|
||||
return number;
|
||||
if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {
|
||||
return new BN(number.replace('0x',''), 16);
|
||||
}
|
||||
return new BN(number.toString(10), 10);
|
||||
};
|
||||
const toBigNumber = number => {
|
||||
/*jshint maxcomplexity:5 */
|
||||
number = number || 0
|
||||
if (isBigNumber(number)) return number
|
||||
if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {
|
||||
return new BN(number.replace('0x', ''), 16)
|
||||
}
|
||||
return new BN(number.toString(10), 10)
|
||||
}
|
||||
|
||||
const isString = (object) => {
|
||||
return typeof object === 'string' ||
|
||||
(object && object.constructor && object.constructor.name === 'String');
|
||||
};
|
||||
const isString = object => {
|
||||
return (
|
||||
typeof object === 'string' ||
|
||||
(object && object.constructor && object.constructor.name === 'String')
|
||||
)
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ export async function fetchGasPrice({ oracleFn }) {
|
||||
}
|
||||
|
||||
export async function fetchGasPriceFromOracle(oracleUrl, speedType) {
|
||||
if(!oracleUrl) {
|
||||
if (!oracleUrl) {
|
||||
throw new Error(`Gas Price Oracle url not defined`)
|
||||
}
|
||||
const response = await fetch(oracleUrl)
|
||||
|
@ -1,7 +1,7 @@
|
||||
import BN from 'bignumber.js';
|
||||
import BN from 'bignumber.js'
|
||||
import { FEE_MANAGER_MODE } from './bridgeMode'
|
||||
|
||||
export const validFee = (fee) => {
|
||||
export const validFee = fee => {
|
||||
const zeroBN = new BN(0)
|
||||
return !zeroBN.eq(fee)
|
||||
}
|
||||
@ -12,7 +12,7 @@ export const getFeeToApply = (homeFeeManager, foreignFeeManager, homeToForeignDi
|
||||
}
|
||||
|
||||
export const getRewardableData = (homeFeeManager, foreignFeeManager) => {
|
||||
if(homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.BOTH_DIRECTIONS) {
|
||||
if (homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.BOTH_DIRECTIONS) {
|
||||
return {
|
||||
homeFee: homeFeeManager.homeFee,
|
||||
foreignFee: homeFeeManager.foreignFee,
|
||||
@ -23,8 +23,10 @@ export const getRewardableData = (homeFeeManager, foreignFeeManager) => {
|
||||
displayDeposit: true,
|
||||
displayWithdraw: true
|
||||
}
|
||||
} else if(homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
&& foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION) {
|
||||
} else if (
|
||||
homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION &&
|
||||
foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
) {
|
||||
return {
|
||||
homeFee: foreignFeeManager.homeFee,
|
||||
foreignFee: homeFeeManager.foreignFee,
|
||||
@ -35,8 +37,10 @@ export const getRewardableData = (homeFeeManager, foreignFeeManager) => {
|
||||
displayDeposit: true,
|
||||
displayWithdraw: true
|
||||
}
|
||||
} else if(homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
&& foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.UNDEFINED) {
|
||||
} else if (
|
||||
homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION &&
|
||||
foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.UNDEFINED
|
||||
) {
|
||||
return {
|
||||
homeFee: new BN(0),
|
||||
foreignFee: homeFeeManager.foreignFee,
|
||||
@ -47,8 +51,10 @@ export const getRewardableData = (homeFeeManager, foreignFeeManager) => {
|
||||
displayDeposit: false,
|
||||
displayWithdraw: true
|
||||
}
|
||||
} else if(homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.UNDEFINED
|
||||
&& foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION) {
|
||||
} else if (
|
||||
homeFeeManager.feeManagerMode === FEE_MANAGER_MODE.UNDEFINED &&
|
||||
foreignFeeManager.feeManagerMode === FEE_MANAGER_MODE.ONE_DIRECTION
|
||||
) {
|
||||
return {
|
||||
homeFee: foreignFeeManager.homeFee,
|
||||
foreignFee: new BN(0),
|
||||
|
@ -3,7 +3,7 @@ let pendingTransaction = 0
|
||||
|
||||
export const balanceLoaded = () => {
|
||||
balanceCount++
|
||||
if(balanceCount > 1) {
|
||||
if (balanceCount > 1) {
|
||||
document.getElementById('root').classList.add('web3-loaded')
|
||||
}
|
||||
}
|
||||
@ -15,7 +15,7 @@ export const addPendingTransaction = () => {
|
||||
|
||||
export const removePendingTransaction = () => {
|
||||
pendingTransaction--
|
||||
if(!pendingTransaction) {
|
||||
if (!pendingTransaction) {
|
||||
document.getElementById('root').classList.remove('pending-transaction')
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,22 @@ const updateTitle = (networkName = 'No chain specified') => {
|
||||
const defaultTitle = 'TokenBridge UI app'
|
||||
if (!process.env.REACT_APP_TITLE) {
|
||||
document.title = defaultTitle
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
const titleReplaceString = '%c'
|
||||
let appTitle = process.env.REACT_APP_TITLE || defaultTitle
|
||||
|
||||
if (appTitle.indexOf(titleReplaceString) !== -1) {
|
||||
document.title = appTitle.replace(titleReplaceString, networkName)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
document.title = appTitle
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getWeb3 = () => {
|
||||
return new Promise(function (resolve, reject) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
// Wait for loading completion to avoid race conditions with web3 injection timing.
|
||||
window.addEventListener('load',async function () {
|
||||
window.addEventListener('load', async function() {
|
||||
let web3 = window.web3
|
||||
const { ethereum } = window
|
||||
|
||||
@ -33,7 +31,7 @@ const getWeb3 = () => {
|
||||
try {
|
||||
// Request account access
|
||||
await ethereum.enable()
|
||||
await processWeb3(web3, resolve, reject)
|
||||
await processWeb3(web3, resolve, reject)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
const errorMsg = `Wallet account rejected by user. You need to unlock your wallet.
|
||||
@ -42,13 +40,13 @@ const getWeb3 = () => {
|
||||
}
|
||||
} else if (typeof web3 !== 'undefined') {
|
||||
web3 = new Web3(web3.currentProvider)
|
||||
await processWeb3(web3, resolve, reject)
|
||||
await processWeb3(web3, resolve, reject)
|
||||
} else {
|
||||
// Fallback to localhost if no web3 injection.
|
||||
const errorMsg = ''
|
||||
reject({ type: 'install', message: errorMsg })
|
||||
console.log('No web3 instance injected, using Local web3.');
|
||||
console.error('wallet not found');
|
||||
console.log('No web3 instance injected, using Local web3.')
|
||||
console.error('wallet not found')
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -62,26 +60,26 @@ const networks = {
|
||||
4: 'Rinkeby',
|
||||
30: 'RSK Mainnet',
|
||||
31: 'RSK Testnet',
|
||||
42:'Kovan',
|
||||
42: 'Kovan',
|
||||
61: 'Ethereum Classic',
|
||||
77:'Sokol',
|
||||
77: 'Sokol',
|
||||
99: 'POA Network',
|
||||
100: 'Dai Chain'
|
||||
}
|
||||
|
||||
export const getNetworkName = (id) => networks[id] || 'Unknown'
|
||||
export const getNetworkName = id => networks[id] || 'Unknown'
|
||||
|
||||
export const getBalance = async (web3, address) => {
|
||||
const balance = await web3.eth.getBalance(address)
|
||||
return fromWei(balance)
|
||||
}
|
||||
|
||||
export const getWeb3Instance = (provider) => {
|
||||
const web3Provider = new Web3.providers.HttpProvider(provider);
|
||||
return new Web3(web3Provider);
|
||||
export const getWeb3Instance = provider => {
|
||||
const web3Provider = new Web3.providers.HttpProvider(provider)
|
||||
return new Web3(web3Provider)
|
||||
}
|
||||
|
||||
export const getNetwork = async (web3) => {
|
||||
export const getNetwork = async web3 => {
|
||||
const id = await web3.eth.getChainId()
|
||||
const name = getNetworkName(id)
|
||||
return {
|
||||
@ -90,28 +88,32 @@ export const getNetwork = async (web3) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const getBlockNumber = (web3) => web3.eth.getBlockNumber()
|
||||
export const getBlockNumber = web3 => web3.eth.getBlockNumber()
|
||||
|
||||
export const estimateGas = async (web3, to, gasPrice, from, value, data) =>{
|
||||
const gas = await web3.eth.estimateGas({to, gasPrice, from, value, data})
|
||||
export const estimateGas = async (web3, to, gasPrice, from, value, data) => {
|
||||
const gas = await web3.eth.estimateGas({ to, gasPrice, from, value, data })
|
||||
return toHex(gas.toString())
|
||||
}
|
||||
|
||||
const processWeb3 = async (web3, resolve, reject) => {
|
||||
const processWeb3 = async (web3, resolve, reject) => {
|
||||
let netId
|
||||
try {
|
||||
netId = await web3.eth.getChainId()
|
||||
} catch (error) {
|
||||
reject({ type: 'unlock', message: 'Wallet does not support getting the Chain ID. Please use another wallet or specify a RPC url of a node that supports eth_chainId call' })
|
||||
reject({
|
||||
type: 'unlock',
|
||||
message:
|
||||
'Wallet does not support getting the Chain ID. Please use another wallet or specify a RPC url of a node that supports eth_chainId call'
|
||||
})
|
||||
}
|
||||
const netIdName = getNetworkName(netId)
|
||||
|
||||
console.log(`This is ${netIdName} network.`, netId)
|
||||
|
||||
const accounts = await web3.eth.getAccounts()
|
||||
const defaultAccount = accounts[0] || null;
|
||||
const defaultAccount = accounts[0] || null
|
||||
|
||||
if(defaultAccount === null){
|
||||
if (defaultAccount === null) {
|
||||
reject({ type: 'unlock', message: 'Please unlock your wallet and refresh the page' })
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user