2015-03-06 12:00:10 -03:00
'use strict' ;
angular . module ( 'copayApp.services' )
2016-12-16 12:06:30 -03:00
. factory ( 'profileService' , function profileServiceFactory ( $rootScope , $timeout , $filter , $log , sjcl , lodash , storageService , bwcService , configService , pushNotificationsService , gettextCatalog , bwcError , uxLanguage , platformInfo , txFormatService , $state ) {
2016-05-31 14:55:08 -03:00
var isChromeApp = platformInfo . isChromeApp ;
var isCordova = platformInfo . isCordova ;
var isWP = platformInfo . isWP ;
2016-06-17 09:33:31 -03:00
var isIOS = platformInfo . isIOS ;
2015-03-06 12:00:10 -03:00
var root = { } ;
2016-01-22 18:16:50 -03:00
var errors = bwcService . getErrors ( ) ;
2016-05-31 14:55:08 -03:00
var usePushNotifications = isCordova && ! isWP ;
2015-03-06 12:00:10 -03:00
2016-08-22 15:11:58 -03:00
var UPDATE _PERIOD = 15 ;
2015-10-23 12:16:41 -03:00
2015-03-06 12:00:10 -03:00
root . profile = null ;
2016-08-29 11:56:31 -03:00
Object . defineProperty ( root , "focusedClient" , {
get : function ( ) {
throw "focusedClient is not used any more"
} ,
set : function ( ) {
throw "focusedClient is not used any more"
}
2016-08-22 14:42:43 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
2016-08-29 11:56:31 -03:00
root . wallet = { } ; // decorated version of client
2015-03-06 12:00:10 -03:00
2016-08-22 14:42:43 -03:00
root . updateWalletSettings = function ( wallet ) {
2016-08-15 10:25:43 -03:00
var defaults = configService . getDefaults ( ) ;
2016-09-07 15:11:26 -03:00
configService . whenAvailable ( function ( config ) {
2016-09-05 17:36:11 -03:00
wallet . usingCustomBWS = config . bwsFor && config . bwsFor [ wallet . id ] && ( config . bwsFor [ wallet . id ] != defaults . bws . url ) ;
wallet . name = ( config . aliasFor && config . aliasFor [ wallet . id ] ) || wallet . credentials . walletName ;
wallet . color = ( config . colorFor && config . colorFor [ wallet . id ] ) || '#4A90E2' ;
2016-09-02 16:36:18 -03:00
wallet . email = config . emailFor && config . emailFor [ wallet . id ] ;
} ) ;
2016-08-22 14:42:43 -03:00
}
2016-08-15 10:25:43 -03:00
2016-08-30 17:07:49 -03:00
root . setBackupFlag = function ( walletId ) {
storageService . setBackupFlag ( walletId , function ( err ) {
if ( err ) $log . error ( err ) ;
2016-08-31 09:35:47 -03:00
$log . debug ( 'Backup flag stored' ) ;
2016-08-30 17:07:49 -03:00
root . wallet [ walletId ] . needsBackup = false ;
} ) ;
} ;
function _requiresBackup ( wallet ) {
if ( wallet . isPrivKeyExternal ( ) ) return false ;
if ( ! wallet . credentials . mnemonic ) return false ;
if ( wallet . credentials . network == 'testnet' ) return false ;
return true ;
} ;
function _needsBackup ( wallet , cb ) {
if ( ! _requiresBackup ( wallet ) )
return cb ( false ) ;
storageService . getBackupFlag ( wallet . credentials . walletId , function ( err , val ) {
if ( err ) $log . error ( err ) ;
if ( val ) return cb ( false ) ;
return cb ( true ) ;
} ) ;
} ;
2016-08-31 12:03:44 -03:00
function _balanceIsHidden ( wallet , cb ) {
storageService . getHideBalanceFlag ( wallet . credentials . walletId , function ( err , shouldHideBalance ) {
if ( err ) $log . error ( err ) ;
var hideBalance = ( shouldHideBalance == 'true' ) ? true : false ;
return cb ( hideBalance ) ;
} ) ;
} ;
2016-06-06 12:21:15 -03:00
// Adds a wallet client to profileService
2016-08-22 14:42:43 -03:00
root . bindWalletClient = function ( wallet , opts ) {
2016-06-06 12:21:15 -03:00
var opts = opts || { } ;
2016-08-22 14:42:43 -03:00
var walletId = wallet . credentials . walletId ;
2016-08-15 10:25:43 -03:00
2016-09-07 15:11:26 -03:00
if ( ( root . wallet [ walletId ] && root . wallet [ walletId ] . started ) && ! opts . force ) {
2016-06-06 12:21:15 -03:00
return false ;
2015-10-19 11:19:28 -03:00
}
2015-03-06 12:00:10 -03:00
2016-08-31 09:35:47 -03:00
// INIT WALLET VIEWMODEL
wallet . id = walletId ;
wallet . started = true ;
wallet . doNotVerifyPayPro = isChromeApp ;
wallet . network = wallet . credentials . network ;
wallet . copayerId = wallet . credentials . copayerId ;
wallet . m = wallet . credentials . m ;
wallet . n = wallet . credentials . n ;
root . updateWalletSettings ( wallet ) ;
root . wallet [ walletId ] = wallet ;
2016-08-30 17:07:49 -03:00
_needsBackup ( wallet , function ( val ) {
wallet . needsBackup = val ;
} ) ;
2016-08-22 14:42:43 -03:00
2016-08-31 12:03:44 -03:00
_balanceIsHidden ( wallet , function ( val ) {
wallet . balanceHidden = val ;
} ) ;
2016-08-22 14:42:43 -03:00
wallet . removeAllListeners ( ) ;
2016-08-31 09:35:47 -03:00
2016-08-22 14:42:43 -03:00
wallet . on ( 'report' , function ( n ) {
2016-05-20 10:02:44 -03:00
$log . info ( 'BWC Report:' + n ) ;
2016-05-03 10:42:18 -03:00
} ) ;
2015-04-13 14:58:07 -03:00
2016-08-22 14:42:43 -03:00
wallet . on ( 'notification' , function ( n ) {
2016-09-01 17:41:00 -03:00
2016-09-30 11:57:57 -03:00
$log . debug ( 'BWC Notification:' , n ) ;
2016-09-01 17:41:00 -03:00
2016-09-30 11:57:57 -03:00
if ( n . type == "NewBlock" && n . data . network == "testnet" ) {
throttledBwsEvent ( n , wallet ) ;
2016-10-12 18:42:30 -03:00
} else newBwsEvent ( n , wallet ) ;
2015-10-19 11:19:28 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
2016-08-22 14:42:43 -03:00
wallet . on ( 'walletCompleted' , function ( ) {
2015-10-19 11:19:28 -03:00
$log . debug ( 'Wallet completed' ) ;
2016-08-22 14:42:43 -03:00
root . updateCredentials ( JSON . parse ( wallet . export ( ) ) , function ( ) {
2016-06-06 12:21:15 -03:00
$rootScope . $emit ( 'Local/WalletCompleted' , walletId ) ;
2015-03-06 12:00:10 -03:00
} ) ;
2015-10-19 11:19:28 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
2016-08-31 15:16:00 -03:00
wallet . initialize ( {
notificationIncludeOwn : true ,
} , function ( err ) {
2015-10-19 11:19:28 -03:00
if ( err ) {
$log . error ( 'Could not init notifications err:' , err ) ;
return ;
}
2016-08-22 15:11:58 -03:00
wallet . setNotificationsInterval ( UPDATE _PERIOD ) ;
2016-08-23 09:35:32 -03:00
wallet . openWallet ( function ( err ) {
2016-08-29 11:56:31 -03:00
if ( wallet . status !== true )
2016-08-23 09:35:32 -03:00
$log . log ( 'Wallet + ' + walletId + ' status:' + wallet . status )
} ) ;
2016-08-22 14:42:43 -03:00
} ) ;
$rootScope . $on ( 'Local/SettingsUpdated' , function ( e , walletId ) {
if ( ! walletId || walletId == wallet . id ) {
2016-08-29 11:56:31 -03:00
$log . debug ( 'Updating settings for wallet:' + wallet . id ) ;
2016-08-22 14:42:43 -03:00
root . updateWalletSettings ( wallet ) ;
}
2015-10-19 11:19:28 -03:00
} ) ;
2015-04-16 19:44:12 -03:00
2016-06-06 12:21:15 -03:00
return true ;
} ;
2016-09-30 11:57:57 -03:00
var throttledBwsEvent = lodash . throttle ( function ( n , wallet ) {
newBwsEvent ( n , wallet ) ;
} , 10000 ) ;
var newBwsEvent = function ( n , wallet ) {
if ( wallet . cachedStatus )
wallet . cachedStatus . isValid = false ;
if ( wallet . completeHistory )
wallet . completeHistory . isValid = false ;
if ( wallet . cachedActivity )
wallet . cachedActivity . isValid = false ;
if ( wallet . cachedTxps )
wallet . cachedTxps . isValid = false ;
$rootScope . $emit ( 'bwsEvent' , wallet . id , n . type , n ) ;
} ;
2016-06-21 11:17:42 -03:00
var validationLock = false ;
root . runValidation = function ( client , delay , retryDelay ) {
2016-07-28 15:04:09 -03:00
2016-06-21 11:17:42 -03:00
delay = delay || 500 ;
retryDelay = retryDelay || 50 ;
if ( validationLock ) {
return $timeout ( function ( ) {
$log . debug ( 'ValidatingWallet Locked: Retrying in: ' + retryDelay ) ;
return root . runValidation ( client , delay , retryDelay ) ;
} , retryDelay ) ;
}
validationLock = true ;
2016-06-17 09:33:31 -03:00
// IOS devices are already checked
var skipDeviceValidation = isIOS || root . profile . isDeviceChecked ( platformInfo . ua ) ;
2016-06-14 12:28:21 -03:00
var walletId = client . credentials . walletId ;
2016-06-21 11:17:42 -03:00
$log . debug ( 'ValidatingWallet: ' + walletId + ' skip Device:' + skipDeviceValidation ) ;
2016-06-14 12:28:21 -03:00
$timeout ( function ( ) {
client . validateKeyDerivation ( {
skipDeviceValidation : skipDeviceValidation ,
} , function ( err , isOK ) {
2016-06-21 11:17:42 -03:00
validationLock = false ;
2016-06-14 14:05:25 -03:00
$log . debug ( 'ValidatingWallet End: ' + walletId + ' isOK:' + isOK ) ;
2016-06-14 12:28:21 -03:00
if ( isOK ) {
root . profile . setChecked ( platformInfo . ua , walletId ) ;
} else {
$log . warn ( 'Key Derivation failed for wallet:' + walletId ) ;
storageService . clearLastAddress ( walletId , function ( ) { } ) ;
}
2016-07-28 15:04:09 -03:00
2016-06-21 11:17:42 -03:00
root . storeProfileIfDirty ( ) ;
2016-06-14 12:28:21 -03:00
} ) ;
2016-06-21 11:17:42 -03:00
} , delay ) ;
2016-06-14 12:28:21 -03:00
} ;
2016-06-06 12:21:15 -03:00
// Used when reading wallets from the profile
2016-06-13 09:50:37 -03:00
root . bindWallet = function ( credentials , cb ) {
2016-08-15 10:25:43 -03:00
if ( ! credentials . walletId || ! credentials . m )
2016-06-13 09:50:37 -03:00
return cb ( 'bindWallet should receive credentials JSON' ) ;
2016-06-06 12:21:15 -03:00
2016-08-29 11:56:31 -03:00
// Create the client
2016-06-07 12:03:00 -03:00
var getBWSURL = function ( walletId ) {
2016-06-06 12:21:15 -03:00
var config = configService . getSync ( ) ;
var defaults = configService . getDefaults ( ) ;
return ( ( config . bwsFor && config . bwsFor [ walletId ] ) || defaults . bws . url ) ;
} ;
2016-06-14 12:28:21 -03:00
var client = bwcService . getClient ( JSON . stringify ( credentials ) , {
bwsurl : getBWSURL ( credentials . walletId ) ,
} ) ;
2016-06-06 12:21:15 -03:00
var skipKeyValidation = root . profile . isChecked ( platformInfo . ua , credentials . walletId ) ;
2016-06-15 12:15:06 -03:00
if ( ! skipKeyValidation )
2016-06-21 11:17:42 -03:00
root . runValidation ( client , 500 ) ;
2016-06-06 12:21:15 -03:00
2016-06-14 12:28:21 -03:00
$log . info ( 'Binding wallet:' + credentials . walletId + ' Validating?:' + ! skipKeyValidation ) ;
return cb ( null , root . bindWalletClient ( client ) ) ;
2015-03-06 12:00:10 -03:00
} ;
root . bindProfile = function ( profile , cb ) {
root . profile = profile ;
2016-01-04 08:55:28 -03:00
2015-03-06 12:00:10 -03:00
configService . get ( function ( err ) {
2015-04-25 12:37:04 -03:00
$log . debug ( 'Preferences read' ) ;
2015-03-06 12:00:10 -03:00
if ( err ) return cb ( err ) ;
2016-06-06 12:21:15 -03:00
2016-06-13 09:50:37 -03:00
function bindWallets ( cb ) {
var l = root . profile . credentials . length ;
2016-06-15 12:15:06 -03:00
var i = 0 ,
totalBound = 0 ;
2016-06-13 09:50:37 -03:00
2016-06-13 10:39:28 -03:00
if ( ! l ) return cb ( ) ;
2016-06-13 09:50:37 -03:00
lodash . each ( root . profile . credentials , function ( credentials ) {
root . bindWallet ( credentials , function ( err , bound ) {
i ++ ;
totalBound += bound ;
if ( i == l ) {
$log . info ( 'Bound ' + totalBound + ' out of ' + l + ' wallets' ) ;
return cb ( ) ;
2016-05-29 21:20:40 -03:00
}
2016-06-13 09:50:37 -03:00
} ) ;
} ) ;
}
bindWallets ( function ( ) {
2016-08-22 14:42:43 -03:00
root . isBound = true ;
2016-08-22 15:11:58 -03:00
lodash . each ( root . _queue , function ( x ) {
$timeout ( function ( ) {
return x ( ) ;
} , 1 ) ;
} ) ;
root . _queue = [ ] ;
2016-08-22 14:42:43 -03:00
root . isDisclaimerAccepted ( function ( val ) {
if ( ! val ) {
return cb ( new Error ( 'NONAGREEDDISCLAIMER: Non agreed disclaimer' ) ) ;
}
2016-10-08 20:19:55 -03:00
var config = configService . getSync ( ) ;
if ( config . pushNotifications . enabled && usePushNotifications )
2016-10-06 12:14:44 -03:00
root . pushNotificationsInit ( ) ;
2016-08-22 14:42:43 -03:00
return cb ( ) ;
} ) ;
2015-03-06 12:00:10 -03:00
} ) ;
} ) ;
2016-03-10 10:58:58 -03:00
} ;
2016-08-22 15:11:58 -03:00
root . _queue = [ ] ;
root . whenAvailable = function ( cb ) {
if ( ! root . isBound ) {
root . _queue . push ( cb ) ;
return ;
}
return cb ( ) ;
} ;
2016-03-10 10:58:58 -03:00
root . pushNotificationsInit = function ( ) {
var defaults = configService . getDefaults ( ) ;
2016-08-15 10:25:43 -03:00
var push = pushNotificationsService . init ( root . wallet ) ;
2016-01-04 08:55:28 -03:00
2016-10-10 13:45:43 -03:00
if ( ! push ) return ;
2016-03-10 10:58:58 -03:00
push . on ( 'notification' , function ( data ) {
if ( ! data . additionalData . foreground ) {
$log . debug ( 'Push notification event: ' , data . message ) ;
$timeout ( function ( ) {
var wallets = root . getWallets ( ) ;
var walletToFind = data . additionalData . walletId ;
2016-01-04 08:55:28 -03:00
2016-03-10 10:58:58 -03:00
var walletFound = lodash . find ( wallets , function ( w ) {
2016-04-07 12:58:32 -03:00
return ( lodash . isEqual ( walletToFind , sjcl . codec . hex . fromBits ( sjcl . hash . sha256 . hash ( w . id ) ) ) ) ;
2016-03-10 10:58:58 -03:00
} ) ;
if ( ! walletFound ) return $log . debug ( 'Wallet not found' ) ;
} , 100 ) ;
}
} ) ;
2016-10-06 12:17:32 -03:00
push . on ( 'error' , function ( e ) {
2016-10-07 14:57:36 -03:00
$log . warn ( 'Error with push notifications:' + e . message ) ;
2016-10-06 12:17:32 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-01-04 08:55:28 -03:00
root . loadAndBindProfile = function ( cb ) {
2015-11-30 12:58:52 -03:00
storageService . getProfile ( function ( err , profile ) {
if ( err ) {
$rootScope . $emit ( 'Local/DeviceError' , err ) ;
return cb ( err ) ;
}
if ( ! profile ) {
// Migration??
storageService . tryToMigrate ( function ( err , migratedProfile ) {
if ( err ) return cb ( err ) ;
if ( ! migratedProfile )
return cb ( new Error ( 'NOPROFILE: No profile' ) ) ;
profile = migratedProfile ;
return root . bindProfile ( profile , cb ) ;
} )
2015-04-25 14:42:17 -03:00
} else {
2015-12-04 18:45:35 -03:00
$log . debug ( 'Profile read' ) ;
return root . bindProfile ( profile , cb ) ;
}
} ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-06-07 10:39:53 -03:00
var seedWallet = function ( opts , cb ) {
2015-09-02 15:56:00 -03:00
opts = opts || { } ;
2016-06-01 15:49:20 -03:00
var walletClient = bwcService . getClient ( null , opts ) ;
2015-09-02 15:56:00 -03:00
var network = opts . networkName || 'livenet' ;
2015-08-27 12:07:13 -03:00
2015-09-02 15:56:00 -03:00
if ( opts . mnemonic ) {
try {
2015-09-15 12:07:34 -03:00
opts . mnemonic = root . _normalizeMnemonic ( opts . mnemonic ) ;
2015-10-22 15:44:28 -03:00
walletClient . seedFromMnemonic ( opts . mnemonic , {
network : network ,
passphrase : opts . passphrase ,
2015-11-04 01:54:54 -03:00
account : opts . account || 0 ,
2015-11-10 20:05:05 -03:00
derivationStrategy : opts . derivationStrategy || 'BIP44' ,
2015-10-22 15:44:28 -03:00
} ) ;
2015-11-04 17:50:05 -03:00
2015-09-02 15:56:00 -03:00
} catch ( ex ) {
$log . info ( ex ) ;
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Could not create: Invalid wallet recovery phrase' ) ) ;
2015-09-02 15:56:00 -03:00
}
2015-09-05 00:11:14 -03:00
} else if ( opts . extendedPrivateKey ) {
try {
walletClient . seedFromExtendedPrivateKey ( opts . extendedPrivateKey ) ;
} catch ( ex ) {
$log . warn ( ex ) ;
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Could not create using the specified extended private key' ) ) ;
2015-09-05 00:11:14 -03:00
}
2015-09-02 15:56:00 -03:00
} else if ( opts . extendedPublicKey ) {
try {
2015-10-22 15:44:28 -03:00
walletClient . seedFromExtendedPublicKey ( opts . extendedPublicKey , opts . externalSource , opts . entropySource , {
2015-11-05 16:00:38 -03:00
account : opts . account || 0 ,
2015-11-10 20:05:05 -03:00
derivationStrategy : opts . derivationStrategy || 'BIP44' ,
2015-10-22 15:44:28 -03:00
} ) ;
2015-09-02 15:56:00 -03:00
} catch ( ex ) {
2015-09-14 09:46:45 -03:00
$log . warn ( "Creating wallet from Extended Public Key Arg:" , ex , opts ) ;
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Could not create using the specified extended public key' ) ) ;
2015-09-02 15:56:00 -03:00
}
} else {
var lang = uxLanguage . getCurrentLanguage ( ) ;
try {
2015-10-22 15:44:28 -03:00
walletClient . seedFromRandomWithMnemonic ( {
network : network ,
passphrase : opts . passphrase ,
language : lang ,
account : 0 ,
} ) ;
2015-09-02 15:56:00 -03:00
} catch ( e ) {
2016-05-09 20:23:20 +02:00
$log . info ( 'Error creating recovery phrase: ' + e . message ) ;
2015-09-02 15:56:00 -03:00
if ( e . message . indexOf ( 'language' ) > 0 ) {
2016-05-09 20:23:20 +02:00
$log . info ( 'Using default language for recovery phrase' ) ;
2015-10-22 15:44:28 -03:00
walletClient . seedFromRandomWithMnemonic ( {
network : network ,
passphrase : opts . passphrase ,
account : 0 ,
} ) ;
2015-09-02 15:56:00 -03:00
} else {
return cb ( e ) ;
}
2015-08-27 12:07:13 -03:00
}
}
2015-09-02 15:56:00 -03:00
return cb ( null , walletClient ) ;
2015-08-27 11:24:39 -03:00
} ;
2016-06-06 12:21:15 -03:00
// Creates a wallet on BWC/BWS
2016-06-07 10:39:53 -03:00
var doCreateWallet = function ( opts , cb ) {
2016-06-06 12:21:15 -03:00
$log . debug ( 'Creating Wallet:' , opts ) ;
2016-06-13 10:39:28 -03:00
$timeout ( function ( ) {
seedWallet ( opts , function ( err , walletClient ) {
if ( err ) return cb ( err ) ;
2015-08-08 09:30:50 -03:00
2016-06-13 10:39:28 -03:00
var name = opts . name || gettextCatalog . getString ( 'Personal Wallet' ) ;
var myName = opts . myName || gettextCatalog . getString ( 'me' ) ;
2016-06-05 16:27:49 -03:00
2016-06-13 10:39:28 -03:00
walletClient . createWallet ( name , myName , opts . m , opts . n , {
network : opts . networkName ,
singleAddress : opts . singleAddress ,
walletPrivKey : opts . walletPrivKey ,
} , function ( err , secret ) {
2016-12-16 12:06:30 -03:00
if ( err ) return bwcError . cb ( err , gettextCatalog . getString ( 'Error creating wallet' ) , cb ) ;
2016-06-13 10:39:28 -03:00
return cb ( null , walletClient , secret ) ;
} ) ;
2015-03-06 12:00:10 -03:00
} ) ;
2016-06-13 11:44:58 -03:00
} , 50 ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-06-06 12:21:15 -03:00
// create and store a wallet
root . createWallet = function ( opts , cb ) {
2016-06-07 10:39:53 -03:00
doCreateWallet ( opts , function ( err , walletClient , secret ) {
2016-06-07 12:34:16 -03:00
if ( err ) return cb ( err ) ;
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-06 12:21:15 -03:00
bwsurl : opts . bwsurl
} , cb ) ;
2015-09-02 15:56:00 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-06-06 12:21:15 -03:00
// joins and stores a wallet
2015-10-19 17:58:12 -03:00
root . joinWallet = function ( opts , cb ) {
2015-03-06 12:00:10 -03:00
var walletClient = bwcService . getClient ( ) ;
$log . debug ( 'Joining Wallet:' , opts ) ;
2015-08-12 11:08:33 -03:00
try {
2015-11-11 10:53:51 -03:00
var walletData = bwcService . parseSecret ( opts . secret ) ;
2015-08-12 11:08:33 -03:00
2015-08-12 11:16:34 -03:00
// check if exist
if ( lodash . find ( root . profile . credentials , {
2016-09-01 16:48:46 -03:00
'walletId' : walletData . walletId
} ) ) {
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Cannot join the same wallet more that once' ) ) ;
2015-08-12 11:16:34 -03:00
}
2015-08-12 11:08:33 -03:00
} catch ( ex ) {
2015-09-29 12:45:06 -03:00
$log . debug ( ex ) ;
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Bad wallet invitation' ) ) ;
2015-08-12 11:08:33 -03:00
}
2015-09-02 15:56:00 -03:00
opts . networkName = walletData . network ;
$log . debug ( 'Joining Wallet:' , opts ) ;
2016-06-07 10:39:53 -03:00
seedWallet ( opts , function ( err , walletClient ) {
2015-09-02 15:56:00 -03:00
if ( err ) return cb ( err ) ;
2015-08-12 11:08:33 -03:00
2015-09-28 10:26:57 -03:00
walletClient . joinWallet ( opts . secret , opts . myName || 'me' , { } , function ( err ) {
2016-12-16 12:06:30 -03:00
if ( err ) return bwcError . cb ( err , gettextCatalog . getString ( 'Could not join wallet' ) , cb ) ;
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-06 12:21:15 -03:00
bwsurl : opts . bwsurl
} , cb ) ;
2015-10-19 17:26:15 -03:00
} ) ;
} ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-08-15 10:25:43 -03:00
root . getWallet = function ( walletId ) {
return root . wallet [ walletId ] ;
2015-06-27 13:22:56 -03:00
} ;
2016-08-15 10:25:43 -03:00
2016-06-06 12:21:15 -03:00
root . deleteWalletClient = function ( client , cb ) {
var walletId = client . credentials . walletId ;
2016-01-15 11:59:29 -03:00
2017-01-02 10:40:17 +01:00
var config = configService . getSync ( ) ;
if ( config . pushNotifications . enabled )
pushNotificationsService . unsubscribe ( root . getWallet ( walletId ) , function ( err ) {
if ( err ) $log . warn ( 'Unsubscription error: ' + err . message ) ;
else $log . debug ( 'Unsubscribed from push notifications service' ) ;
} ) ;
2015-03-06 12:00:10 -03:00
2016-06-06 19:09:57 -03:00
$log . debug ( 'Deleting Wallet:' , client . credentials . walletName ) ;
client . removeAllListeners ( ) ;
2016-06-06 12:21:15 -03:00
root . profile . deleteWallet ( walletId ) ;
2015-03-06 12:00:10 -03:00
2016-08-15 10:25:43 -03:00
delete root . wallet [ walletId ] ;
2015-11-06 16:54:25 -03:00
2016-06-06 12:21:15 -03:00
storageService . removeAllWalletData ( walletId , function ( err ) {
2016-05-29 21:20:40 -03:00
if ( err ) $log . warn ( err ) ;
} ) ;
2015-11-06 16:54:25 -03:00
2016-08-22 15:11:58 -03:00
storageService . storeProfile ( root . profile , function ( err ) {
if ( err ) return cb ( err ) ;
return cb ( ) ;
2015-03-06 12:00:10 -03:00
} ) ;
} ;
2016-06-17 11:46:40 -03:00
root . setMetaData = function ( walletClient , addressBook , cb ) {
2015-11-09 10:58:10 -03:00
storageService . getAddressbook ( walletClient . credentials . network , function ( err , localAddressBook ) {
2015-11-11 10:37:07 -03:00
var localAddressBook1 = { } ;
try {
localAddressBook1 = JSON . parse ( localAddressBook ) ;
} catch ( ex ) {
$log . warn ( ex ) ;
}
var mergeAddressBook = lodash . merge ( addressBook , localAddressBook1 ) ;
2015-11-09 10:58:10 -03:00
storageService . setAddressbook ( walletClient . credentials . network , JSON . stringify ( addressBook ) , function ( err ) {
2015-11-05 17:48:56 -03:00
if ( err ) return cb ( err ) ;
2016-06-17 11:46:40 -03:00
return cb ( null ) ;
2015-11-05 17:48:56 -03:00
} ) ;
} ) ;
}
2016-06-06 18:26:45 -03:00
// Adds and bind a new client to the profile
2016-08-15 16:07:30 -03:00
var addAndBindWalletClient = function ( client , opts , cb ) {
2016-06-07 12:34:16 -03:00
if ( ! client || ! client . credentials )
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Could not access wallet' ) ) ;
2016-06-07 12:34:16 -03:00
2016-06-06 12:21:15 -03:00
var walletId = client . credentials . walletId
2015-03-06 12:00:10 -03:00
2016-06-06 12:21:15 -03:00
if ( ! root . profile . addWallet ( JSON . parse ( client . export ( ) ) ) )
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Wallet already in Copay' ) ) ;
2015-10-25 23:25:44 -03:00
2016-06-14 14:05:25 -03:00
var skipKeyValidation = root . profile . isChecked ( platformInfo . ua , walletId ) ;
2016-06-15 12:15:06 -03:00
if ( ! skipKeyValidation )
2016-06-14 14:05:25 -03:00
root . runValidation ( client ) ;
2016-06-06 12:21:15 -03:00
root . bindWalletClient ( client ) ;
2015-10-25 23:25:44 -03:00
2016-06-06 12:21:15 -03:00
var saveBwsUrl = function ( cb ) {
var defaults = configService . getDefaults ( ) ;
var bwsFor = { } ;
bwsFor [ walletId ] = opts . bwsurl || defaults . bws . url ;
2015-11-14 17:29:45 -03:00
2016-06-06 18:26:45 -03:00
// Dont save the default
if ( bwsFor [ walletId ] == defaults . bws . url )
return cb ( ) ;
2016-06-06 12:21:15 -03:00
configService . set ( {
bwsFor : bwsFor ,
} , function ( err ) {
if ( err ) $log . warn ( err ) ;
return cb ( ) ;
} ) ;
} ;
2015-11-14 17:29:45 -03:00
2016-06-06 12:21:15 -03:00
saveBwsUrl ( function ( ) {
2016-08-22 14:42:43 -03:00
storageService . storeProfile ( root . profile , function ( err ) {
var config = configService . getSync ( ) ;
if ( config . pushNotifications . enabled )
pushNotificationsService . enableNotifications ( root . wallet ) ;
return cb ( err , client ) ;
2015-10-25 23:25:44 -03:00
} ) ;
2015-10-25 23:06:29 -03:00
} ) ;
2015-03-06 12:00:10 -03:00
} ;
2016-06-06 18:26:45 -03:00
root . storeProfileIfDirty = function ( cb ) {
if ( root . profile . dirty ) {
storageService . storeProfile ( root . profile , function ( err ) {
$log . debug ( 'Saved modified Profile' ) ;
if ( cb ) return cb ( err ) ;
} ) ;
} else {
if ( cb ) return cb ( ) ;
} ;
} ;
2015-08-24 17:09:59 -03:00
root . importWallet = function ( str , opts , cb ) {
2015-11-06 16:04:35 -03:00
2016-06-01 15:49:20 -03:00
var walletClient = bwcService . getClient ( null , opts ) ;
2015-10-19 17:26:15 -03:00
2015-08-24 17:09:59 -03:00
$log . debug ( 'Importing Wallet:' , opts ) ;
2016-10-12 18:42:30 -03:00
2015-08-24 17:09:59 -03:00
try {
2016-10-19 13:36:22 -03:00
var c = JSON . parse ( str ) ;
if ( c . xPrivKey && c . xPrivKeyEncrypted ) {
$log . warn ( 'Found both encrypted and decrypted key. Deleting the encrypted version' ) ;
delete c . xPrivKeyEncrypted ;
delete c . mnemonicEncrypted ;
}
str = JSON . stringify ( c ) ;
2015-08-24 17:09:59 -03:00
walletClient . import ( str , {
compressed : opts . compressed ,
password : opts . password
} ) ;
} catch ( err ) {
2016-12-16 12:06:30 -03:00
return cb ( gettextCatalog . getString ( 'Could not import. Check input file and spending password' ) ) ;
2015-08-24 17:09:59 -03:00
}
2015-11-06 17:45:23 -03:00
str = JSON . parse ( str ) ;
2016-09-03 22:25:51 -03:00
if ( ! str . n ) {
return cb ( "Backup format not recognized. If you are using a Copay Beta backup and version is older than 0.10, please see: https://github.com/bitpay/copay/issues/4730#issuecomment-244522614" ) ;
}
2015-11-09 10:58:10 -03:00
var addressBook = str . addressBook || { } ;
2015-11-06 16:04:35 -03:00
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-15 12:15:06 -03:00
bwsurl : opts . bwsurl
2016-06-06 12:21:15 -03:00
} , function ( err , walletId ) {
2015-11-11 11:25:03 -03:00
if ( err ) return cb ( err ) ;
2016-06-17 11:46:40 -03:00
root . setMetaData ( walletClient , addressBook , function ( error ) {
2016-02-22 19:32:24 -03:00
if ( error ) $log . warn ( error ) ;
2016-08-15 16:07:30 -03:00
return cb ( err , walletClient ) ;
2015-11-11 11:25:03 -03:00
} ) ;
2015-11-06 11:26:50 -03:00
} ) ;
2015-08-24 17:09:59 -03:00
} ;
2015-10-20 12:03:08 -03:00
root . importExtendedPrivateKey = function ( xPrivKey , opts , cb ) {
2016-06-01 16:44:07 -03:00
var walletClient = bwcService . getClient ( null , opts ) ;
2015-09-05 00:11:14 -03:00
$log . debug ( 'Importing Wallet xPrivKey' ) ;
2016-05-09 12:03:25 -03:00
walletClient . importFromExtendedPrivateKey ( xPrivKey , opts , function ( err ) {
2016-06-07 17:11:57 -03:00
if ( err ) {
if ( err instanceof errors . NOT _AUTHORIZED )
return cb ( err ) ;
2016-12-16 12:06:30 -03:00
return bwcError . cb ( err , gettextCatalog . getString ( 'Could not import' ) , cb ) ;
2016-06-07 17:11:57 -03:00
}
2015-09-05 00:11:14 -03:00
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-15 12:15:06 -03:00
bwsurl : opts . bwsurl
2016-06-06 12:21:15 -03:00
} , cb ) ;
2015-09-05 00:11:14 -03:00
} ) ;
} ;
2015-09-15 12:07:34 -03:00
root . _normalizeMnemonic = function ( words ) {
2016-12-28 16:49:42 -03:00
if ( ! words || ! words . indexOf ) return words ;
2015-10-19 11:19:28 -03:00
var isJA = words . indexOf ( '\u3000' ) > - 1 ;
2015-09-15 12:07:34 -03:00
var wordList = words . split ( /[\u3000\s]+/ ) ;
return wordList . join ( isJA ? '\u3000' : ' ' ) ;
2015-09-05 01:02:01 -03:00
} ;
2015-09-05 00:11:14 -03:00
root . importMnemonic = function ( words , opts , cb ) {
2016-06-01 16:44:07 -03:00
var walletClient = bwcService . getClient ( null , opts ) ;
2015-09-05 01:02:01 -03:00
2015-08-24 17:09:59 -03:00
$log . debug ( 'Importing Wallet Mnemonic' ) ;
2015-09-15 12:07:34 -03:00
words = root . _normalizeMnemonic ( words ) ;
2015-08-24 17:09:59 -03:00
walletClient . importFromMnemonic ( words , {
2015-09-02 15:56:00 -03:00
network : opts . networkName ,
2015-08-24 17:09:59 -03:00
passphrase : opts . passphrase ,
2015-11-04 17:50:05 -03:00
account : opts . account || 0 ,
2015-08-24 17:09:59 -03:00
} , function ( err ) {
2016-06-07 17:11:57 -03:00
if ( err ) {
if ( err instanceof errors . NOT _AUTHORIZED )
return cb ( err ) ;
2016-12-16 12:06:30 -03:00
return bwcError . cb ( err , gettextCatalog . getString ( 'Could not import' ) , cb ) ;
2016-06-07 17:11:57 -03:00
}
2015-08-24 17:09:59 -03:00
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-15 12:15:06 -03:00
bwsurl : opts . bwsurl
2016-06-06 12:21:15 -03:00
} , cb ) ;
2015-08-24 17:09:59 -03:00
} ) ;
} ;
2015-09-04 21:18:20 -03:00
root . importExtendedPublicKey = function ( opts , cb ) {
2016-06-01 16:44:07 -03:00
var walletClient = bwcService . getClient ( null , opts ) ;
2015-09-04 21:18:20 -03:00
$log . debug ( 'Importing Wallet XPubKey' ) ;
2015-10-22 15:44:28 -03:00
walletClient . importFromExtendedPublicKey ( opts . extendedPublicKey , opts . externalSource , opts . entropySource , {
2015-11-04 01:54:54 -03:00
account : opts . account || 0 ,
2015-11-10 20:05:05 -03:00
derivationStrategy : opts . derivationStrategy || 'BIP44' ,
2015-10-22 15:44:28 -03:00
} , function ( err ) {
2015-09-04 21:18:20 -03:00
if ( err ) {
// in HW wallets, req key is always the same. They can't addAccess.
2016-01-22 18:16:50 -03:00
if ( err instanceof errors . NOT _AUTHORIZED )
err . name = 'WALLET_DOES_NOT_EXIST' ;
2015-09-04 21:18:20 -03:00
2016-12-16 12:06:30 -03:00
return bwcError . cb ( err , gettextCatalog . getString ( 'Could not import' ) , cb ) ;
2015-09-04 21:18:20 -03:00
}
2016-08-15 16:07:30 -03:00
addAndBindWalletClient ( walletClient , {
2016-06-15 12:15:06 -03:00
bwsurl : opts . bwsurl
2016-06-06 12:21:15 -03:00
} , cb ) ;
2015-09-04 21:18:20 -03:00
} ) ;
} ;
2016-08-30 15:38:48 -03:00
root . createProfile = function ( cb ) {
$log . info ( 'Creating profile' ) ;
2015-10-20 12:18:44 -03:00
var defaults = configService . getDefaults ( ) ;
2015-04-25 14:42:17 -03:00
configService . get ( function ( err ) {
2016-08-30 15:38:48 -03:00
if ( err ) $log . debug ( err ) ;
2015-04-25 14:42:17 -03:00
2016-08-30 15:38:48 -03:00
var p = Profile . create ( ) ;
storageService . storeNewProfile ( p , function ( err ) {
if ( err ) return cb ( err ) ;
root . bindProfile ( p , function ( err ) {
// ignore NONAGREEDDISCLAIMER
if ( err && err . toString ( ) . match ( 'NONAGREEDDISCLAIMER' ) ) return cb ( ) ;
return cb ( err ) ;
2015-03-06 12:00:10 -03:00
} ) ;
} ) ;
} ) ;
} ;
2016-08-30 15:38:48 -03:00
root . createDefaultWallet = function ( cb ) {
var opts = { } ;
opts . m = 1 ;
opts . n = 1 ;
2016-12-23 15:57:59 +01:00
opts . networkName = 'livenet' ;
2016-08-30 15:38:48 -03:00
root . createWallet ( opts , cb ) ;
} ;
2015-12-07 12:52:42 -03:00
root . setDisclaimerAccepted = function ( cb ) {
2016-02-22 19:32:24 -03:00
root . profile . disclaimerAccepted = true ;
2016-06-14 17:48:00 -03:00
storageService . storeProfile ( root . profile , function ( err ) {
2016-02-22 19:32:24 -03:00
return cb ( err ) ;
2015-11-30 13:32:54 -03:00
} ) ;
2015-12-04 18:45:35 -03:00
} ;
2015-12-07 12:52:42 -03:00
root . isDisclaimerAccepted = function ( cb ) {
2016-02-22 19:32:24 -03:00
var disclaimerAccepted = root . profile && root . profile . disclaimerAccepted ;
if ( disclaimerAccepted )
return cb ( true ) ;
// OLD flag
storageService . getCopayDisclaimerFlag ( function ( err , val ) {
if ( val ) {
root . profile . disclaimerAccepted = true ;
2015-12-04 18:45:35 -03:00
return cb ( true ) ;
2016-01-04 08:55:28 -03:00
} else {
2015-12-04 18:45:35 -03:00
return cb ( ) ;
}
2016-01-04 08:55:28 -03:00
} ) ;
2015-12-04 18:45:35 -03:00
} ;
2015-11-30 13:32:54 -03:00
2016-06-06 18:26:45 -03:00
root . updateCredentials = function ( credentials , cb ) {
2016-06-14 17:59:23 -03:00
root . profile . updateWallet ( credentials ) ;
2016-06-14 17:48:00 -03:00
storageService . storeProfile ( root . profile , cb ) ;
2015-03-06 12:00:10 -03:00
} ;
2017-01-31 14:24:13 -03:00
root . getLastKnownBalance = function ( wid , cb ) {
storageService . getBalanceCache ( wid , cb ) ;
} ;
root . addLastKnownBalance = function ( wallet , cb ) {
var now = Math . floor ( Date . now ( ) / 1000 ) ;
var showRange = 600 ; // 10min;
root . getLastKnownBalance ( wallet . id , function ( err , data ) {
if ( data ) {
data = JSON . parse ( data ) ;
wallet . cachedBalance = data . balance ;
wallet . cachedBalanceUpdatedOn = ( data . updatedOn < now - showRange ) ? data . updatedOn : null ;
}
return cb ( ) ;
} ) ;
} ;
root . setLastKnownBalance = function ( wid , balance , cb ) {
storageService . setBalanceCache ( wid , {
balance : balance ,
updatedOn : Math . floor ( Date . now ( ) / 1000 ) ,
} , cb ) ;
} ;
2016-08-15 11:56:59 -03:00
root . getWallets = function ( opts ) {
if ( opts && ! lodash . isObject ( opts ) )
throw "bad argument" ;
opts = opts || { } ;
2016-08-15 10:25:43 -03:00
var ret = lodash . values ( root . wallet ) ;
2016-08-15 11:56:59 -03:00
if ( opts . network ) {
2016-08-15 10:25:43 -03:00
ret = lodash . filter ( ret , function ( x ) {
2016-08-15 11:56:59 -03:00
return ( x . credentials . network == opts . network ) ;
} ) ;
}
if ( opts . n ) {
ret = lodash . filter ( ret , function ( w ) {
return ( w . credentials . n == opts . n ) ;
2016-08-15 10:25:43 -03:00
} ) ;
}
2016-12-12 09:58:17 -03:00
if ( opts . m ) {
ret = lodash . filter ( ret , function ( w ) {
return ( w . credentials . m == opts . m ) ;
} ) ;
}
2016-08-15 11:56:59 -03:00
if ( opts . onlyComplete ) {
2016-08-15 10:25:43 -03:00
ret = lodash . filter ( ret , function ( w ) {
2016-08-15 11:56:59 -03:00
return w . isComplete ( ) ;
2016-08-15 10:25:43 -03:00
} ) ;
2016-08-29 11:56:31 -03:00
} else { }
2016-08-15 10:25:43 -03:00
2017-01-31 14:24:13 -03:00
// Add cached balance async
lodash . each ( ret , function ( x ) {
root . addLastKnownBalance ( x , function ( ) { } ) ;
} ) ;
2016-08-31 17:12:36 -03:00
return lodash . sortBy ( ret , [
2016-08-31 18:12:28 -03:00
2016-08-31 17:12:36 -03:00
function ( x ) {
return x . isComplete ( ) ;
} , 'createdOn'
] ) ;
2016-06-06 18:26:45 -03:00
} ;
2015-03-06 12:00:10 -03:00
2016-08-31 12:18:04 -03:00
root . toggleHideBalanceFlag = function ( walletId , cb ) {
2016-08-31 11:49:28 -03:00
root . wallet [ walletId ] . balanceHidden = ! root . wallet [ walletId ] . balanceHidden ;
2016-08-31 12:03:44 -03:00
storageService . setHideBalanceFlag ( walletId , root . wallet [ walletId ] . balanceHidden . toString ( ) , cb ) ;
2016-08-31 17:12:36 -03:00
} ;
2016-08-31 18:12:28 -03:00
root . getNotifications = function ( opts , cb ) {
opts = opts || { } ;
2016-08-31 17:12:36 -03:00
2017-01-31 14:24:13 -03:00
var TIME _STAMP = 60 * 60 * 6 ;
2017-01-18 11:00:51 -03:00
var MAX = 30 ;
2016-08-31 17:12:36 -03:00
2016-09-27 15:57:39 -03:00
var typeFilter = {
'NewOutgoingTx' : 1 ,
'NewIncomingTx' : 1
2016-08-31 17:12:36 -03:00
} ;
var w = root . getWallets ( ) ;
if ( lodash . isEmpty ( w ) ) return cb ( ) ;
var l = w . length ,
j = 0 ,
notifications = [ ] ;
2016-08-31 18:12:28 -03:00
function isActivityCached ( wallet ) {
return wallet . cachedActivity && wallet . cachedActivity . isValid ;
} ;
2016-09-01 17:41:00 -03:00
function updateNotifications ( wallet , cb2 ) {
2016-08-31 18:12:28 -03:00
if ( isActivityCached ( wallet ) && ! opts . force ) return cb2 ( ) ;
wallet . getNotifications ( {
timeSpan : TIME _STAMP ,
includeOwn : true ,
} , function ( err , n ) {
if ( err ) return cb2 ( err ) ;
wallet . cachedActivity = {
n : n . slice ( - MAX ) ,
isValid : true ,
} ;
return cb2 ( ) ;
} ) ;
} ;
function process ( notifications ) {
if ( ! notifications ) return [ ] ;
var shown = lodash . sortBy ( notifications , 'createdOn' ) . reverse ( ) ;
shown = shown . splice ( 0 , opts . limit || MAX ) ;
lodash . each ( shown , function ( x ) {
x . txpId = x . data ? x . data . txProposalId : null ;
x . txid = x . data ? x . data . txid : null ;
x . types = [ x . type ] ;
if ( x . data && x . data . amount )
x . amountStr = txFormatService . formatAmountStr ( x . data . amount ) ;
x . action = function ( ) {
// TODO?
2016-09-28 11:08:08 -03:00
// $state.go('tabs.wallet', {
2016-09-20 12:02:45 -03:00
// walletId: x.walletId,
// txpId: x.txpId,
// txid: x.txid,
// });
2016-08-31 18:12:28 -03:00
} ;
} ) ;
2016-09-01 16:50:13 -03:00
var finale = shown ; // GROUPING DISABLED!
2016-11-10 13:47:57 -03:00
var finale = [ ] ,
2016-11-17 16:07:06 -03:00
prev ;
2016-11-10 13:47:57 -03:00
// Item grouping... DISABLED.
// REMOVE (if we want 1-to-1 notification) ????
lodash . each ( shown , function ( x ) {
if ( prev && prev . walletId === x . walletId && prev . txpId && prev . txpId === x . txpId && prev . creatorId && prev . creatorId === x . creatorId ) {
prev . types . push ( x . type ) ;
prev . data = lodash . assign ( prev . data , x . data ) ;
prev . txid = prev . txid || x . txid ;
prev . amountStr = prev . amountStr || x . amountStr ;
prev . creatorName = prev . creatorName || x . creatorName ;
} else {
finale . push ( x ) ;
prev = x ;
}
} ) ;
2016-08-31 18:12:28 -03:00
var u = bwcService . getUtils ( ) ;
lodash . each ( finale , function ( x ) {
if ( x . data && x . data . message && x . wallet && x . wallet . credentials . sharedEncryptingKey ) {
// TODO TODO TODO => BWC
x . message = u . decryptMessage ( x . data . message , x . wallet . credentials . sharedEncryptingKey ) ;
}
} ) ;
return finale ;
} ;
2016-08-31 17:12:36 -03:00
lodash . each ( w , function ( wallet ) {
2016-09-01 17:41:00 -03:00
updateNotifications ( wallet , function ( err ) {
2016-08-31 17:12:36 -03:00
j ++ ;
if ( err ) {
2016-08-31 18:12:28 -03:00
$log . warn ( 'Error updating notifications:' + err ) ;
} else {
2016-09-14 11:08:47 -03:00
var n ;
n = lodash . filter ( wallet . cachedActivity . n , function ( x ) {
2016-09-27 15:57:39 -03:00
return typeFilter [ x . type ] ;
2016-08-31 18:12:28 -03:00
} ) ;
2016-08-31 17:12:36 -03:00
2016-08-31 18:12:28 -03:00
var idToName = { } ;
if ( wallet . cachedStatus ) {
lodash . each ( wallet . cachedStatus . wallet . copayers , function ( c ) {
idToName [ c . id ] = c . name ;
} ) ;
}
2016-08-31 17:12:36 -03:00
2016-08-31 18:12:28 -03:00
lodash . each ( n , function ( x ) {
x . wallet = wallet ;
if ( x . creatorId && wallet . cachedStatus ) {
x . creatorName = idToName [ x . creatorId ] ;
} ;
2016-08-31 17:12:36 -03:00
} ) ;
2016-08-31 18:12:28 -03:00
notifications . push ( n ) ;
}
if ( j == l ) {
notifications = lodash . sortBy ( notifications , 'createdOn' ) ;
2016-09-01 16:48:46 -03:00
notifications = lodash . compact ( lodash . flatten ( notifications ) ) . slice ( 0 , MAX ) ;
2017-01-18 11:00:51 -03:00
var total = notifications . length ;
return cb ( null , process ( notifications ) , total ) ;
2016-08-31 17:12:36 -03:00
} ;
} ) ;
} ) ;
} ;
2016-08-31 11:49:28 -03:00
2016-09-01 17:41:00 -03:00
root . getTxps = function ( opts , cb ) {
2016-09-01 19:14:18 -03:00
var MAX = 100 ;
2016-09-01 17:41:00 -03:00
opts = opts || { } ;
var w = root . getWallets ( ) ;
if ( lodash . isEmpty ( w ) ) return cb ( ) ;
var txps = [ ] ;
lodash . each ( w , function ( x ) {
if ( x . pendingTxps )
txps = txps . concat ( x . pendingTxps ) ;
} ) ;
2016-09-01 19:14:18 -03:00
var n = txps . length ;
2016-09-29 19:04:52 -03:00
txps = lodash . sortBy ( txps , 'pendingForUs' , 'createdOn' ) ;
txps = lodash . compact ( lodash . flatten ( txps ) ) . slice ( 0 , opts . limit || MAX ) ;
2016-09-02 14:33:18 -03:00
return cb ( null , txps , n ) ;
2016-09-01 17:41:00 -03:00
} ;
2015-03-06 12:00:10 -03:00
return root ;
} ) ;