@ -10,6 +10,7 @@ import {
clearLastSendToResponseState ,
shepherdElectrumSend ,
shepherdElectrumSendPreflight ,
shepherdGetRemoteBTCFees ,
copyString ,
} from '../../../actions/actionCreators' ;
import Store from '../../../store' ;
@ -21,11 +22,20 @@ import {
} from './sendCoin.render' ;
import { isPositiveNumber } from '../../../util/number' ;
import mainWindow from '../../../util/mainWindow' ;
import Slider , { Range } from 'rc-slider' ;
import ReactTooltip from 'react-tooltip' ;
// TODO: - add links to explorers
// - render z address trim
// - handle click outside
const _ feeLookup = [
'fastestFee' ,
'halfHourFee' ,
'hourFee' ,
'advanced'
] ;
class SendCoin extends React . Component {
constructor ( props ) {
super ( props ) ;
@ -44,7 +54,14 @@ class SendCoin extends React.Component {
coin : null ,
spvVerificationWarning : false ,
spvPreflightSendInProgress : false ,
btcFees : { } ,
btcFeesType : 'halfHourFee' ,
btcFeesAdvancedStep : 9 ,
btcFeesSize : 0 ,
btcFeesTimeBasedStep : 1 ,
btcPreflightRes : null ,
} ;
this . defaultState = JSON . parse ( JSON . stringify ( this . state ) ) ;
this . updateInput = this . updateInput . bind ( this ) ;
this . handleSubmit = this . handleSubmit . bind ( this ) ;
this . openDropMenu = this . openDropMenu . bind ( this ) ;
@ -58,13 +75,17 @@ class SendCoin extends React.Component {
this . isFullySynced = this . isFullySynced . bind ( this ) ;
this . setSendAmountAll = this . setSendAmountAll . bind ( this ) ;
this . setSendToSelf = this . setSendToSelf . bind ( this ) ;
this . fetchBTCFees = this . fetchBTCFees . bind ( this ) ;
this . onSliderChange = this . onSliderChange . bind ( this ) ;
this . onSliderChangeTime = this . onSliderChangeTime . bind ( this ) ;
}
setSendAmountAll ( ) {
const _ amount = this . state . amount ;
const _ amountSats = this . state . amount * 100000000 ;
const _ balanceSats = this . props . ActiveCoin . balance . balanceSats ;
const _ fees = mainWindow . spvFees ;
let _ fees = mainWindow . spvFees ;
_ fees . BTC = 0 ;
this . setState ( {
amount : Number ( ( 0.00000001 * ( _ balanceSats - _ fees [ this . props . ActiveCoin . coin ] ) ) . toFixed ( 8 ) ) ,
@ -136,6 +157,11 @@ class SendCoin extends React.Component {
Store . dispatch ( clearLastSendToResponseState ( ) ) ;
}
this . checkZAddressCount ( props ) ;
if ( this . props . ActiveCoin . activeSection !== props . ActiveCoin . activeSection &&
this . props . ActiveCoin . activeSection !== 'send' ) {
this . fetchBTCFees ( ) ;
}
}
setRecieverFromScan ( receiver ) {
@ -400,8 +426,29 @@ class SendCoin extends React.Component {
} ) ;
}
fetchBTCFees ( ) {
if ( this . props . ActiveCoin . mode === 'spv' &&
this . props . ActiveCoin . coin === 'BTC' ) {
shepherdGetRemoteBTCFees ( )
. then ( ( res ) => {
if ( res . msg === 'success' ) {
// TODO: check, approx fiat value
this . setState ( {
btcFees : res . result ,
btcFeesSize : this . state . btcFeesType === 'advanced' ? res . result . electrum [ this . state . btcFeesAdvancedStep ] : res . result . recommended [ _ feeLookup [ this . state . btcFeesTimeBasedStep ] ] ,
} ) ;
} else {
// TODO: fallback to local electrum
}
console . warn ( 'btcfees' , res ) ;
} ) ;
}
}
changeSendCoinStep ( step , back ) {
if ( step === 0 ) {
this . fetchBTCFees ( ) ;
if ( back ) {
this . setState ( {
currentStep : 0 ,
@ -411,21 +458,7 @@ class SendCoin extends React.Component {
} else {
Store . dispatch ( clearLastSendToResponseState ( ) ) ;
this . setState ( {
currentStep : 0 ,
addressType : null ,
sendFrom : null ,
sendFromAmount : 0 ,
sendTo : '' ,
sendToOA : null ,
amount : 0 ,
fee : 0 ,
addressSelectorOpen : false ,
renderAddressDropdown : true ,
subtractFee : false ,
spvVerificationWarning : false ,
spvPreflightSendInProgress : false ,
} ) ;
this . setState ( this . defaultState ) ;
}
}
@ -444,7 +477,8 @@ class SendCoin extends React.Component {
this . props . ActiveCoin . coin ,
this . state . amount * 100000000 ,
this . state . sendTo ,
this . props . Dashboard . electrumCoins [ this . props . ActiveCoin . coin ] . pub
this . props . Dashboard . electrumCoins [ this . props . ActiveCoin . coin ] . pub ,
this . props . ActiveCoin . coin === 'BTC' ? this . state . btcFeesSize : null
)
. then ( ( sendPreflight ) => {
if ( sendPreflight &&
@ -452,6 +486,7 @@ class SendCoin extends React.Component {
this . setState ( Object . assign ( { } , this . state , {
spvVerificationWarning : ! sendPreflight . result . utxoVerified ,
spvPreflightSendInProgress : false ,
btcPreflightRes : this . props . ActiveCoin . coin === 'BTC' ? { fee : sendPreflight . result . fee , value : sendPreflight . result . value , change : sendPreflight . result . change } : null ,
} ) ) ;
} else {
this . setState ( Object . assign ( { } , this . state , {
@ -502,7 +537,8 @@ class SendCoin extends React.Component {
this . props . ActiveCoin . coin ,
this . state . amount * 100000000 ,
this . state . sendTo ,
this . props . Dashboard . electrumCoins [ this . props . ActiveCoin . coin ] . pub
this . props . Dashboard . electrumCoins [ this . props . ActiveCoin . coin ] . pub ,
this . props . ActiveCoin . coin === 'BTC' ? this . state . btcFeesSize : null
)
) ;
}
@ -517,7 +553,8 @@ class SendCoin extends React.Component {
const _ amount = this . state . amount ;
const _ amountSats = this . state . amount * 100000000 ;
const _ balanceSats = this . props . ActiveCoin . balance . balanceSats ;
const _ fees = mainWindow . spvFees ;
let _ fees = mainWindow . spvFees ;
_ fees . BTC = 0 ;
if ( Number ( _ amountSats ) + _ fees [ this . props . ActiveCoin . coin ] > _ balanceSats ) {
Store . dispatch (
@ -638,6 +675,102 @@ class SendCoin extends React.Component {
}
}
onSliderChange ( value ) {
console . warn ( value ) ;
console . warn ( ` btc fee /byte ${ this . state . btcFees . electrum [ value ] } ` ) ;
this . setState ( {
btcFeesSize : this . state . btcFees . electrum [ value ] ,
btcFeesAdvancedStep : value ,
} ) ;
}
onSliderChangeTime ( value ) {
console . warn ( value ) ;
console . warn ( ` btc fee /byte ${ _ feeLookup [ value ] } ` ) ;
this . setState ( {
btcFeesSize : this . state . btcFees . recommended [ _ feeLookup [ value ] ] ,
btcFeesTimeBasedStep : value ,
btcFeesType : _ feeLookup [ value ] === 'advanced' ? 'advanced' : null ,
} ) ;
}
renderBTCFees ( ) {
if ( this . props . ActiveCoin . mode === 'spv' &&
this . props . ActiveCoin . coin === 'BTC' &&
! this . state . btcFees . lastUpdated ) {
return ( < div className = "col-lg-6 form-group form-material" > Fetching BTC fees ... < / d i v > ) ;
} else if ( this . props . ActiveCoin . mode === 'spv' && this . props . ActiveCoin . coin === 'BTC' && this . state . btcFees . lastUpdated ) {
const _ min = 0 ;
const _ max = this . state . btcFees . electrum . length - 1 ;
const _ confTime = [
'within less than 30 min' ,
'within 30 min' ,
'within 60 min' ,
] ;
const _ minTimeBased = 0 ;
const _ maxTimeBased = 3 ;
/ * l e t _ m a r k s = { } ;
for ( let i = _ min ; i < _ max ; i ++ ) {
_ marks [ i ] = i + 1 ;
} * /
return (
< div className = "col-lg-12 form-group form-material" >
< div >
< div >
Fee
< span >
< i
className = "icon fa-question-circle settings-help"
data - html = { true }
data - tip = { this . state . btcFeesType === 'advanced' ? 'Electrum based fee estimates may not be as accurate as bitcoinfees.earn.com.<br />It is advised to use fast/average/slow options if you want your transaction to be confirmed within 60 min time frame.' : 'Estimates are based on bitcoinfees.earn.com data.<br />Around 90% probability for a transaction to be confirmed within desired time frame.' } > < / i >
< ReactTooltip
effect = "solid"
className = "text-left" / >
< / s p a n >
< / d i v >
< div className = "send-target-block" >
{ this . state . btcFeesType !== 'advanced' &&
< span > Confirmation time < strong > { _ confTime [ this . state . btcFeesTimeBasedStep ] } < / s t r o n g > < / s p a n >
}
{ this . state . btcFeesType === 'advanced' &&
< span > Advanced selection < / s p a n >
}
< / d i v >
< Slider
className = "send-slider-time-based margin-bottom-70"
onChange = { this . onSliderChangeTime }
defaultValue = { this . state . btcFeesTimeBasedStep }
min = { _ minTimeBased }
max = { _ maxTimeBased }
dots = { true }
marks = { {
0 : 'fast' ,
1 : 'average' ,
2 : 'slow' ,
3 : 'advanced'
} } / >
{ this . state . btcFeesType === 'advanced' &&
< div >
< div className = "send-target-block" > Estimated to be included within the next < strong > { this . state . btcFeesAdvancedStep + 1 } { ( this . state . btcFeesAdvancedStep + 1 ) > 1 ? 'blocks' : 'block' } < / s t r o n g > < / d i v >
< Slider
onChange = { this . onSliderChange }
defaultValue = { this . state . btcFeesAdvancedStep }
min = { _ min }
max = { _ max } / >
< / d i v >
}
{ this . state . btcFeesSize > 0 &&
< div className = "margin-top-10" > Fee per byte { this . state . btcFeesSize } , per KB { this . state . btcFeesSize * 1024 } < / d i v >
}
< / d i v >
< / d i v >
) ;
}
}
render ( ) {
if ( this . props &&
this . props . ActiveCoin &&