2018-08-01 11:33:24 +12:00
'use strict' ;
angular
. module ( 'copayApp.controllers' )
. controller ( 'reviewController' , reviewController ) ;
2018-08-14 16:58:13 +12:00
function reviewController ( addressbookService , bitcoinCashJsService , bitcore , bitcoreCash , bwcError , clipboardService , configService , feeService , gettextCatalog , $interval , $ionicHistory , $ionicModal , ionicToast , lodash , $log , ongoingProcess , platformInfo , popupService , profileService , $scope , sendFlowService , shapeshiftService , soundService , $state , $timeout , txConfirmNotification , txFormatService , walletService ) {
2018-08-01 11:33:24 +12:00
var vm = this ;
2018-08-02 15:42:35 +02:00
2018-08-03 17:56:46 +12:00
vm . buttonText = '' ;
2018-08-02 11:48:41 +12:00
vm . destination = {
address : '' ,
balanceAmount : '' ,
2018-08-02 18:14:54 +12:00
balanceCurrency : '' ,
coin : '' ,
2018-08-02 11:48:41 +12:00
color : '' ,
2018-08-02 18:14:54 +12:00
currency : '' ,
currencyColor : '' ,
kind : '' , // 'address', 'contact', 'wallet'
2018-08-02 11:48:41 +12:00
name : ''
} ;
2018-08-14 15:53:18 +02:00
vm . displayAddress = '' ;
2018-08-02 10:20:03 +12:00
vm . feeCrypto = '' ;
vm . feeFiat = '' ;
2018-08-02 18:30:35 +02:00
vm . fiatCurrency = '' ;
2018-08-03 10:41:21 +12:00
vm . feeIsHigh = false ;
2018-08-02 18:30:35 +02:00
vm . feeLessThanACent = false ;
2018-08-03 19:14:33 +12:00
vm . isCordova = platformInfo . isCordova ;
vm . notReadyMessage = '' ;
2018-08-02 09:48:12 +12:00
vm . origin = {
balanceAmount : '' ,
balanceCurrency : '' ,
currency : '' ,
2018-08-02 10:07:25 +12:00
currencyColor : '' ,
2018-08-02 09:48:12 +12:00
} ;
2018-08-03 19:14:33 +12:00
vm . originWallet = null ;
2018-08-07 09:39:48 +12:00
vm . paymentExpired = false ;
2018-08-13 13:48:41 +02:00
vm . personalNotePlaceholder = gettextCatalog . getString ( 'Enter text here' ) ;
2018-08-01 17:17:34 +12:00
vm . primaryAmount = '' ;
2018-08-01 14:28:26 +12:00
vm . primaryCurrency = '' ;
2018-08-02 18:30:35 +02:00
vm . usingMerchantFee = false ;
2018-08-03 17:56:46 +12:00
vm . readyToSend = false ;
2018-08-07 09:39:48 +12:00
vm . remainingTimeStr = '' ;
2018-08-01 14:28:26 +12:00
vm . secondaryAmount = '' ;
vm . secondaryCurrency = '' ;
2018-08-02 16:05:12 +02:00
vm . sendingTitle = gettextCatalog . getString ( 'You are sending' ) ;
2018-08-03 19:14:33 +12:00
vm . sendStatus = '' ;
2018-08-07 09:39:48 +12:00
vm . showAddress = true ;
2018-08-03 17:56:46 +12:00
vm . thirdParty = false ;
2018-08-03 19:14:33 +12:00
vm . wallet = null ;
2018-08-06 23:19:46 +09:00
vm . memoExpanded = false ;
2018-08-07 09:39:48 +12:00
// Functions
2018-08-09 13:12:44 +12:00
vm . goBack = goBack ;
2018-08-07 09:39:48 +12:00
vm . onSuccessConfirm = onSuccessConfirm ;
2018-08-14 16:58:13 +12:00
vm . onShareTransaction = onShareTransaction ;
2018-08-07 09:39:48 +12:00
2018-08-08 17:10:47 +02:00
var sendFlowData ;
2018-08-02 18:14:54 +12:00
var config = null ;
2018-08-01 17:17:34 +12:00
var coin = '' ;
2018-08-02 18:30:35 +02:00
var countDown = null ;
2018-08-14 15:53:18 +02:00
var defaults = { } ;
2018-08-02 18:30:35 +02:00
var usingCustomFee = false ;
var usingMerchantFee = false ;
var destinationWalletId = '' ;
2018-08-14 16:58:13 +12:00
var lastTxId = '' ;
2018-08-02 09:48:12 +12:00
var originWalletId = '' ;
var priceDisplayIsFiat = true ;
2018-08-01 17:17:34 +12:00
var satoshis = null ;
2018-08-02 09:48:12 +12:00
var toAddress = '' ;
2018-08-02 18:30:35 +02:00
var tx = { } ;
2018-08-07 09:39:48 +12:00
var txPayproData = null ;
2018-08-03 10:41:21 +12:00
var unitFromSat = 0 ;
2018-08-02 09:48:12 +12:00
2018-08-02 18:30:35 +02:00
var FEE _TOO _HIGH _LIMIT _PERCENTAGE = 15 ;
2018-08-01 17:17:34 +12:00
2018-08-01 14:28:26 +12:00
$scope . $on ( "$ionicView.beforeEnter" , onBeforeEnter ) ;
function onBeforeEnter ( event , data ) {
2018-08-13 10:00:39 +12:00
console . log ( 'walletSelector onBeforeEnter sendflow ' , sendFlowService . state ) ;
2018-08-03 14:28:56 +02:00
defaults = configService . getDefaults ( ) ;
2018-08-29 17:28:07 +09:00
sendFlowData = sendFlowService . state . getClone ( ) ;
2018-08-08 17:10:47 +02:00
originWalletId = sendFlowData . fromWalletId ;
satoshis = parseInt ( sendFlowData . amount , 10 ) ;
toAddress = sendFlowData . toAddress ;
destinationWalletId = sendFlowData . toWalletId ;
2018-08-14 15:53:18 +02:00
vm . displayAddress = sendFlowData . displayAddress ;
2018-08-03 19:14:33 +12:00
vm . originWallet = profileService . getWallet ( originWalletId ) ;
vm . origin . currency = vm . originWallet . coin . toUpperCase ( ) ;
coin = vm . originWallet . coin ;
2018-08-01 14:28:26 +12:00
2018-08-08 17:10:47 +02:00
if ( sendFlowData . thirdParty ) {
2018-08-09 16:11:29 +12:00
vm . thirdParty = sendFlowData . thirdParty ;
handleThirdPartyInitIfBip70 ( ) ;
handleThirdPartyInitIfShapeshift ( ) ;
2018-08-02 15:42:35 +02:00
}
2018-08-02 18:14:54 +12:00
configService . get ( function onConfig ( err , configCache ) {
2018-08-01 14:28:26 +12:00
if ( err ) {
$log . err ( 'Error getting config.' , err ) ;
} else {
2018-08-02 18:14:54 +12:00
config = configCache ;
2018-08-02 10:07:25 +12:00
priceDisplayIsFiat = config . wallet . settings . priceDisplay === 'fiat' ;
2018-08-03 14:28:56 +02:00
vm . origin . currencyColor = ( vm . originWallet . coin === 'btc' ? defaults . bitcoinWalletColor : defaults . bitcoinCashWalletColor ) ;
console . log ( "coin" , vm . originWallet . coin , vm . origin . currencyColor , config . bitcoinWalletColor , vm . originWallet . coin === 'btc' ) ;
2018-08-14 15:53:18 +02:00
unitFromSat = 1 / config . wallet . settings . unitToSatoshi ;
2018-08-01 14:28:26 +12:00
}
2018-08-02 09:48:12 +12:00
updateSendAmounts ( ) ;
2018-08-03 19:14:33 +12:00
getOriginWalletBalance ( vm . originWallet ) ;
2018-08-02 19:51:50 +12:00
handleDestinationAsAddress ( toAddress , coin ) ;
2018-08-08 17:10:47 +02:00
handleDestinationAsWallet ( sendFlowData . toWalletId ) ;
2018-08-02 18:30:35 +02:00
createVanityTransaction ( data ) ;
2018-08-01 14:28:26 +12:00
} ) ;
2018-08-02 18:30:35 +02:00
}
2018-08-03 19:14:33 +12:00
vm . approve = function ( ) {
2018-08-07 15:02:29 +09:00
2018-08-03 19:14:33 +12:00
if ( ! tx || ! vm . originWallet ) return ;
2018-08-03 17:56:46 +12:00
2018-08-07 11:59:36 +12:00
if ( vm . paymentExpired ) {
2018-08-10 11:11:53 +09:00
popupService . showAlert ( null , gettextCatalog . getString ( 'This bitcoin payment request has expired.' , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ) ;
2018-08-07 11:59:36 +12:00
vm . sendStatus = '' ;
2018-08-03 17:56:46 +12:00
$timeout ( function ( ) {
$scope . $apply ( ) ;
} ) ;
return ;
}
2018-08-03 19:14:33 +12:00
ongoingProcess . set ( 'creatingTx' , true , statusChangeHandler ) ;
getTxp ( lodash . clone ( tx ) , vm . originWallet , false , function ( err , txp ) {
ongoingProcess . set ( 'creatingTx' , false , statusChangeHandler ) ;
2018-08-03 17:56:46 +12:00
if ( err ) return ;
// confirm txs for more that 20usd, if not spending/touchid is enabled
function confirmTx ( cb ) {
2018-08-03 19:14:33 +12:00
if ( walletService . isEncrypted ( vm . originWallet ) )
2018-08-03 17:56:46 +12:00
return cb ( ) ;
2018-08-03 19:14:33 +12:00
var amountUsd = parseFloat ( txFormatService . formatToUSD ( vm . originWallet . coin , txp . amount ) ) ;
2018-08-03 17:56:46 +12:00
return cb ( ) ;
} ;
function publishAndSign ( ) {
2018-08-03 19:14:33 +12:00
if ( ! vm . originWallet . canSign ( ) && ! vm . originWallet . isPrivKeyExternal ( ) ) {
2018-08-03 17:56:46 +12:00
$log . info ( 'No signing proposal: No private key' ) ;
2018-08-03 19:14:33 +12:00
return walletService . onlyPublish ( vm . originWallet , txp , function ( err ) {
2018-08-03 17:56:46 +12:00
if ( err ) setSendError ( err ) ;
2018-08-03 19:14:33 +12:00
} , statusChangeHandler ) ;
2018-08-03 17:56:46 +12:00
}
2018-08-03 19:14:33 +12:00
walletService . publishAndSign ( vm . originWallet , txp , function ( err , txp ) {
2018-08-03 17:56:46 +12:00
if ( err ) return setSendError ( err ) ;
if ( config . confirmedTxsNotifications && config . confirmedTxsNotifications . enabled ) {
2018-08-03 19:14:33 +12:00
txConfirmNotification . subscribe ( vm . originWallet , {
2018-08-03 17:56:46 +12:00
txid : txp . txid
} ) ;
2018-08-14 16:58:13 +12:00
lastTxId = txp . txid ;
2018-08-03 17:56:46 +12:00
}
2018-08-03 19:14:33 +12:00
} , statusChangeHandler ) ;
2018-08-03 17:56:46 +12:00
} ;
confirmTx ( function ( nok ) {
if ( nok ) {
2018-08-03 19:14:33 +12:00
vm . sendStatus = '' ;
2018-08-03 17:56:46 +12:00
$timeout ( function ( ) {
$scope . $apply ( ) ;
} ) ;
return ;
}
publishAndSign ( ) ;
} ) ;
} ) ;
} ;
2018-08-02 18:30:35 +02:00
vm . chooseFeeLevel = function ( tx , wallet ) {
if ( wallet . coin == 'bch' ) return ;
if ( usingMerchantFee ) return ;
var scope = $rootScope . $new ( true ) ;
scope . network = tx . network ;
scope . feeLevel = tx . feeLevel ;
scope . noSave = true ;
2018-08-03 19:14:33 +12:00
scope . coin = vm . originWallet . coin ;
2018-08-02 18:30:35 +02:00
if ( usingCustomFee ) {
scope . customFeePerKB = tx . feeRate ;
scope . feePerSatByte = tx . feeRate / 1000 ;
}
$ionicModal . fromTemplateUrl ( 'views/modals/chooseFeeLevel.html' , {
scope : scope ,
backdropClickToClose : false ,
hardwareBackButtonClose : false
} ) . then ( function ( modal ) {
scope . chooseFeeLevelModal = modal ;
scope . openModal ( ) ;
} ) ;
scope . openModal = function ( ) {
scope . chooseFeeLevelModal . show ( ) ;
} ;
scope . hideModal = function ( newFeeLevel , customFeePerKB ) {
scope . chooseFeeLevelModal . hide ( ) ;
$log . debug ( 'New fee level choosen:' + newFeeLevel + ' was:' + tx . feeLevel ) ;
usingCustomFee = newFeeLevel == 'custom' ? true : false ;
if ( tx . feeLevel == newFeeLevel && ! usingCustomFee ) return ;
tx . feeLevel = newFeeLevel ;
if ( usingCustomFee ) tx . feeRate = parseInt ( customFeePerKB ) ;
2018-08-01 14:28:26 +12:00
2018-08-03 19:14:33 +12:00
updateTx ( tx , vm . originWallet , {
2018-08-02 18:30:35 +02:00
clearCache : true ,
dryRun : true
} , function ( ) { } ) ;
} ;
} ;
function createVanityTransaction ( data ) {
2018-08-03 17:56:46 +12:00
console . log ( 'createVanityTransaction()' ) ;
2018-08-02 18:30:35 +02:00
var configFeeLevel = config . wallet . settings . feeLevel ? config . wallet . settings . feeLevel : 'normal' ;
// Grab stateParams
tx = {
2018-08-08 17:10:47 +02:00
amount : parseInt ( sendFlowData . amount ) ,
2018-08-09 13:39:27 +02:00
sendMax : sendFlowData . sendMax ,
2018-08-08 17:10:47 +02:00
fromWalletId : sendFlowData . fromWalletId ,
toAddress : sendFlowData . toAddress ,
2018-08-07 09:39:48 +12:00
paypro : txPayproData ,
2018-08-02 18:30:35 +02:00
feeLevel : configFeeLevel ,
spendUnconfirmed : config . wallet . spendUnconfirmed ,
// Vanity tx info (not in the real tx)
recipientType : vm . destination . kind || null ,
toName : vm . destination . name || null ,
toEmail : vm . destination . email || null ,
toColor : vm . destination . color || null ,
network : false ,
2018-08-03 19:14:33 +12:00
coin : vm . originWallet . coin ,
2018-08-02 18:30:35 +02:00
txp : { } ,
} ;
2018-08-07 09:39:48 +12:00
2018-08-02 18:30:35 +02:00
if ( data . stateParams . requiredFeeRate ) {
vm . usingMerchantFee = true ;
tx . feeRate = parseInt ( data . stateParams . requiredFeeRate ) ;
}
if ( tx . coin && tx . coin === 'bch' ) {
tx . feeLevel = 'normal' ;
}
2018-08-08 17:10:47 +02:00
var B = tx . coin === 'bch' ? bitcoreCash : bitcore ;
2018-08-02 18:30:35 +02:00
var networkName ;
try {
2018-08-03 17:56:46 +12:00
if ( vm . destination . kind === 'wallet' ) { // This is a wallet-to-wallet transfer
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'generatingNewAddress' , true ) ;
2018-08-07 14:23:53 +12:00
var toWallet = profileService . getWallet ( destinationWalletId ) ;
2018-08-02 18:30:35 +02:00
// We need an address to send to, so we ask the walletService to create a new address for the toWallet.
2018-08-03 17:56:46 +12:00
console . log ( 'Getting address for wallet...' ) ;
walletService . getAddress ( toWallet , true , function onWalletAddress ( err , addr ) {
console . log ( 'getAddress cb called' , err ) ;
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'generatingNewAddress' , false ) ;
2018-08-02 18:30:35 +02:00
tx . toAddress = addr ;
networkName = ( new B . Address ( tx . toAddress ) ) . network . name ;
tx . network = networkName ;
2018-08-03 17:56:46 +12:00
console . log ( 'calling setupTx() for wallet.' ) ;
2018-08-02 18:30:35 +02:00
setupTx ( tx ) ;
} ) ;
} else { // This is a Wallet-to-address transfer
networkName = ( new B . Address ( tx . toAddress ) ) . network . name ;
tx . network = networkName ;
2018-08-03 17:56:46 +12:00
console . log ( 'calling setupTx() for address.' ) ;
2018-08-02 18:30:35 +02:00
setupTx ( tx ) ;
}
} catch ( e ) {
2018-08-03 17:56:46 +12:00
console . error ( 'Error setting up tx' , e ) ;
2018-08-02 18:30:35 +02:00
var message = gettextCatalog . getString ( 'Invalid address' ) ;
popupService . showAlert ( null , message , function ( ) {
$ionicHistory . nextViewOptions ( {
disableAnimate : true ,
historyRoot : true
} ) ;
$state . go ( 'tabs.send' ) . then ( function ( ) {
$ionicHistory . clearHistory ( ) ;
} ) ;
} ) ;
return ;
}
}
2018-08-02 09:48:12 +12:00
function getOriginWalletBalance ( originWallet ) {
2018-08-03 19:14:33 +12:00
var balanceText = getWalletBalanceDisplayText ( vm . originWallet ) ;
2018-08-02 18:14:54 +12:00
vm . origin . balanceAmount = balanceText . amount ;
2018-08-02 19:51:50 +12:00
vm . origin . balanceCurrency = balanceText . currency ;
2018-08-02 18:14:54 +12:00
}
2018-08-02 18:30:35 +02:00
function getSendMaxInfo ( tx , wallet , cb ) {
if ( ! tx . sendMax ) return cb ( ) ;
//ongoingProcess.set('retrievingInputs', true);
walletService . getSendMaxInfo ( wallet , {
feePerKb : tx . feeRate ,
excludeUnconfirmedUtxos : ! tx . spendUnconfirmed ,
returnInputs : true ,
} , cb ) ;
} ;
function getTxp ( tx , wallet , dryRun , cb ) {
// ToDo: use a credential's (or fc's) function for this
if ( tx . description && ! wallet . credentials . sharedEncryptingKey ) {
var msg = gettextCatalog . getString ( 'Could not add message to imported wallet without shared encrypting key' ) ;
$log . warn ( msg ) ;
return setSendError ( msg ) ;
}
if ( tx . amount > Number . MAX _SAFE _INTEGER ) {
var msg = gettextCatalog . getString ( 'Amount too big' ) ;
$log . warn ( msg ) ;
return setSendError ( msg ) ;
}
var txp = { } ;
txp . outputs = [ {
'toAddress' : tx . toAddress ,
'amount' : tx . amount ,
2018-08-06 23:19:46 +09:00
'message' : vm . memo
2018-08-02 18:30:35 +02:00
} ] ;
if ( tx . sendMaxInfo ) {
txp . inputs = tx . sendMaxInfo . inputs ;
txp . fee = tx . sendMaxInfo . fee ;
} else {
if ( usingCustomFee || usingMerchantFee ) {
txp . feePerKb = tx . feeRate ;
} else txp . feeLevel = tx . feeLevel ;
}
2018-08-06 23:19:46 +09:00
txp . message = vm . memo ;
2018-08-02 18:30:35 +02:00
if ( tx . paypro ) {
txp . payProUrl = tx . paypro . url ;
}
txp . excludeUnconfirmedUtxos = ! tx . spendUnconfirmed ;
txp . dryRun = dryRun ;
walletService . createTx ( wallet , txp , function ( err , ctxp ) {
if ( err ) {
setSendError ( err ) ;
return cb ( err ) ;
}
return cb ( null , ctxp ) ;
} ) ;
} ;
2018-08-02 18:14:54 +12:00
function getWalletBalanceDisplayText ( wallet ) {
2018-08-02 09:48:12 +12:00
var balanceCryptoAmount = '' ;
var balanceCryptoCurrencyCode = '' ;
var balanceFiatAmount = '' ;
var balanceFiatCurrency = ''
2018-08-02 18:14:54 +12:00
var displayAmount = '' ;
var displayCurrency = '' ;
var walletStatus = null ;
if ( wallet . status . isValid ) {
walletStatus = wallet . status ;
} else if ( wallet . cachedStatus . isValid ) {
walletStatus = wallet . cachedStatus ;
2018-08-02 09:48:12 +12:00
}
2018-08-02 18:14:54 +12:00
if ( walletStatus ) {
var cryptoBalanceParts = walletStatus . spendableBalanceStr . split ( ' ' ) ;
2018-08-02 09:48:12 +12:00
balanceCryptoAmount = cryptoBalanceParts [ 0 ] ;
balanceCryptoCurrencyCode = cryptoBalanceParts . length > 1 ? cryptoBalanceParts [ 1 ] : '' ;
2018-08-02 18:14:54 +12:00
if ( walletStatus . alternativeBalanceAvailable ) {
balanceFiatAmount = walletStatus . spendableBalanceAlternative ;
balanceFiatCurrency = walletStatus . alternativeIsoCode ;
2018-08-02 09:48:12 +12:00
}
}
if ( priceDisplayIsFiat ) {
2018-08-02 18:14:54 +12:00
displayAmount = balanceFiatAmount ? balanceFiatAmount : balanceCryptoAmount ;
displayCurrency = balanceFiatAmount ? balanceFiatCurrency : balanceCryptoCurrencyCode ;
2018-08-02 09:48:12 +12:00
} else {
2018-08-02 18:14:54 +12:00
displayAmount = balanceCryptoAmount ;
displayCurrency = balanceCryptoCurrencyCode ;
}
return {
amount : displayAmount ,
currency : displayCurrency
} ;
}
2018-08-09 13:12:44 +12:00
function goBack ( ) {
2018-08-29 17:28:07 +09:00
sendFlowService . router . goBack ( ) ;
2018-08-09 13:12:44 +12:00
}
2018-08-02 19:51:50 +12:00
function handleDestinationAsAddress ( address , originCoin ) {
if ( ! address ) {
return ;
}
// Check if the recipient is a contact
addressbookService . get ( originCoin + address , function ( err , contact ) {
if ( ! err && contact ) {
2018-08-09 12:12:29 +12:00
handleDestinationAsAddressOfContact ( contact ) ;
2018-08-02 19:51:50 +12:00
} else {
2018-08-09 12:12:29 +12:00
if ( originCoin === 'bch' ) {
vm . destination . address = bitcoinCashJsService . readAddress ( address ) . cashaddr ;
} else {
vm . destination . address = address ;
}
2018-08-02 19:51:50 +12:00
vm . destination . kind = 'address' ;
}
} ) ;
}
2018-08-09 12:12:29 +12:00
function handleDestinationAsAddressOfContact ( contact ) {
2018-08-02 19:51:50 +12:00
vm . destination . kind = 'contact' ;
vm . destination . name = contact . name ;
2018-08-02 18:30:35 +02:00
vm . destination . email = contact . email ;
2018-08-03 14:28:56 +02:00
vm . destination . color = contact . coin === 'btc' ? defaults . bitcoinWalletColor : defaults . bitcoinCashWalletColor ;
2018-08-02 19:51:50 +12:00
vm . destination . currency = contact . coin . toUpperCase ( ) ;
vm . destination . currencyColor = vm . destination . color ;
}
2018-08-02 18:14:54 +12:00
function handleDestinationAsWallet ( walletId ) {
destinationWalletId = walletId ;
2018-08-02 19:51:50 +12:00
if ( ! destinationWalletId ) {
return ;
}
2018-08-02 18:14:54 +12:00
2018-08-02 19:51:50 +12:00
var destinationWallet = profileService . getWallet ( destinationWalletId ) ;
vm . destination . coin = destinationWallet . coin ;
vm . destination . color = destinationWallet . color ;
vm . destination . currency = destinationWallet . coin . toUpperCase ( ) ;
vm . destination . kind = 'wallet' ;
vm . destination . name = destinationWallet . name ;
2018-08-03 14:28:56 +02:00
if ( defaults ) {
vm . destination . currencyColor = vm . destination . coin === 'btc' ? defaults . bitcoinWalletColor : defaults . bitcoinCashWalletColor ;
2018-08-02 09:48:12 +12:00
}
2018-08-02 19:51:50 +12:00
var balanceText = getWalletBalanceDisplayText ( destinationWallet ) ;
vm . destination . balanceAmount = balanceText . amount ;
vm . destination . balanceCurrency = balanceText . currency ;
2018-08-02 09:48:12 +12:00
}
2018-08-07 09:39:48 +12:00
function handleThirdPartyInitIfBip70 ( ) {
if ( vm . thirdParty . id === 'bip70' ) {
2018-08-07 11:59:36 +12:00
vm . sendingTitle = gettextCatalog . getString ( 'You are paying' ) ;
2018-08-07 11:34:35 +12:00
vm . memo = vm . thirdParty . memo ;
vm . memoExpanded = ! ! vm . memo ;
2018-08-07 17:58:35 +12:00
vm . destination . name = vm . thirdParty . name ;
2018-08-07 11:34:35 +12:00
2018-08-07 09:39:48 +12:00
txPayproData = {
caTrusted : vm . thirdParty . caTrusted ,
domain : vm . thirdParty . domain ,
expires : vm . thirdParty . expires ,
toAddress : toAddress ,
url : vm . thirdParty . url ,
verified : vm . thirdParty . verified ,
} ;
}
}
function handleThirdPartyInitIfShapeshift ( ) {
if ( vm . thirdParty . id === 'shapeshift' ) {
vm . sendingTitle = gettextCatalog . getString ( 'You are shifting' ) ;
if ( ! vm . thirdParty . data ) {
vm . thirdParty . data = { } ;
}
2018-08-07 14:23:53 +12:00
var toWallet = profileService . getWallet ( destinationWalletId ) ;
2018-08-07 14:48:43 +12:00
vm . destination . name = toWallet . name ;
vm . destination . color = toWallet . color ;
vm . destination . currency = toWallet . coin . toUpperCase ( ) ;
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'connectingShapeshift' , true ) ;
2018-08-07 14:48:43 +12:00
walletService . getAddress ( vm . originWallet , false , function onReturnWalletAddress ( err , returnAddr ) {
if ( err ) {
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'connectingShapeshift' , false ) ;
2018-08-10 11:11:53 +09:00
popupService . showAlert ( gettextCatalog . getString ( 'Shapeshift Error' ) , err . toString ( ) , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ;
2018-08-07 14:48:43 +12:00
return ;
}
walletService . getAddress ( toWallet , false , function onWithdrawalWalletAddress ( err , withdrawalAddr ) {
if ( err ) {
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'connectingShapeshift' , false ) ;
2018-08-10 11:11:53 +09:00
popupService . showAlert ( gettextCatalog . getString ( 'Shapeshift Error' ) , err . toString ( ) , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ;
2018-08-07 14:48:43 +12:00
return ;
}
2018-08-07 20:11:21 +09:00
shapeshiftService . shiftIt ( vm . originWallet . coin , toWallet . coin , withdrawalAddr , returnAddr , function onShiftIt ( err , shapeshiftData ) {
if ( err && err != null ) {
2018-08-08 17:11:16 +09:00
ongoingProcess . set ( 'connectingShapeshift' , false ) ;
2018-08-10 11:11:53 +09:00
popupService . showAlert ( gettextCatalog . getString ( 'Shapeshift Error' ) , err . toString ( ) , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ;
2018-08-07 20:11:21 +09:00
} else {
vm . memo = 'ShapeShift Order:\nhttps://www.shapeshift.io/#/status/' + shapeshiftData . orderId ;
2018-08-07 20:50:56 +09:00
vm . memoExpanded = ! ! vm . memo ;
2018-08-07 20:11:21 +09:00
tx . toAddress = shapeshiftData . toAddress ;
vm . destination . address = toAddress ;
vm . destination . kind = 'shapeshift' ;
}
2018-08-07 09:39:48 +12:00
} ) ;
} ) ;
} ) ;
}
}
2018-08-14 16:58:13 +12:00
function onShareTransaction ( ) {
var explorerTxUrl = 'https://explorer.bitcoin.com/' + tx . coin + '/tx/' + lastTxId ;
if ( platformInfo . isCordova ) {
var text = gettextCatalog . getString ( 'Take a look at this Bitcoin Cash transaction here: ' ) + explorerTxUrl ;
if ( coin === 'btc' ) {
text = gettextCatalog . getString ( 'Take a look at this Bitcoin transaction here: ' ) + explorerTxUrl ;
}
window . plugins . socialsharing . share ( text , null , null , null ) ;
} else {
ionicToast . show ( gettextCatalog . getString ( 'Copied to clipboard' ) , 'bottom' , false , 3000 ) ;
clipboardService . copyToClipboard ( explorerTxUrl ) ;
}
}
2018-08-07 09:39:48 +12:00
function startExpirationTimer ( expirationTime ) {
vm . paymentExpired = false ;
setExpirationTime ( ) ;
countDown = $interval ( function ( ) {
setExpirationTime ( ) ;
} , 1000 ) ;
function setExpirationTime ( ) {
console . log ( 'setExpirationTime()' ) ;
var now = Math . floor ( Date . now ( ) / 1000 ) ;
if ( now > expirationTime ) {
setExpiredValues ( ) ;
return ;
}
var totalSecs = expirationTime - now ;
var m = Math . floor ( totalSecs / 60 ) ;
var s = totalSecs % 60 ;
vm . remainingTimeStr = m + ":" + ( '0' + s ) . slice ( - 2 ) ;
} ;
function setExpiredValues ( ) {
vm . paymentExpired = true ;
vm . remainingTimeStr = gettextCatalog . getString ( 'Expired' ) ;
2018-08-07 11:07:19 +12:00
vm . readyToSend = false ;
2018-08-07 09:39:48 +12:00
if ( countDown ) $interval . cancel ( countDown ) ;
$timeout ( function ( ) {
$scope . $apply ( ) ;
} ) ;
} ;
} ;
2018-08-02 09:48:12 +12:00
function updateSendAmounts ( ) {
2018-08-01 17:17:34 +12:00
if ( typeof satoshis !== 'number' ) {
return ;
}
2018-08-02 09:48:12 +12:00
var cryptoAmount = '' ;
var cryptoCurrencyCode = '' ;
2018-08-01 17:17:34 +12:00
var amountStr = txFormatService . formatAmountStr ( coin , satoshis ) ;
2018-08-02 09:48:12 +12:00
if ( amountStr ) {
var amountParts = amountStr . split ( ' ' ) ;
cryptoAmount = amountParts [ 0 ] ;
cryptoCurrencyCode = amountParts . length > 1 ? amountParts [ 1 ] : '' ;
}
// Want to avoid flashing of amount strings so do all formatting after this has returned.
2018-08-01 17:17:34 +12:00
txFormatService . formatAlternativeStr ( coin , satoshis , function ( v ) {
if ( ! v ) {
2018-08-02 09:48:12 +12:00
vm . primaryAmount = cryptoAmount ;
vm . primaryCurrency = cryptoCurrencyCode ;
2018-08-01 17:17:34 +12:00
vm . secondaryAmount = '' ;
vm . secondaryCurrency = '' ;
return ;
}
vm . secondaryAmount = vm . primaryAmount ;
vm . secondaryCurrency = vm . primaryCurrency ;
var fiatParts = v . split ( ' ' ) ;
2018-08-02 09:48:12 +12:00
var fiatAmount = fiatParts [ 0 ] ;
var fiatCurrency = fiatParts . length > 1 ? fiatParts [ 1 ] : '' ;
if ( priceDisplayIsFiat ) {
vm . primaryAmount = fiatAmount ;
vm . primaryCurrency = fiatCurrency ;
vm . secondaryAmount = cryptoAmount ;
vm . secondaryCurrency = cryptoCurrencyCode ;
} else {
vm . primaryAmount = cryptoAmount ;
vm . primaryCurrency = cryptoCurrencyCode ;
vm . secondaryAmount = fiatAmount ;
vm . secondaryCurrency = fiatCurrency ;
}
2018-08-01 17:17:34 +12:00
} ) ;
}
2018-08-07 09:39:48 +12:00
function onSuccessConfirm ( ) {
2018-08-03 19:14:33 +12:00
vm . sendStatus = '' ;
$ionicHistory . nextViewOptions ( {
disableAnimate : true ,
historyRoot : true
} ) ;
$state . go ( 'tabs.send' ) . then ( function ( ) {
$ionicHistory . clearHistory ( ) ;
$state . transitionTo ( 'tabs.home' ) ;
} ) ;
} ;
2018-08-02 18:30:35 +02:00
function setButtonText ( isMultisig , isPayPro ) {
if ( isPayPro ) {
if ( vm . isCordova ) {
vm . buttonText = gettextCatalog . getString ( 'Slide to pay' ) ;
} else {
vm . buttonText = gettextCatalog . getString ( 'Click to pay' ) ;
}
} else if ( isMultisig ) {
if ( vm . isCordova ) {
vm . buttonText = gettextCatalog . getString ( 'Slide to accept' ) ;
} else {
vm . buttonText = gettextCatalog . getString ( 'Click to accept' ) ;
}
} else {
if ( vm . isCordova ) {
vm . buttonText = gettextCatalog . getString ( 'Slide to send' ) ;
} else {
vm . buttonText = gettextCatalog . getString ( 'Click to send' ) ;
}
}
}
2018-08-03 17:56:46 +12:00
function setNotReady ( msg , criticalError ) {
vn . readyToSend = false ;
vm . notReadyMessage = msg ;
$scope . criticalError = criticalError ;
$log . warn ( 'Not ready to make the payment:' + msg ) ;
$timeout ( function ( ) {
$scope . $apply ( ) ;
} ) ;
} ;
2018-08-03 10:41:21 +12:00
function setSendError ( msg ) {
$scope . sendStatus = '' ;
2018-08-03 17:56:46 +12:00
vm . readyToSend = false ;
2018-08-03 10:41:21 +12:00
$timeout ( function ( ) {
$scope . $apply ( ) ;
} ) ;
2018-08-10 11:11:53 +09:00
popupService . showAlert ( gettextCatalog . getString ( 'Error at confirm' ) , bwcError . msg ( msg ) , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ;
2018-08-03 10:41:21 +12:00
} ;
2018-08-02 18:30:35 +02:00
function setupTx ( tx ) {
if ( tx . coin === 'bch' ) {
tx . displayAddress = bitcoinCashJsService . readAddress ( tx . toAddress ) . cashaddr ;
} else {
2018-08-03 13:13:29 +02:00
tx . displayAddress = tx . toAddress ;
2018-08-02 18:30:35 +02:00
}
addressbookService . get ( tx . coin + tx . toAddress , function ( err , addr ) { // Check if the recipient is a contact
if ( ! err && addr ) {
tx . toName = addr . name ;
tx . toEmail = addr . email ;
tx . recipientType = 'contact' ;
}
} ) ;
vm . showAddress = false ;
2018-08-03 19:14:33 +12:00
setButtonText ( vm . originWallet . credentials . m > 1 , ! ! tx . paypro ) ;
2018-08-02 18:30:35 +02:00
if ( tx . paypro )
2018-08-07 09:39:48 +12:00
startExpirationTimer ( tx . paypro . expires ) ;
2018-08-02 18:30:35 +02:00
2018-08-03 19:14:33 +12:00
updateTx ( tx , vm . originWallet , {
2018-08-02 18:30:35 +02:00
dryRun : true
} , function ( err ) {
$timeout ( function ( ) {
$scope . $apply ( ) ;
} , 10 ) ;
} ) ;
// setWalletSelector(tx.coin, tx.network, tx.amount, function(err) {
// if (err) {
// return exitWithError('Could not update wallets');
// }
//
// if (vm.wallets.length > 1) {
// vm.showWalletSelector();
// } else if (vm.wallets.length) {
// setWallet(vm.wallets[0], tx);
// }
// });
}
2018-08-03 19:14:33 +12:00
2018-08-07 12:16:59 +12:00
function showSendMaxWarning ( wallet , sendMaxInfo ) {
var feeAlternative = '' ,
msg = '' ;
function verifyExcludedUtxos ( ) {
var warningMsg = [ ] ;
if ( sendMaxInfo . utxosBelowFee > 0 ) {
warningMsg . push ( gettextCatalog . getString ( "A total of {{amountBelowFeeStr}} were excluded. These funds come from UTXOs smaller than the network fee provided." , {
amountBelowFeeStr : txFormatService . formatAmountStr ( wallet . coin , sendMaxInfo . amountBelowFee )
} ) ) ;
}
if ( sendMaxInfo . utxosAboveMaxSize > 0 ) {
warningMsg . push ( gettextCatalog . getString ( "A total of {{amountAboveMaxSizeStr}} were excluded. The maximum size allowed for a transaction was exceeded." , {
amountAboveMaxSizeStr : txFormatService . formatAmountStr ( vm . originWallet . coin , sendMaxInfo . amountAboveMaxSize )
} ) ) ;
}
return warningMsg . join ( '\n' ) ;
} ;
feeAlternative = txFormatService . formatAlternativeStr ( vm . originWallet . coin , sendMaxInfo . fee ) ;
if ( feeAlternative ) {
msg = gettextCatalog . getString ( "{{feeAlternative}} will be deducted for bitcoin networking fees ({{fee}})." , {
fee : txFormatService . formatAmountStr ( vm . originWallet . coin , sendMaxInfo . fee ) ,
feeAlternative : feeAlternative
} ) ;
} else {
msg = gettextCatalog . getString ( "{{fee}} will be deducted for bitcoin networking fees)." , {
fee : txFormatService . formatAmountStr ( vm . originWallet . coin , sendMaxInfo . fee )
} ) ;
}
var warningMsg = verifyExcludedUtxos ( ) ;
if ( ! lodash . isEmpty ( warningMsg ) )
msg += '\n' + warningMsg ;
popupService . showAlert ( null , msg , function ( ) { } ) ;
} ;
2018-08-03 19:14:33 +12:00
function statusChangeHandler ( processName , showName , isOn ) {
$log . debug ( 'statusChangeHandler: ' , processName , showName , isOn ) ;
if (
(
processName === 'broadcastingTx' ||
( ( processName === 'signingTx' ) && vm . originWallet . m > 1 ) ||
( processName == 'sendingTx' && ! vm . originWallet . canSign ( ) && ! vm . originWallet . isPrivKeyExternal ( ) )
) && ! isOn ) {
2018-08-03 19:59:25 +12:00
vm . sendStatus = 'success' ;
2018-08-03 19:14:33 +12:00
if ( $state . current . name === "tabs.send.review" ) { // XX SP: Otherwise all open wallets on other devices play this sound if you have been in a send flow before on that device.
soundService . play ( 'misc/payment_sent.mp3' ) ;
}
var channel = "firebase" ;
if ( platformInfo . isNW ) {
channel = "ga" ;
}
// When displaying Fiat, if the formatting fails, the crypto will be the primary amount.
2018-08-06 21:46:03 +12:00
var amount = unitFromSat * satoshis ;
2018-08-03 19:14:33 +12:00
var log = new window . BitAnalytics . LogEvent ( "transfer_success" , [ {
"coin" : vm . originWallet . coin ,
"type" : "outgoing" ,
"amount" : amount ,
"fees" : vm . feeCrypto
} ] , [ channel , "adjust" ] ) ;
window . BitAnalytics . LogEventHandlers . postEvent ( log ) ;
$timeout ( function ( ) {
$scope . $digest ( ) ;
} , 100 ) ;
} else if ( showName ) {
2018-08-03 19:59:25 +12:00
vm . sendStatus = showName ;
2018-08-03 19:14:33 +12:00
}
} ;
2018-08-02 18:30:35 +02:00
function updateTx ( tx , wallet , opts , cb ) {
ongoingProcess . set ( 'calculatingFee' , true ) ;
if ( opts . clearCache ) {
tx . txp = { } ;
}
// $scope.tx = tx;
// function updateAmount() {
// if (!tx.amount) return;
//
// // Amount
// tx.amountStr = txFormatService.formatAmountStr(originWallet.coin, tx.amount);
// tx.amountValueStr = tx.amountStr.split(' ')[0];
// tx.amountUnitStr = tx.amountStr.split(' ')[1];
// txFormatService.formatAlternativeStr(wallet.coin, tx.amount, function(v) {
// var parts = v.split(' ');
// tx.alternativeAmountStr = v;
// tx.alternativeAmountValueStr = parts[0];
// tx.alternativeAmountUnitStr = (parts.length > 0) ? parts[1] : '';
// });
// }
//
// updateAmount();
// refresh();
2018-08-03 19:14:33 +12:00
var feeServiceLevel = usingMerchantFee && vm . originWallet . coin == 'btc' ? 'urgent' : tx . feeLevel ;
feeService . getFeeRate ( vm . originWallet . coin , tx . network , feeServiceLevel , function ( err , feeRate ) {
2018-08-02 18:30:35 +02:00
if ( err ) {
ongoingProcess . set ( 'calculatingFee' , false ) ;
return cb ( err ) ;
}
var msg ;
if ( usingCustomFee ) {
msg = gettextCatalog . getString ( 'Custom' ) ;
tx . feeLevelName = msg ;
} else if ( usingMerchantFee ) {
$log . info ( 'Using Merchant Fee:' + tx . feeRate + ' vs. Urgent level:' + feeRate ) ;
msg = gettextCatalog . getString ( 'Suggested by Merchant' ) ;
tx . feeLevelName = msg ;
} else {
tx . feeLevelName = feeService . feeOpts [ tx . feeLevel ] ;
tx . feeRate = feeRate ;
}
getSendMaxInfo ( lodash . clone ( tx ) , wallet , function ( err , sendMaxInfo ) {
if ( err ) {
ongoingProcess . set ( 'calculatingFee' , false ) ;
var msg = gettextCatalog . getString ( 'Error getting SendMax information' ) ;
return setSendError ( msg ) ;
}
if ( sendMaxInfo ) {
$log . debug ( 'Send max info' , sendMaxInfo ) ;
if ( tx . sendMax && sendMaxInfo . amount == 0 ) {
ongoingProcess . set ( 'calculatingFee' , false ) ;
2018-08-03 17:56:46 +12:00
setNotReady ( gettextCatalog . getString ( 'Insufficient confirmed funds' ) ) ;
2018-08-10 11:11:53 +09:00
popupService . showAlert ( gettextCatalog . getString ( 'Error' ) , gettextCatalog . getString ( 'Not enough funds for fee' ) , function ( ) {
$ionicHistory . goBack ( ) ;
} ) ;
2018-08-02 18:30:35 +02:00
return cb ( 'no_funds' ) ;
}
tx . sendMaxInfo = sendMaxInfo ;
tx . amount = tx . sendMaxInfo . amount ;
2018-08-06 21:46:03 +12:00
satoshis = tx . amount ;
updateSendAmounts ( ) ;
2018-08-02 18:30:35 +02:00
ongoingProcess . set ( 'calculatingFee' , false ) ;
$timeout ( function ( ) {
showSendMaxWarning ( wallet , sendMaxInfo ) ;
} , 200 ) ;
}
// txp already generated for this wallet?
if ( tx . txp [ wallet . id ] ) {
ongoingProcess . set ( 'calculatingFee' , false ) ;
2018-08-03 17:56:46 +12:00
vm . readyToSend = true ;
2018-08-02 18:30:35 +02:00
updateSendAmounts ( ) ;
2018-08-03 17:56:46 +12:00
$scope . $apply ( ) ;
2018-08-02 18:30:35 +02:00
return cb ( ) ;
}
2018-08-03 17:56:46 +12:00
console . log ( 'calling getTxp() from getSendMaxInfo cb.' ) ;
2018-08-02 18:30:35 +02:00
getTxp ( lodash . clone ( tx ) , wallet , opts . dryRun , function ( err , txp ) {
ongoingProcess . set ( 'calculatingFee' , false ) ;
if ( err ) {
if ( err . message == 'Insufficient funds' ) {
2018-08-03 17:56:46 +12:00
setNotReady ( gettextCatalog . getString ( 'Insufficient funds' ) ) ;
2018-08-02 18:30:35 +02:00
popupService . showAlert ( gettextCatalog . getString ( 'Error' ) , gettextCatalog . getString ( 'Not enough funds for fee' ) ) ;
return cb ( 'no_funds' ) ;
} else
return cb ( err ) ;
}
txp . feeStr = txFormatService . formatAmountStr ( wallet . coin , txp . fee ) ;
txFormatService . formatAlternativeStr ( wallet . coin , txp . fee , function ( v ) {
// txp.alternativeFeeStr = v;
// if (txp.alternativeFeeStr.substring(0, 4) == '0.00')
// txp.alternativeFeeStr = '< ' + txp.alternativeFeeStr;
vm . feeFiat = v ;
vm . fiatCurrency = config . wallet . settings . alternativeIsoCode ;
if ( v . substring ( 0 , 1 ) === "<" ) {
vm . feeLessThanACent = true ;
}
console . log ( "fiat" , vm . feeFiat ) ;
} ) ;
var per = ( txp . fee / ( txp . amount + txp . fee ) * 100 ) ;
var perString = per . toFixed ( 2 ) ;
txp . feeRatePerStr = ( perString == '0.00' ? '< ' : '' ) + perString + '%' ;
txp . feeToHigh = per > FEE _TOO _HIGH _LIMIT _PERCENTAGE ;
2018-08-03 10:41:21 +12:00
vm . feeCrypto = ( unitFromSat * txp . fee ) . toFixed ( 8 ) ;
vm . feeIsHigh = txp . feeToHigh ;
2018-08-02 18:30:35 +02:00
console . log ( "crypto" , vm . feeCrypto ) ;
tx . txp [ wallet . id ] = txp ;
$log . debug ( 'Confirm. TX Fully Updated for wallet:' + wallet . id , tx ) ;
2018-08-03 17:56:46 +12:00
vm . readyToSend = true ;
2018-08-02 18:30:35 +02:00
updateSendAmounts ( ) ;
2018-08-03 17:56:46 +12:00
console . log ( 'readyToSend:' , vm . readyToSend ) ;
$scope . $apply ( ) ;
2018-08-02 18:30:35 +02:00
return cb ( ) ;
} ) ;
} ) ;
} ) ;
}
2018-08-01 11:33:24 +12:00
}