Skip to content
This repository has been archived by the owner on May 24, 2022. It is now read-only.

Commit

Permalink
feat: Relates to #360. Only allow import from Parity Signer chain acc…
Browse files Browse the repository at this point in the history
…ount matching current chain. ETC support
  • Loading branch information
ltfschoen committed Apr 1, 2019
1 parent a1d014b commit 2d1e131
Show file tree
Hide file tree
Showing 15 changed files with 520 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,43 @@
// SPDX-License-Identifier: BSD-3-Clause

import React, { Component } from 'react';
import { addressShort, Card, Form as FetherForm } from 'fether-ui';
import BigNumber from 'bignumber.js';
import { branch } from 'recompose';
import { chainId$, chainName$ } from '@parity/light.js';
import light from '@parity/light.js-react';
import { inject, observer } from 'mobx-react';
import { addressShort, Card, Form as FetherForm } from 'fether-ui';

import RequireHealthOverlay from '../../../RequireHealthOverlay';
import Scanner from '../../../Scanner';
import withAccountsInfo from '../../../utils/withAccountsInfo';
import withHealth from '../../../utils/withHealth';

// Parity Signer networks that are available
const PARITY_SIGNER_NETWORKS = {
1: 'foundation',
3: 'ropsten',
42: 'kovan',
61: 'classic'
};

@withAccountsInfo
@withHealth
@inject('createAccountStore')
@light({
chainId: () => chainId$()
})
@branch(
({
health: {
status: { good, syncing }
}
}) => good || syncing,
// Only call light.js chainName$ if we're syncing or good
light({
chainName: () => chainName$()
})
)
@observer
class AccountImportOptions extends Component {
state = {
Expand Down Expand Up @@ -88,8 +116,17 @@ class AccountImportOptions extends Component {
}
};

/**
* The `chainId$` and `chainName$` from light.js corresponds to `chainID` in the
* Genesis configs contained in: paritytech/parity-ethereum/ethcore/res/ethereum
* and was introduced in EIP-155 https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
* to prevent replay attacks between `foundation` and `classic` chains, which both have
* `networkID` of `1`.
*/
handleSignerImported = async ({ address, chainId: chainIdString }) => {
const {
chainId: currentChainIdBN,
chainName,
createAccountStore: { importFromSigner }
} = this.props;

Expand All @@ -98,13 +135,22 @@ class AccountImportOptions extends Component {
return;
}

const chainId = parseInt(chainIdString);
const signerChainId = parseInt(chainIdString);

if (!this.isCurrentChainIdTheAddressForImportChainId(signerChainId)) {
this.setState({
error: `Parity Signer account chainId ${chainIdString} (${
PARITY_SIGNER_NETWORKS[signerChainId]
}) must match current chainId ${currentChainIdBN.valueOf()} (${chainName}).`
});
return;
}

if (this.hasExistingAddressForImport(address, chainId)) {
if (this.hasExistingAddressForImport(address, signerChainId)) {
return;
}

await importFromSigner({ address, chainId });
await importFromSigner({ address, signerChainId });

this.handleNextStep();
};
Expand All @@ -115,14 +161,20 @@ class AccountImportOptions extends Component {
});
};

hasExistingAddressForImport = (addressForImport, chainId) => {
isCurrentChainIdTheAddressForImportChainId = chainIdInt => {
const { chainId: currentChainIdBN } = this.props;

return BigNumber(chainIdInt).eq(currentChainIdBN);
};

hasExistingAddressForImport = (addressForImport, chainIdInt) => {
const { accountsInfo } = this.props;
const isExistingAddress = Object.keys(accountsInfo).some(
key =>
key.toLowerCase() === addressForImport.toLowerCase() &&
(!accountsInfo[key].chainId ||
!chainId ||
accountsInfo[key].chainId === chainId)
!chainIdInt ||
accountsInfo[key].chainId === chainIdInt)
);

if (isExistingAddress) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import loading from '../../../assets/img/icons/loading.svg';
class AccountName extends Component {
componentDidMount () {
const { createAccountStore } = this.props;

// Generate a new public address if there's none yet
if (!createAccountStore.address) {
createAccountStore.generateNewAccount();
Expand Down
12 changes: 6 additions & 6 deletions packages/fether-react/src/Onboarding/termsAndConditions.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
**Disclaimer of Liability and Warranties**

- The user expressly acknowledges and agrees that Parity Technologies Limited makes the Fether client available to the user at the user's sole risk.
- The user represents that the user has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software, the Ethereum platform and ETH.
- The user represents that the user has an adequate understanding of the risks, usage and intricacies of cryptographic tokens and blockchain-based open source software, the Ethereum platform, and both ETH and ETC.
- The user acknowledges and agrees that, to the fullest extent permitted by any applicable law, the disclaimers of liability contained herein apply to any and all damages or injury whatsoever caused by or related to risks of, use of, or inability to use, the Fether client under any cause or action whatsoever of any kind in any jurisdiction, including, without limitation, actions for breach of warranty, breach of contract or tort (including negligence) and that Parity Technologies Limited shall not be liable for any indirect, incidental, special, exemplary or consequential damages, including for loss of profits, goodwill or data.
- Some jurisdictions do not allow the exclusion of certain warranties or the limitation or exclusion of liability for certain types of damages. Therefore, some of the above limitations in this section may not apply to a user. In particular, nothing in these terms shall affect the statutory rights of any user or limit or exclude liability for death or physical injury arising from the negligence or wilful misconduct of Parity Technologies Limited or for fraud or fraudulent misrepresentation.
- All rights reserved by Parity Technologies Limited. Licensed to the public under the BSD3.0 License (also known as "BSD-3-Clause"): [https://opensource.org/licenses/BSD-3-Clause](https://opensource.org/licenses/BSD-3-Clause)
Expand All @@ -20,23 +20,23 @@ The User acknowledges the following serious risks to any use of Fether and expre

**Risk of Security Weaknesses in the Parity Core Infrastructure Software**

Fether uses open-source libraries and components developed by third parties. While Parity Technologies Limited generally aims to use only widely adopted open-source technology and develop it in line with industry standards, such open-source technology may contain bugs and errors and may not function correctly in all circumstances. As a result, there is a risk that Parity Technologies or the Parity Technologies Team may have introduced unintentional weaknesses or bugs into the core infrastructural elements of Fether causing the system to lose Ethereum tokens ("ETH") stored in one or more User accounts or other accounts or lose sums of other valued tokens.
Fether uses open-source libraries and components developed by third parties. While Parity Technologies Limited generally aims to use only widely adopted open-source technology and develop it in line with industry standards, such open-source technology may contain bugs and errors and may not function correctly in all circumstances. As a result, there is a risk that Parity Technologies or the Parity Technologies Team may have introduced unintentional weaknesses or bugs into the core infrastructural elements of Fether causing the system to lose Ethereum tokens ("ETH") and Ethereum Classic tokens ("ETC") stored in one or more User accounts or other accounts or lose sums of other valued tokens.

**Risk of Weaknesses or Exploitable Breakthroughs in the Field of Cryptography**

Cryptography is an art, not a science, and the state of the art can advance over time. Advances in code cracking, or technical advances such as the development of quantum computers, could present risks to cryptocurrencies and Fether, which could result in the theft or loss of ETH. To the extent possible, Parity Technologies intends to update the protocol underlying Fether to account for any advances in cryptography and to incorporate additional security measures, but it cannot predict the future of cryptography or guarantee that any security updates will be made, timely or successful.
Cryptography is an art, not a science, and the state of the art can advance over time. Advances in code cracking, or technical advances such as the development of quantum computers, could present risks to cryptocurrencies and Fether, which could result in the theft or loss of ETH and ETC. To the extent possible, Parity Technologies intends to update the protocol underlying Fether to account for any advances in cryptography and to incorporate additional security measures, but it cannot predict the future of cryptography or guarantee that any security updates will be made, timely or successful.

**Risk of Ether Mining Attacks**

As with other cryptocurrencies, the blockchain accessed by Fether is susceptible to mining attacks, including but not limited to double-spend attacks, majority mining power attacks, "selfish-mining" attacks, and race condition attacks. Any successful attacks present a risk to the Ethereum ecosystem, expected proper execution and sequencing of ETH transactions, and expected proper execution and sequencing of contract computations. Despite the efforts of Parity Technologies and the Parity Technologies Team, known or novel mining attacks may be successful.
As with other cryptocurrencies, the blockchain accessed by Fether is susceptible to mining attacks, including but not limited to double-spend attacks, majority mining power attacks, "selfish-mining" attacks, and race condition attacks. Any successful attacks present a risk to the Ethereum ecosystem, expected proper execution and sequencing of ETH and ETC transactions, and expected proper execution and sequencing of contract computations. Despite the efforts of Parity Technologies and the Parity Technologies Team, known or novel mining attacks may be successful.

**Risk of Rapid Adoption and Insufficiency of Computational Application Processing Power on the Ethereum Network**

If Ethereum is rapidly adopted, the demand for transaction processing and distributed application computations could rise dramatically and at a pace that exceeds the rate with which ETH miners can bring online additional mining power. Under such a scenario, the entire Ethereum ecosystem could become destabilized, due to the increased cost of running distributed applications. In turn, this could dampen interest in the Ethereum ecosystem and ETH. Insufficiency of computational resources and an associated rise in the price of ETH could result in businesses being unable to acquire scarce computational resources to run their distributed applications. This would represent revenue losses to businesses or worst case, cause businesses to cease operations because such operations have become uneconomical due to distortions in the crypto-economy.
If Ethereum is rapidly adopted, the demand for transaction processing and distributed application computations could rise dramatically and at a pace that exceeds the rate with which ETH and ETC miners can bring online additional mining power. Under such a scenario, the entire Ethereum ecosystem could become destabilized, due to the increased cost of running distributed applications. In turn, this could dampen interest in the Ethereum ecosystem and both ETH and ETC. Insufficiency of computational resources and an associated rise in the price of ETH or ETC could result in businesses being unable to acquire scarce computational resources to run their distributed applications. This would represent revenue losses to businesses or worst case, cause businesses to cease operations because such operations have become uneconomical due to distortions in the crypto-economy.

**Risk of temporary network incoherence**

We recommend any groups handling large or important transactions to maintain a voluntary 24 hour waiting period on any ETH deposited. If we become aware that the integrity of the network is at risk due to issues with Fether, we will endeavour to publish patches in a timely fashion to address the issues. We will endeavour to provide solutions within the voluntary 24 hour waiting period.
We recommend any groups handling large or important transactions to maintain a voluntary 24 hour waiting period on any ETH or ETC deposited. If we become aware that the integrity of the network is at risk due to issues with Fether, we will endeavour to publish patches in a timely fashion to address the issues. We will endeavour to provide solutions within the voluntary 24 hour waiting period.

**Use of Fether by you**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import withTokens from '../../utils/withTokens';
token: tokens[tokenAddress]
}))
@withAccount
@withBalance // Balance of current token (can be ETH)
@withEthBalance // ETH balance
@withBalance // Balance of current token (can be ETH or ETC)
@withEthBalance // ETH or ETC balance
@observer
class SignedTxSummary extends Component {
handleSubmit = values => {
Expand Down
12 changes: 8 additions & 4 deletions packages/fether-react/src/Send/TxForm/TxDetails/TxDetails.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,17 @@ ${this.renderTotalAmount()}`;
};

renderFee = () => {
const { estimatedTxFee } = this.props;
const { estimatedTxFee, values } = this.props;

if (!estimatedTxFee) {
return;
}

return `Fee: ${fromWei(estimatedTxFee, 'ether')
.toFixed(9)
.toString()} ETH (gas limit * gas price)`;
.toString()} ${
values.chainId.valueOf() === '61' ? 'ETC' : 'ETH'
} (gas limit * gas price)`;
};

renderTotalAmount = () => {
Expand All @@ -70,10 +72,12 @@ ${this.renderTotalAmount()}`;

return `Total Amount: ${fromWei(
estimatedTxFee.plus(
token.address === 'ETH' ? toWei(values.amount.toString()) : 0
token.address === 'ETH' || token.address === 'ETC'
? toWei(values.amount.toString())
: 0
),
'ether'
).toString()} ETH`;
).toString()} ${values.chainId.valueOf() === '61' ? 'ETC' : 'ETH'}`;
};

render () {
Expand Down
56 changes: 43 additions & 13 deletions packages/fether-react/src/Send/TxForm/TxForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,18 @@ const debug = Debug('TxForm');
@withAccount
@light({
// We need to wait for 3 values that might take time:
// - ethBalance: to check that we have enough to send amount+fees
// - ethBalance: to check that we have enough balance to send amount+fees
// It may be ETH or ETC corresponding to whether we are connected to the
// 'foundation' or 'classic' chain.
// - chainId & transactionCount: needed to construct the tx
// For the three of them, we add the `startWith()` operator so that the UI is
// not blocked while waiting for their first response.
chainId: () => chainId$().pipe(startWith(undefined)),
transactionCount: ({ account: { address } }) =>
transactionCountOf$(address).pipe(startWith(undefined))
})
@withBalance // Balance of current token (can be ETH)
@withEthBalance // ETH balance
@withBalance // Balance of current token (can be ETH or ETC)
@withEthBalance // ETH or ETC balance
@observer
class TxForm extends Component {
state = {
Expand Down Expand Up @@ -104,7 +106,7 @@ class TxForm extends Component {
const gasPriceBn = new BigNumber(gasPrice);
let output;

if (token.address === 'ETH') {
if (token.address === 'ETH' || token.address === 'ETC') {
output = fromWei(
toWei(balance).minus(gasBn.multipliedBy(toWei(gasPriceBn, 'shannon')))
);
Expand Down Expand Up @@ -378,7 +380,7 @@ class TxForm extends Component {
* Prevalidate form on user's input. These validations are sync.
*/
preValidate = values => {
const { balance, token } = this.props;
const { balance, chainId: currentChainIdBN, token } = this.props;

if (!values) {
return;
Expand All @@ -394,12 +396,19 @@ class TxForm extends Component {
return { amount: 'Please enter a valid amount' };
} else if (amountBn.isZero()) {
if (this.state.maxSelected) {
return { amount: 'ETH balance too low to pay for gas.' };
return {
amount: `${
currentChainIdBN.valueOf() === '61' ? 'ETC' : 'ETH'
} balance too low to pay for gas.`
};
}
return { amount: 'Please enter a non-zero amount' };
} else if (amountBn.isNegative()) {
return { amount: 'Please enter a positive amount' };
} else if (token.address === 'ETH' && toWei(values.amount).lt(1)) {
} else if (
(token.address === 'ETH' || token.address === 'ETC') &&
toWei(values.amount).lt(1)
) {
return { amount: 'Please enter at least 1 Wei' };
} else if (amountBn.dp() > token.decimals) {
return {
Expand All @@ -409,8 +418,17 @@ class TxForm extends Component {
};
} else if (balance && balance.lt(amountBn)) {
return { amount: `You don't have enough ${token.symbol} balance` };
} else if (!values.to || !isAddress(values.to)) {
} else if (
(!values.to || !isAddress(values.to)) &&
currentChainIdBN.valueOf() !== '61'
) {
return { to: 'Please enter a valid Ethereum address' };
// FIXME - modify to check if it is a valid ETC address
} else if (
(!values.to || isAddress(values.to)) &&
currentChainIdBN.valueOf() === '61'
) {
return { to: 'Please enter a valid Ethereum Classic address' };
} else if (values.to === '0x0000000000000000000000000000000000000000') {
return {
to: `You are not permitted to send ${
Expand All @@ -431,7 +449,7 @@ class TxForm extends Component {
}

try {
const { token } = this.props;
const { chainId: currentChainIdBN, token } = this.props;

const preValidation = this.preValidate(values);

Expand Down Expand Up @@ -473,12 +491,24 @@ class TxForm extends Component {
// Verify that `gas + (eth amount if sending eth) <= ethBalance`
if (
this.estimatedTxFee(values)
.plus(token.address === 'ETH' ? toWei(values.amount) : 0)
.plus(
token.address === 'ETH' || token.address === 'ETC'
? toWei(values.amount)
: 0
)
.gt(toWei(values.ethBalance))
) {
return token.address !== 'ETH'
? { amount: 'ETH balance too low to pay for gas' }
: { amount: "You don't have enough ETH balance" };
return token.address !== 'ETH' && token.address === 'ETC'
? {
amount: `${
currentChainIdBN.valueOf() === '61' ? 'ETC' : 'ETH'
} balance too low to pay for gas`
}
: {
amount: `You don't have enough ${
currentChainIdBN.valueOf() === '61' ? 'ETC' : 'ETH'
} balance`
};
}

debug('Transaction seems valid');
Expand Down
Loading

0 comments on commit 2d1e131

Please sign in to comment.