@ -1,5 +1,5 @@
/* @flow */
/* @flow */
'use strict' ;
import Web3 from 'web3' ;
import Web3 from 'web3' ;
import HDKey from 'hdkey' ;
import HDKey from 'hdkey' ;
@ -7,27 +7,27 @@ import HDKey from 'hdkey';
import EthereumjsUtil from 'ethereumjs-util' ;
import EthereumjsUtil from 'ethereumjs-util' ;
import EthereumjsTx from 'ethereumjs-tx' ;
import EthereumjsTx from 'ethereumjs-tx' ;
import TrezorConnect from 'trezor-connect' ;
import TrezorConnect from 'trezor-connect' ;
import type { ContractFactory , EstimateGasOptions } from 'web3' ;
import type BigNumber from 'bignumber.js' ;
import type { TransactionStatus , TransactionReceipt } from 'web3' ;
import { strip } from '../utils/ethUtils' ;
import { strip } from '../utils/ethUtils' ;
import * as WEB3 from './constants/web3' ;
import * as WEB3 from './constants/web3' ;
import * as PENDING from './constants/pendingTx' ;
import * as PENDING from './constants/pendingTx' ;
import * as AccountsActions from '. ./actions /AccountsActions';
import * as AccountsActions from '. /AccountsActions';
import * as TokenActions from '. ./actions /TokenActions';
import * as TokenActions from '. /TokenActions';
import type {
import type {
Dispatch ,
Dispatch ,
GetState ,
GetState ,
Action ,
Action ,
AsyncAction ,
AsyncAction ,
} from '~/flowtype' ;
} from '~/flowtype' ;
import type { ContractFactory , EstimateGasOptions } from 'web3' ;
import type BigNumber from 'bignumber.js' ;
import type { Account } from '../reducers/AccountsReducer' ;
import type { Account } from '../reducers/AccountsReducer' ;
import type { PendingTx } from '../reducers/PendingTxReducer' ;
import type { PendingTx } from '../reducers/PendingTxReducer' ;
import type { Web3Instance } from '../reducers/Web3Reducer' ;
import type { Web3Instance } from '../reducers/Web3Reducer' ;
import type { Token } from '../reducers/TokensReducer' ;
import type { Token } from '../reducers/TokensReducer' ;
import type { NetworkToken } from '../reducers/LocalStorageReducer' ;
import type { NetworkToken } from '../reducers/LocalStorageReducer' ;
import type { TransactionStatus , TransactionReceipt } from 'web3' ;
export type Web3Action = {
export type Web3Action = {
type : typeof WEB3 . READY ,
type : typeof WEB3 . READY ,
@ -53,10 +53,9 @@ export type Web3UpdateGasPriceAction = {
export function init ( instance : ? Web3 , coinIndex : number = 0 ) : AsyncAction {
export function init ( instance : ? Web3 , coinIndex : number = 0 ) : AsyncAction {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const { config , ERC20Abi } = getState ( ) . localStorage ;
const { config , ERC20Abi } = getState ( ) . localStorage ;
const coin = config . coins [ coinIndex ] ;
const coin = config . coins [ coinIndex ] ;
if ( ! coin ) {
if ( ! coin ) {
// all instances done
// all instances done
dispatch ( {
dispatch ( {
@ -72,12 +71,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
if ( instance ) {
if ( instance ) {
const currentHost = instance . currentProvider . host ;
const currentHost = instance . currentProvider . host ;
le t currentHostIndex : number = urls . indexOf ( currentHost ) ;
cons t currentHostIndex : number = urls . indexOf ( currentHost ) ;
if ( currentHostIndex + 1 < urls . length ) {
if ( currentHostIndex + 1 < urls . length ) {
web3host = urls [ currentHostIndex + 1 ] ;
web3host = urls [ currentHostIndex + 1 ] ;
} else {
} else {
console . error ( "TODO: Backend " + network + " not working" , instance . currentProvider ) ;
console . error ( ` TODO: Backend ${ network } not working ` , instance . currentProvider ) ;
dispatch ( {
dispatch ( {
type : WEB3 . CREATE ,
type : WEB3 . CREATE ,
@ -88,17 +87,17 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
erc20 : instance . eth . contract ( ERC20Abi ) ,
erc20 : instance . eth . contract ( ERC20Abi ) ,
latestBlock : '0' ,
latestBlock : '0' ,
gasPrice : '0' ,
gasPrice : '0' ,
}
} ,
} ) ;
} ) ;
// try next coin
// try next coin
dispatch ( init ( null , coinIndex + 1 ) ) ;
dispatch ( init ( null , coinIndex + 1 ) ) ;
return ;
return ;
}
}
}
}
//const instance = new Web3(window.web3.currentProvider);
//const instance = new Web3(window.web3.currentProvider);
const web3 = new Web3 ( new Web3 . providers . HttpProvider ( web3host ) ) ;
const web3 = new Web3 ( new Web3 . providers . HttpProvider ( web3host ) ) ;
// instance = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); // UBQ
// instance = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') ); // UBQ
//instance = new Web3( new Web3.providers.HttpProvider('https://node.expanse.tech/') ); // EXP
//instance = new Web3( new Web3.providers.HttpProvider('https://node.expanse.tech/') ); // EXP
@ -112,7 +111,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
// initial check if backend is running
// initial check if backend is running
if ( ! web3 . currentProvider . isConnected ( ) ) {
if ( ! web3 . currentProvider . isConnected ( ) ) {
// try different url
// try different url
dispatch ( init ( web3 , coinIndex ) ) ;
dispatch ( init ( web3 , coinIndex ) ) ;
return ;
return ;
}
}
@ -122,12 +121,12 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
type : WEB3 . CREATE ,
type : WEB3 . CREATE ,
instance : {
instance : {
network ,
network ,
web3 : web3 ,
web3 ,
chainId : coin . chainId ,
chainId : coin . chainId ,
erc20 ,
erc20 ,
latestBlock : '0' ,
latestBlock : '0' ,
gasPrice : '0' ,
gasPrice : '0' ,
}
} ,
} ) ;
} ) ;
// dispatch({
// dispatch({
@ -136,15 +135,13 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
// gasPrice
// gasPrice
// });
// });
// console.log("GET CHAIN", instance.version.network)
// console.log("GET CHAIN", instance.version.network)
// instance.version.getWhisper((err, shh) => {
// instance.version.getWhisper((err, shh) => {
// console.log("-----whisperrr", error, shh)
// console.log("-----whisperrr", error, shh)
// })
// })
// const sshFilter = instance.ssh.filter('latest');
// const sshFilter = instance.ssh.filter('latest');
// sshFilter.watch((error, blockHash) => {
// sshFilter.watch((error, blockHash) => {
@ -157,10 +154,9 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
const onBlockMined = async ( error : ? Error , blockHash : ? string ) => {
const onBlockMined = async ( error : ? Error , blockHash : ? string ) => {
if ( error ) {
if ( error ) {
window . setTimeout ( ( ) => {
window . setTimeout ( ( ) => {
// try again
// try again
onBlockMined ( new Error ( "manually_triggered_error" ) , undefined ) ;
onBlockMined ( new Error ( 'manually_triggered_error' ) , undefined ) ;
} , 30000 ) ;
} , 30000 ) ;
}
}
@ -168,7 +164,7 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
dispatch ( {
dispatch ( {
type : WEB3 . BLOCK _UPDATED ,
type : WEB3 . BLOCK _UPDATED ,
network ,
network ,
blockHash
blockHash ,
} ) ;
} ) ;
}
}
@ -181,70 +177,66 @@ export function init(instance: ?Web3, coinIndex: number = 0): AsyncAction {
// dispatch( getBalance(account) );
// dispatch( getBalance(account) );
// TODO: check if nonce was updated,
// TODO: check if nonce was updated,
// update tokens balance,
// update tokens balance,
// update account balance,
// update account balance,
// update pending transactions
// update pending transactions
}
}
dispatch ( getBalance ( account ) ) ;
dispatch ( getBalance ( account ) ) ;
// dispatch( getNonce(account) );
// dispatch( getNonce(account) );
}
}
const tokens = getState ( ) . tokens . filter ( t => t . network === network ) ;
const tokens = getState ( ) . tokens . filter ( t => t . network === network ) ;
for ( const token of tokens ) {
for ( const token of tokens ) {
dispatch ( getTokenBalance ( token ) ) ;
dispatch ( getTokenBalance ( token ) ) ;
}
}
dispatch ( getGasPrice ( network ) ) ;
dispatch ( getGasPrice ( network ) ) ;
const pending = getState ( ) . pending . filter ( p => p . network === network ) ;
const pending = getState ( ) . pending . filter ( p => p . network === network ) ;
for ( const tx of pending ) {
for ( const tx of pending ) {
dispatch ( getTransactionReceipt ( tx ) ) ;
dispatch ( getTransactionReceipt ( tx ) ) ;
}
}
} ;
}
// latestBlockFilter.watch(onBlockMined);
// latestBlockFilter.watch(onBlockMined);
onBlockMined ( new Error ( "manually_triggered_error" ) , undefined ) ;
onBlockMined ( new Error ( 'manually_triggered_error' ) , undefined ) ;
// init next coin
// init next coin
dispatch ( init ( web3 , coinIndex + 1 ) ) ;
dispatch ( init ( web3 , coinIndex + 1 ) ) ;
// let instance2 = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') );
// let instance2 = new Web3( new Web3.providers.HttpProvider('https://pyrus2.ubiqscan.io') );
// console.log("INIT WEB3", instance, instance2);
// console.log("INIT WEB3", instance, instance2);
// instance2.eth.getGasPrice((error, gasPrice) => {
// instance2.eth.getGasPrice((error, gasPrice) => {
// console.log("---gasss price from UBQ", gasPrice)
// console.log("---gasss price from UBQ", gasPrice)
// });
// });
}
} ;
}
}
export function getGasPrice ( network : string ) : AsyncAction {
export function getGasPrice ( network : string ) : AsyncAction {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const index : number = getState ( ) . web3 . findIndex ( w3 => w3 . network === network ) ;
const index : number = getState ( ) . web3 . findIndex ( w3 => w3 . network === network ) ;
const web3instance = getState ( ) . web3 [ index ] ;
const web3instance = getState ( ) . web3 [ index ] ;
const web3 = web3instance . web3 ;
const web3 = web3instance . web3 ;
web3 . eth . getGasPrice ( ( error , gasPrice ) => {
web3 . eth . getGasPrice ( ( error , gasPrice ) => {
if ( ! error ) {
if ( ! error ) {
if ( web3instance . gasPrice && web3instance . gasPrice . toString ( ) !== gasPrice . toString ( ) ) {
if ( web3instance . gasPrice && web3instance . gasPrice . toString ( ) !== gasPrice . toString ( ) ) {
dispatch ( {
dispatch ( {
type : WEB3 . GAS _PRICE _UPDATED ,
type : WEB3 . GAS _PRICE _UPDATED ,
network : network ,
network ,
gasPrice
gasPrice ,
} ) ;
} ) ;
}
}
}
}
} ) ;
} ) ;
}
} ;
}
}
export function getBalance ( account : Account ) : AsyncAction {
export function getBalance ( account : Account ) : AsyncAction {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === account . network ) [ 0 ] ;
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === account . network ) [ 0 ] ;
const web3 : Web3 = web3instance . web3 ;
const web3 : Web3 = web3instance . web3 ;
@ -256,42 +248,39 @@ export function getBalance(account: Account): AsyncAction {
account . address ,
account . address ,
account . network ,
account . network ,
account . deviceState ,
account . deviceState ,
newBalance
newBalance ,
) ) ;
) ) ;
// dispatch( loadHistory(addr) );
// dispatch( loadHistory(addr) );
}
}
}
}
} ) ;
} ) ;
}
} ;
}
}
export function getTokenBalance ( token : Token ) : AsyncAction {
export function getTokenBalance ( token : Token ) : AsyncAction {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === token . network ) [ 0 ] ;
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === token . network ) [ 0 ] ;
const web3 = web3instance . web3 ;
const web3 = web3instance . web3 ;
const contract = web3instance . erc20 . at ( token . address ) ;
const contract = web3instance . erc20 . at ( token . address ) ;
contract . balanceOf ( token . ethAddress , ( error : Error , balance : BigNumber ) => {
contract . balanceOf ( token . ethAddress , ( error : Error , balance : BigNumber ) => {
if ( balance ) {
if ( balance ) {
const newBalance : string = balance . dividedBy ( Math . pow ( 10 , token . decimals ) ) . toString ( 10 ) ;
const newBalance : string = balance . dividedBy ( Math . pow ( 10 , token . decimals ) ) . toString ( 10 ) ;
if ( newBalance !== token . balance ) {
if ( newBalance !== token . balance ) {
dispatch ( TokenActions . setBalance (
dispatch ( TokenActions . setBalance (
token . address ,
token . address ,
token . ethAddress ,
token . ethAddress ,
newBalance
newBalance ,
) ) ;
) ) ;
}
}
}
}
} ) ;
} ) ;
}
} ;
}
}
export function getNonce ( account : Account ) : AsyncAction {
export function getNonce ( account : Account ) : AsyncAction {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === account . network ) [ 0 ] ;
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === account . network ) [ 0 ] ;
const web3 = web3instance . web3 ;
const web3 = web3instance . web3 ;
@ -302,158 +291,138 @@ export function getNonce(account: Account): AsyncAction {
}
}
}
}
} ) ;
} ) ;
}
} ;
}
}
export const getTransactionReceipt = ( tx : PendingTx ) : AsyncAction => {
export const getTransactionReceipt = ( tx : PendingTx ) : AsyncAction => async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
return async ( dispatch : Dispatch , getState : GetState ) : Promise < void > => {
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === tx . network ) [ 0 ] ;
const web3 = web3instance . web3 ;
const web3instance = getState ( ) . web3 . filter ( w3 => w3 . network === tx . network ) [ 0 ] ;
web3 . eth . getTransaction ( tx . id , ( error : Error , status : TransactionStatus ) => {
const web3 = web3instance . web3 ;
if ( ! error && ! status ) {
dispatch ( {
web3 . eth . getTransaction ( tx . id , ( error : Error , status : TransactionStatus ) => {
type : PENDING . TX _NOT _FOUND ,
if ( ! error && ! status ) {
tx ,
dispatch ( {
} ) ;
type : PENDING . TX _NOT _FOUND ,
} else if ( status && status . blockNumber ) {
tx ,
web3 . eth . getTransactionReceipt ( tx . id , ( error : Error , receipt : TransactionReceipt ) => {
} )
if ( receipt ) {
} else if ( status && status . blockNumber ) {
if ( status . gas !== receipt . gasUsed ) {
web3 . eth . getTransactionReceipt ( tx . id , ( error : Error , receipt : TransactionReceipt ) => {
if ( receipt ) {
if ( status . gas !== receipt . gasUsed ) {
dispatch ( {
type : PENDING . TX _TOKEN _ERROR ,
tx
} )
}
dispatch ( {
dispatch ( {
type : PENDING . TX _ RESOLVED ,
type : PENDING . TX _TOKEN _ERROR ,
tx ,
tx ,
receipt
} ) ;
} )
}
}
dispatch ( {
} ) ;
type : PENDING . TX _RESOLVED ,
}
tx ,
} ) ;
receipt ,
}
} ) ;
}
}
} ) ;
export const getTransaction = ( web3 : Web3 , txid : string ) : Promise < any > => {
}
return new Promise ( ( resolve , reject ) => {
web3 . eth . getTransaction ( txid , ( error , result ) => {
if ( error ) {
reject ( error ) ;
} else {
resolve ( result ) ;
}
} ) ;
} ) ;
} ) ;
}
} ;
export const getBalanceAsync = ( web3 : Web3 , address : string ) : Promise < BigNumber > => {
export const getTransaction = ( web3 : Web3 , txid : string ) : Promise < any > => new Promise ( ( resolve , reject ) => {
return new Promise ( ( resolve , reject ) => {
web3 . eth . getTransaction ( txid , ( error , result ) => {
web3 . eth . getBalance ( address , ( error : Error , result : BigNumber ) => {
if ( error ) {
if ( error ) {
reject ( error ) ;
reject ( error ) ;
} else {
} else {
resolve ( result ) ;
resolve ( result ) ;
}
}
} ) ;
} ) ;
} ) ;
}
} ) ;
export const getTokenBalanceAsync = ( erc20 : ContractFactory , token : Token ) : Promise < string > => {
export const getBalanceAsync = ( web3 : Web3 , address : string ) : Promise < BigNumber > => new Promise ( ( resolve , reject ) => {
return new Promise ( ( resolve , reject ) => {
web3 . eth . getBalance ( address , ( error : Error , result : BigNumber ) => {
if ( error ) {
const contract = erc20 . at ( token . address ) ;
reject ( error ) ;
contract . balanceOf ( token . ethAddress , ( error : Error , balance : BigNumber ) => {
} else {
if ( error ) {
resolve ( result ) ;
reject ( error ) ;
}
} else {
const newBalance : string = balance . dividedBy ( Math . pow ( 10 , token . decimals ) ) . toString ( 10 ) ;
resolve ( newBalance ) ;
}
} ) ;
} ) ;
} ) ;
}
} ) ;
export const getTokenBalanceAsync = ( erc20 : ContractFactory , token : Token ) : Promise < string > => new Promise ( ( resolve , reject ) => {
const contract = erc20 . at ( token . address ) ;
contract . balanceOf ( token . ethAddress , ( error : Error , balance : BigNumber ) => {
if ( error ) {
reject ( error ) ;
} else {
const newBalance : string = balance . dividedBy ( Math . pow ( 10 , token . decimals ) ) . toString ( 10 ) ;
resolve ( newBalance ) ;
}
} ) ;
} ) ;
export const getNonceAsync = ( web3 : Web3 , address : string ) : Promise < number > => new Promise ( ( resolve , reject ) => {
web3 . eth . getTransactionCount ( address , ( error : Error , result : number ) => {
if ( error ) {
reject ( error ) ;
} else {
resolve ( result ) ;
}
} ) ;
} ) ;
export const getNonceAsync = ( web3 : Web3 , address : string ) : Promise < number > => {
return new Promise ( ( resolve , reject ) => {
export const getTokenInfoAsync = ( erc20 : ContractFactory , address : string ) : Promise < ? NetworkToken > => new Promise ( ( resolve , reject ) => {
web3 . eth . getTransactionCount ( address , ( error : Error , result : number ) => {
const contract = erc20 . at ( address , ( error , res ) => {
if ( error ) {
// console.warn("callback", error, res)
reject ( error ) ;
} else {
resolve ( result ) ;
}
} ) ;
} ) ;
} ) ;
}
const info : NetworkToken = {
address ,
name : '' ,
symbol : '' ,
decimals : 0 ,
} ;
export const getTokenInfoAsync = ( erc20 : ContractFactory , address : string ) : Promise < ? NetworkToken > => {
contract . name . call ( ( error : Error , name : string ) => {
return new Promise ( ( resolve , reject ) => {
if ( error ) {
resolve ( null ) ;
return ;
}
info . name = name ;
const contract = erc20 . at ( address , ( error , res ) => {
// console.warn("callback", error, res)
} ) ;
const info : NetworkToken = {
contract . symbol . call ( ( error : Error , symbol : string ) => {
address ,
name : '' ,
symbol : '' ,
decimals : 0
} ;
contract . name . call ( ( error : Error , name : string ) => {
if ( error ) {
if ( error ) {
resolve ( null ) ;
resolve ( null ) ;
return ;
return ;
} else {
info . name = name ;
}
}
info . symbol = symbol ;
contract . symbol . call ( ( error : Error , symbol : string ) => {
if ( error ) {
resolve ( null ) ;
contract . decimals . call ( ( error : Error , decimals : BigNumber ) => {
return ;
if ( decimals ) {
info . decimals = decimals . toNumber ( ) ;
resolve ( info ) ;
} else {
} else {
info . symbol = symbol ;
resolve( null ) ;
}
}
} ) ;
contract . decimals . call ( ( error : Error , decimals : BigNumber ) => {
if ( decimals ) {
info . decimals = decimals . toNumber ( ) ;
resolve ( info ) ;
} else {
resolve ( null ) ;
}
} ) ;
} )
} ) ;
} ) ;
} ) ;
} ) ;
}
} ) ;
export const estimateGas = ( web3 : Web3 , options : EstimateGasOptions ) : Promise < number > => {
export const estimateGas = ( web3 : Web3 , options : EstimateGasOptions ) : Promise < number > => new Promise ( ( resolve , reject ) => {
return new Promise ( ( resolve , reject ) => {
web3 . eth . estimateGas ( options , ( error : ? Error , gas : ? number ) => {
web3 . eth . estimateGas ( options , ( error : ? Error , gas : ? number ) => {
if ( error ) {
if ( error ) {
reject ( error ) ;
reject ( error ) ;
} else if ( typeof gas === 'number' ) {
} else if ( typeof gas === 'number' ) {
resolve ( gas ) ;
resolve ( gas ) ;
}
}
} ) ;
} ) ;
} ) ;
} )
}
export const pushTx = ( web3 : Web3 , tx : any ) : Promise < string > => new Promise ( ( resolve , reject ) => {
web3 . eth . sendRawTransaction ( tx , ( error : Error , result : string ) => {
export const pushTx = ( web3 : Web3 , tx : any ) : Promise < string > => {
if ( error ) {
return new Promise ( ( resolve , reject ) => {
reject ( error ) ;
web3 . eth . sendRawTransaction ( tx , ( error : Error , result : string ) => {
} else {
if ( error ) {
resolve ( result ) ;
reject ( error ) ;
}
} else {
} ) ;
resolve ( result ) ;
} ) ;
}
} ) ;
} )
}