Compare commits

...

48 commits

Author SHA1 Message Date
A R Hansen
8e73e4c16d Merge branch 'develop' 2018-10-12 12:50:54 +02:00
A R Hansen
06f1f4df91 - ll - 2018-10-12 12:48:15 +02:00
A R Hansen
70f520ea43 adding instructions 2018-10-12 12:46:09 +02:00
A R Hansen
f1d2b00b2b set up my own bitcore server and changed the url. for some reason Bitcoin.com's server won't accept 0 fee txs. 2018-10-12 11:53:16 +02:00
A R Hansen
4e524a7500 Not needed. 2018-10-08 02:16:43 +02:00
A R Hansen
c0a14fe11c Merge ZeroFeeTxs 2018-10-08 02:01:15 +02:00
A R Hansen
d47393f160 .. 2018-10-08 02:00:36 +02:00
A R Hansen
898b7d03fe 0 fee transaction feature added. 2018-10-08 01:55:55 +02:00
Jean-Baptiste Dominguez
49a6711970
Merge branch 'wallet/prod' into master 2018-09-22 10:59:24 +02:00
Brendon Duncan
d72a71d920 RC version. 2018-09-21 17:21:59 -07:00
Brendon Duncan
4d623d51d7 Merged sprint 21. 2018-09-21 17:16:18 -07:00
Brendon Duncan
ff40317d87 Merged fix for wallet transaction history. 2018-09-21 16:45:46 -07:00
Brendon Duncan
2e1cc9fa87 Showing cached history first when entering Wallet Details screen. 2018-09-21 16:43:27 -07:00
Brendon Duncan
cecad4a072 Merged 575. 2018-09-21 14:58:39 -07:00
Brendon Duncan
61c91d518a Merge branch 'wallet/sprint/21'. 2018-09-21 14:50:47 -07:00
Brendon Duncan
a17c3518c3 Manual merge from Sprint 22 for 575. 2018-09-21 14:38:28 -07:00
Brendon Duncan
6554b385cb
Merge pull request #345 from Bitcoin-com/wallet/task/591
591 - Wallet balance directive fails to get fiat balance sometimes
2018-09-21 12:53:46 -07:00
Brendon Duncan
c0912c5f17 IIFE for reviewController to make merging easier. 2018-09-21 12:31:55 -07:00
Brendon Duncan
e7eac1ee16
Merge pull request #335 from Bitcoin-com/wallet/task/586
Bug - 586 - Reconnect WebSocket when connection is failing or lost.
2018-09-21 11:35:27 -07:00
Brendon Duncan
46413fa6aa
Merge pull request #346 from Bitcoin-com/wallet/task/593
Bug - 593 - Update confirmations on cached transactions
2018-09-21 11:29:30 -07:00
Brendon Duncan
fb2802f392
Merge pull request #347 from Bitcoin-com/wallet/task/546
546 - Fix modal & shapeshift
2018-09-21 11:26:08 -07:00
Brendon Duncan
ea51e035ab Fixed updating of confirmations of cached transactions. Cache now properly cleared on first fetch from Wallet Details screen. 2018-09-21 03:56:51 -07:00
Brendon Duncan
0c8d145f73 Check validity of cachedStatus. 2018-09-21 02:54:06 -07:00
Jean-Baptiste Dominguez
977d03429d
Merge pull request #343 from Bitcoin-com/wallet/task/590
590 - The Personal Note field is not cleared between transactions.
2018-09-21 11:47:28 +02:00
Jean-Baptiste Dominguez
a8e5c212f0 Fix : Check if the status could be set before checking the balance. 2018-09-21 11:41:20 +02:00
Jean-Baptiste Dominguez
4250a98718 walletStatus worst case, IIFE for both controllers. 2018-09-21 11:31:27 +02:00
Brendon Duncan
a3614566e3 Reconnecting socket based on CloseEvent.code. 2018-09-21 02:27:34 -07:00
Jean-Baptiste Dominguez
5cb3d7521d Fix modal 2018-09-21 10:23:02 +02:00
Sebastiaan Pasma
3cad7d7ad8
Update confirmations on cached transactions 2018-09-20 15:58:42 +02:00
Brendon Duncan
4d6aeb4f91 Renamed directive and replaced old variable references with new ones. 2018-09-18 15:26:30 -07:00
Sebastiaan Pasma
78e4942fd6
Merge pull request #339 from Bitcoin-com/wallet/task/589
589 - Fix mobile build scripts
2018-09-18 13:51:54 +02:00
Brendon Duncan
7b6efaa1db Clear memo before entering Review screen. 2018-09-17 21:26:21 -07:00
Brendon Duncan
ebc32a2d85 Added 'default' to mobile debug build configs. 2018-09-16 21:04:41 -07:00
Sebastiaan Pasma
e6d8ddb360
update wallets in the promise callback 2018-09-13 09:54:53 +02:00
Sebastiaan Pasma
eb3067d369
Use cachedStatus when available and a fix for the review controller 2018-09-13 09:47:45 +02:00
Sebastiaan Pasma
908dcbf968
Add the received wallet status to the wallet API object 2018-09-12 16:50:26 +02:00
Sebastiaan Pasma
6692812d55
Websocket reconnect (and close old connection on leave) 2018-09-12 15:09:21 +02:00
Brendon Duncan
9438960e24 Hotfix version. 2018-09-12 18:39:56 +12:00
Brendon Duncan
d55fc70e7d Remove Games link. 2018-09-12 18:13:50 +12:00
Sebastiaan Pasma
ad4aa76902
Empty origin wallet screen bug 2018-09-11 14:55:22 +02:00
Brendon Duncan
ce02025991 Merge for building pkg. 2018-09-05 18:03:49 +12:00
Brendon Duncan
d2715016b5 Merge for building pkg. 2018-09-05 18:00:45 +12:00
Brendon Duncan
3afbdf73d3
Merge pull request #323 from Bitcoin-com/wallet/hotfix/578
578 - Shapeshift item on home tab now links to the Shapeshift website.
2018-09-05 15:30:09 +12:00
Brendon Duncan
00e4f8ac39 Hotfix version. 2018-09-05 15:28:10 +12:00
Brendon Duncan
8c62bc445a Shapeshift item on home tab now goes to the Shapeshift website. 2018-09-05 12:37:39 +12:00
Jean-Baptiste Dominguez
1c450418b8
Merge pull request #301 from Bitcoin-com/wallet/prod
5.0
2018-08-27 12:59:17 +09:00
Jean-Baptiste Dominguez
15b161d55d
Merge pull request #269 from Bitcoin-com/wallet/dev
Wallet/dev
2018-08-13 15:36:06 +09:00
Jean-Baptiste Dominguez
e127b81e7c
Merge pull request #242 from Bitcoin-com/wallet/prod
Wallet/prod
2018-08-07 23:01:10 +09:00
21 changed files with 1324 additions and 1122 deletions

14
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,14 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/www/index.html"
}
]
}

View file

@ -366,13 +366,13 @@ module.exports = function(grunt) {
grunt.registerTask('build-mobile-release', ['build-ios-release', 'build-android-release']);
// Build ios
grunt.registerTask('start-ios', ['exec:build_ios_debug', 'exec:xcode']);
grunt.registerTask('build-ios-debug', ['exec:build_ios_debug']);
grunt.registerTask('start-ios', ['default', 'exec:build_ios_debug', 'exec:xcode']);
grunt.registerTask('build-ios-debug', ['default', 'exec:build_ios_debug']);
grunt.registerTask('build-ios-release', ['prod', 'exec:build_ios_release']);
// Build android
grunt.registerTask('start-android', ['build-android-debug', 'exec:run_android']);
grunt.registerTask('build-android-debug', ['exec:build_android_debug']);
grunt.registerTask('build-android-debug', ['default', 'exec:build_android_debug']);
grunt.registerTask('start-android-emulator', ['build-android-debug', 'exec:run_android_emulator']);
grunt.registerTask('build-android-release', ['prod', 'exec:build_android_release', 'sign-android']);
grunt.registerTask('sign-android', ['exec:sign_android']);

View file

@ -1,3 +1,24 @@
This is a fork of the Bitcoin.com wallet to add additional features.
Features included:
- Zero fee transactions (only works for Bitcoin Cash). You will be asked for, if you want to send a transaction as zero fee on the confirmation page.
## Zero fee transactions:
Because most network nodes on the Bitcoin Cash network don't relay zero fee txs, you will experience some strange issues, but don't worry: for me personally the Bitcoin.com pool has included all my zero fee transactions, but please beware that the receiver probably won't see your tx before it has been confirmed and please do also keep in mind, that the transactions coming after it won't confirm or be seen before the zero fee one has been confirmed.
If you do already have a Bitcoin.com wallet, you need to create a new one to use this feature or change the wallet URL to: https://bws.freepages.dk/bws/api
## Disclaimer
Please beware this is my personal experimental project. You are more than welcome to play with it, but I don't take any responsibility of loss of funds due to errors in the code, so please make sure you made a backup before running this software.
## Builds
You can build the software yourself using the instructions below or use prebuilt binaries which can be found here (currently Windows and Linux only): https://ipfs.io/ipfs/QmR1DaS3QsDS48SzAWKUWFfmtMfJc4tgMtkSk3JFmuzewe
##
The Bitcoin.com wallet is a fork of the Copay Wallet (https://github.com/bitpay/copay).
The Bitcoin.com wallet is a secure bitcoin wallet platform for both desktop and mobile devices. It uses [Bitcore Wallet Service](https://github.com/Bitcoin-com/bitcore-wallet-service) (our fork of the [Bitpay Bitcore Wallet Service](https://github.com/bitpay/bitcore-wallet-service)) (BWS) for peer synchronization and network interfacing.

View file

@ -24,9 +24,9 @@
"windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c",
"pushSenderId": "1036948132229",
"description": "A Secure Bitcoin Wallet",
"version": "5.1.2",
"fullVersion": "5.1-rc1",
"androidVersion": "501002",
"version": "5.1.3",
"fullVersion": "5.1-rc2",
"androidVersion": "501003",
"_extraCSS": "",
"_enabledExtensions": {
"coinbase": false,

View file

@ -517,7 +517,8 @@ angular.module('copayApp.controllers').controller('confirmController', function(
if (!lodash.isEmpty(warningMsg))
msg += '\n' + warningMsg;
popupService.showAlert(null, msg, function() {});
popupService.showAlert(null, msg, function() {});
};
$scope.onWalletSelect = function(wallet) {

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
'use strict';
angular.module('copayApp.controllers').controller('servicesController', function($scope, $ionicScrollDelegate, $timeout, servicesService, configService) {
angular.module('copayApp.controllers').controller('servicesController', function(externalLinkService, $scope, $ionicScrollDelegate, $timeout, servicesService, configService) {
$scope.hide = false;
configService.whenAvailable(function(config) {
@ -20,4 +20,8 @@ angular.module('copayApp.controllers').controller('servicesController', function
}, 10);
};
$scope.open = function(url) {
externalLinkService.open(url, false);
}
});

View file

@ -10,7 +10,7 @@ angular.module('copayApp.controllers').controller('shapeshiftController', functi
walletsBtc = profileService.getWallets({coin: 'btc'});
walletsBch = profileService.getWallets({coin: 'bch'});
$scope.fromWallets = lodash.filter(walletsBtc.concat(walletsBch), function(w) {
return w.status.balance.availableAmount > 0;
return (w.status && w.status.balance && w.status.balance.availableAmount > 0);
});
$scope.singleFromWallet = $scope.fromWallets.length === 1;

View file

@ -2,6 +2,7 @@
angular.module('copayApp.controllers').controller('tabReceiveController', function($rootScope, $scope, $timeout, $log, $ionicModal, $state, $ionicHistory, $ionicPopover, storageService, platformInfo, walletService, profileService, configService, lodash, gettextCatalog, popupService, bwcError, bitcoinCashJsService, $ionicNavBarDelegate, sendFlowService, txFormatService, soundService, clipboardService) {
var CLOSE_NORMAL = 1000;
var listeners = [];
$scope.bchAddressType = { type: 'cashaddr' };
var bchAddresses = {};
@ -10,12 +11,11 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
$scope.isCordova = platformInfo.isCordova;
$scope.isNW = platformInfo.isNW;
var currentAddressSocket = {};
var paymentSubscriptionObj = { op:"addr_sub" }
var config;
var currentAddressSocket = null;
var paymentSubscriptionObj = { op:'addr_sub' };
$scope.displayBalanceAsFiat = true;
$scope.$on('$ionicView.beforeLeave', onBeforeLeave);
$scope.requestSpecificAmount = function() {
sendFlowService.start({
@ -24,6 +24,50 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
});
};
function connectSocket() {
// Close existing socket if not connected with current address
if (currentAddressSocket) {
currentAddressSocket.close([CLOSE_NORMAL]);
}
if ($scope.wallet.coin === 'bch') {
// listen to bch address
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/bch/inv');
paymentSubscriptionObj.addr = $scope.addrBchLegacy;
} else {
// listen to btc address
currentAddressSocket = new WebSocket('wss://ws.blockchain.info/inv');
paymentSubscriptionObj.addr = $scope.addr;
}
// create subscription to address
var msg = JSON.stringify(paymentSubscriptionObj);
currentAddressSocket.onopen = function (event) {
currentAddressSocket.send(msg);
};
// listen for response
currentAddressSocket.onmessage = function (event) {
//console.log("message received:" + event.data);
receivedPayment(event.data);
};
currentAddressSocket.onclose = function(event) {
if (event.code !== CLOSE_NORMAL) {
$log.debug('Socket was closed abnormally. Reconnect will be attempted in 1 second.');
$timeout(function() {
connectSocket();
}, 1000);
}
};
currentAddressSocket.onerror = function(err) {
console.error('Socket encountered error: ', err, 'Closing socket');
currentAddressSocket.close();
};
}
$scope.setAddress = function(newAddr, copyAddress) {
$scope.addr = null;
if (!$scope.wallet || $scope.generatingAddress || !$scope.wallet.isComplete()) return;
@ -36,49 +80,24 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
popupService.showAlert(err);
}
//close existing socket
if (currentAddressSocket.close === 'function') {
currentAddressSocket.close();
}
if ($scope.wallet.coin == 'bch') {
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
$scope.addr = bchAddresses[$scope.bchAddressType.type];
$scope.addrBchLegacy = bchAddresses['legacy'];
// listen to bch address
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/bch/inv");
paymentSubscriptionObj.addr = bchAddresses['legacy'];
if ($scope.wallet.coin === 'bch') {
bchAddresses = bitcoinCashJsService.translateAddresses(addr);
$scope.addr = bchAddresses[$scope.bchAddressType.type];
$scope.addrBchLegacy = bchAddresses['legacy'];
} else {
$scope.addr = addr;
// listen to btc address
currentAddressSocket = new WebSocket("wss://ws.blockchain.info/inv");
paymentSubscriptionObj.addr = $scope.addr
$scope.addr = addr;
}
connectSocket();
if (copyAddress === true) {
try {
clipboardService.copyToClipboard($scope.wallet.coin == 'bch' && $scope.bchAddressType.type == 'cashaddr' ? 'bitcoincash:' + $scope.addr : $scope.addr);
} catch (error) {
$log.debug("Error copying to clipboard:");
$log.debug('Error copying to clipboard:');
$log.debug(error);
}
}
// create subscription
var msg = JSON.stringify(paymentSubscriptionObj);
currentAddressSocket.onopen = function (event) {
//console.log("message sent: " + msg);
currentAddressSocket.send(msg);
}
// listen for response
currentAddressSocket.onmessage = function (event) {
//console.log("message received:" + event.data);
receivedPayment(event.data);
}
$timeout(function() {
$scope.$apply();
@ -164,7 +183,6 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
// Notify new tx
$scope.$emit('bwsEvent', $scope.wallet.id);
$scope.$apply(function () {
$scope.showingPaymentReceived = true;
});
@ -233,6 +251,10 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
}
};
function onBeforeLeave() {
currentAddressSocket.close([CLOSE_NORMAL]);
}
$scope.$on("$ionicView.beforeEnter", function(event, data) {
$scope.wallets = profileService.getWallets();
$scope.singleWallet = $scope.wallets.length == 1;
@ -258,7 +280,6 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
configService.whenAvailable(function(_config) {
$scope.displayBalanceAsFiat = _config.wallet.settings.priceDisplay === 'fiat';
config = _config;
});
});

View file

@ -203,6 +203,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
function updateTxHistoryFromCachedData() {
$scope.vm.gettingCachedHistory = true;
walletHistoryService.getCachedTxHistory($scope.wallet.id, function onGetCachedTxHistory(err, txHistory){
$scope.vm.gettingCachedHistory = false;
if (err) {
@ -400,8 +401,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
var refreshInterval;
$scope.$on("$ionicView.afterEnter", function(event, data) {
$scope.updateAll();
$scope.$on("$ionicView.afterEnter", function onAfterEnter(event, data) {
updateTxHistoryFromCachedData();
$scope.updateAll(true, true);
// refreshAmountSection();
refreshInterval = $interval($scope.onRefresh, 10 * 1000);
$timeout(function() {

View file

@ -1,189 +1,204 @@
'use strict';
angular.module('copayApp.controllers').controller('walletSelectorController', function($scope, $state, sendFlowService, configService, gettextCatalog, profileService, txFormatService) {
(function () {
var fromWalletId = '';
var priceDisplayAsFiat = false;
var unitDecimals = 0;
var unitsFromSatoshis = 0;
angular
.module('copayApp.controllers')
.controller('walletSelectorController', walletSelectorController);
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
$scope.$on("$ionicView.enter", onEnter);
function walletSelectorController ($scope, $state, sendFlowService, configService, gettextCatalog, ongoingProcess, profileService, walletService, txFormatService) {
var fromWalletId = '';
var priceDisplayAsFiat = false;
var unitDecimals = 0;
var unitsFromSatoshis = 0;
function onBeforeEnter(event, data) {
if (data.direction == "back") {
sendFlowService.state.pop();
}
$scope.$on("$ionicView.beforeEnter", onBeforeEnter);
$scope.$on("$ionicView.enter", onEnter);
$scope.params = sendFlowService.state.getClone();
function onBeforeEnter(event, data) {
if (data.direction == "back") {
sendFlowService.state.pop();
}
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
$scope.params = sendFlowService.state.getClone();
var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat';
unitDecimals = config.unitDecimals;
unitsFromSatoshis = 1 / config.unitToSatoshi;
console.log('walletSelector onBeforeEnter after back sendflow', $scope.params);
if ($scope.params.isWalletTransfer) {
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
} else if (!$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Send');
}
var config = configService.getSync().wallet.settings;
priceDisplayAsFiat = config.priceDisplay === 'fiat';
unitDecimals = config.unitDecimals;
unitsFromSatoshis = 1 / config.unitToSatoshi;
$scope.coin = false; // Wallets to show (for destination screen or contacts)
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
fromWalletId = $scope.params['fromWalletId'];
if ($scope.params.isWalletTransfer) {
$scope.sendFlowTitle = gettextCatalog.getString('Transfer between wallets');
} else if (!$scope.params.thirdParty) {
$scope.sendFlowTitle = gettextCatalog.getString('Send');
}
if ($scope.type === 'destination' && $scope.params.toAddress) {
$state.transitionTo(getNextStep($scope.params));
}
$scope.coin = false; // Wallets to show (for destination screen or contacts)
$scope.type = $scope.params['fromWalletId'] ? 'destination' : 'origin'; // origin || destination
fromWalletId = $scope.params['fromWalletId'];
if ($scope.params.coin) {
$scope.coin = $scope.params.coin; // Contacts have a coin embedded
}
if ($scope.type === 'destination' && $scope.params.toAddress) {
$state.transitionTo(getNextStep($scope.params));
}
if ($scope.params.amount) { // There is an amount, so presume that it is a payment request
$scope.sendFlowTitle = gettextCatalog.getString('Payment Request');
$scope.specificAmount = $scope.specificAlternativeAmount = '';
$scope.isPaymentRequest = true;
}
if ($scope.params.thirdParty) {
$scope.thirdParty = $scope.params.thirdParty;
}
};
if ($scope.params.coin) {
$scope.coin = $scope.params.coin; // Contacts have a coin embedded
}
function onEnter (event, data) {
configService.whenAvailable(function(config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
});
if ($scope.params.amount) { // There is an amount, so presume that it is a payment request
$scope.sendFlowTitle = gettextCatalog.getString('Payment Request');
$scope.specificAmount = $scope.specificAlternativeAmount = '';
$scope.isPaymentRequest = true;
}
if ($scope.params.thirdParty) {
$scope.thirdParty = $scope.params.thirdParty;
}
};
if ($scope.thirdParty) {
// Third party services specific logic
handleThirdPartyIfShapeshift();
}
prepareWalletLists();
formatRequestedAmount();
};
function formatRequestedAmount() {
if ($scope.params.amount) {
var cryptoAmount = (unitsFromSatoshis * $scope.params.amount).toFixed(unitDecimals);
var cryptoCoin = $scope.coin.toUpperCase();
txFormatService.formatAlternativeStr($scope.coin, $scope.params.amount, function onFormatAlternativeStr(formatted){
if (formatted) {
var fiatParts = formatted.split(' ');
var fiatAmount = fiatParts[0];
var fiatCurrrency = fiatParts.length > 1 ? fiatParts[1] : '';
if (priceDisplayAsFiat) {
$scope.requestAmount = fiatAmount;
$scope.requestCurrency = fiatCurrrency;
$scope.requestAmountSecondary = cryptoAmount;
$scope.requestCurrencySecondary = cryptoCoin;
} else {
$scope.requestAmount = cryptoAmount;
$scope.requestCurrency = cryptoCoin;
$scope.requestAmountSecondary = fiatAmount;
$scope.requestCurrencySecondary = fiatCurrrency;
}
$scope.$apply();
}
function onEnter (event, data) {
configService.whenAvailable(function(config) {
$scope.selectedPriceDisplay = config.wallet.settings.priceDisplay;
});
}
}
function handleThirdPartyIfShapeshift() {
console.log($scope.thirdParty, $scope.coin);
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
$scope.coin = profileService.getWallet(fromWalletId).coin;
if ($scope.coin === 'bch') {
$scope.coin = 'btc';
} else {
$scope.coin = 'bch';
if ($scope.thirdParty) {
// Third party services specific logic
handleThirdPartyIfShapeshift();
}
}
}
function prepareWalletLists() {
var walletsAll = [];
var walletsSufficientFunds = [];
$scope.walletsInsufficientFunds = []; // For origin screen
if ($scope.type === 'origin') {
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
prepareWalletLists();
formatRequestedAmount();
};
function formatRequestedAmount() {
if ($scope.params.amount) {
var cryptoAmount = (unitsFromSatoshis * $scope.params.amount).toFixed(unitDecimals);
var cryptoCoin = $scope.coin.toUpperCase();
walletsAll = profileService.getWallets({coin: $scope.coin});
txFormatService.formatAlternativeStr($scope.coin, $scope.params.amount, function onFormatAlternativeStr(formatted){
if (formatted) {
var fiatParts = formatted.split(' ');
var fiatAmount = fiatParts[0];
var fiatCurrrency = fiatParts.length > 1 ? fiatParts[1] : '';
walletsAll.forEach(function forWallet(wallet){
if (wallet.status.availableBalanceSat > $scope.params.amount) {
walletsSufficientFunds.push(wallet);
} else {
$scope.walletsInsufficientFunds.push(wallet);
if (priceDisplayAsFiat) {
$scope.requestAmount = fiatAmount;
$scope.requestCurrency = fiatCurrrency;
$scope.requestAmountSecondary = cryptoAmount;
$scope.requestCurrencySecondary = cryptoCoin;
} else {
$scope.requestAmount = cryptoAmount;
$scope.requestCurrency = cryptoCoin;
$scope.requestAmountSecondary = fiatAmount;
$scope.requestCurrencySecondary = fiatCurrrency;
}
$scope.$apply();
}
});
}
}
if ($scope.coin === 'btc') {
$scope.walletsBtc = walletsSufficientFunds;
function handleThirdPartyIfShapeshift() {
console.log($scope.thirdParty, $scope.coin);
if ($scope.thirdParty.id === 'shapeshift' && $scope.type === 'destination') { // Shapeshift wants to know the
$scope.coin = profileService.getWallet(fromWalletId).coin;
if ($scope.coin === 'bch') {
$scope.coin = 'btc';
} else {
$scope.walletsBch = walletsSufficientFunds;
$scope.coin = 'bch';
}
}
}
} else if ($scope.coin) {
walletsAll = profileService.getWallets({coin: $scope.coin});
walletsAll.forEach(function forWallet(wallet){
if (wallet.status.availableBalanceSat > 0) {
walletsSufficientFunds.push(wallet);
function prepareWalletLists() {
var walletsAll = [];
var walletsSufficientFunds = [];
$scope.walletsInsufficientFunds = []; // For origin screen
if ($scope.type === 'origin') {
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send from');
if ($scope.params.amount || $scope.coin) {
walletsAll = profileService.getWallets({coin: $scope.coin});
ongoingProcess.set('scanning', true);
walletsAll.forEach(function forWallet(wallet) {
if (!wallet.status && !wallet.cachedStatus) {
walletService.getStatus(wallet, {}, function(err, status) {
wallet.status = status;
if (status.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
walletsSufficientFunds.push(wallet);
} else {
$scope.walletsInsufficientFunds.push(wallet);
}
if ($scope.coin === 'btc') { // As this is a promise
$scope.walletsBtc = walletsSufficientFunds;
} else {
$scope.walletsBch = walletsSufficientFunds;
}
ongoingProcess.set('scanning', false);
});
} else {
var walletStatus = null;
if (wallet.status && wallet.status.isValid) {
walletStatus = wallet.status;
} else if (wallet.cachedStatus && wallet.status.isValid) {
walletStatus = wallet.cachedStatus;
}
if (walletStatus && walletStatus.availableBalanceSat > ($scope.params.amount ? $scope.params.amount : 0)) {
walletsSufficientFunds.push(wallet);
} else {
$scope.walletsInsufficientFunds.push(wallet);
}
ongoingProcess.set('scanning', false);
}
});
if ($scope.coin === 'btc') {
$scope.walletsBtc = walletsSufficientFunds;
} else {
$scope.walletsInsufficientFunds.push(wallet);
$scope.walletsBch = walletsSufficientFunds;
}
});
if ($scope.coin === 'btc') {
$scope.walletsBtc = walletsSufficientFunds;
} else {
$scope.walletsBch = walletsSufficientFunds;
$scope.walletsBch = profileService.getWallets({coin: 'bch', hasFunds: true});
$scope.walletsBtc = profileService.getWallets({coin: 'btc', hasFunds: true});
$scope.walletsInsufficientFunds = profileService.getWallets({coin: $scope.coin, hasNoFunds: true});
}
} else {
$scope.walletsBch = profileService.getWallets({coin: 'bch', hasFunds: true});
$scope.walletsBtc = profileService.getWallets({coin: 'btc', hasFunds: true});
$scope.walletsInsufficientFunds = profileService.getWallets({coin: $scope.coin, hasNoFunds: true});
}
} else if ($scope.type === 'destination') {
if (!$scope.coin) { // Allow for the coin to be set by a third party
$scope.fromWallet = profileService.getWallet(fromWalletId);
$scope.coin = $scope.fromWallet.coin; // Only show wallets with the select origin wallet coin
}
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send to');
} else if ($scope.type === 'destination') {
if (!$scope.coin) { // Allow for the coin to be set by a third party
$scope.fromWallet = profileService.getWallet(fromWalletId);
$scope.coin = $scope.fromWallet.coin; // Only show wallets with the select origin wallet coin
}
$scope.headerTitle = gettextCatalog.getString('Choose a wallet to send to');
if ($scope.coin === 'btc') { // if no specific coin is set or coin is set btc
$scope.walletsBtc = profileService.getWallets({coin: $scope.coin});
} else {
$scope.walletsBch = profileService.getWallets({coin: $scope.coin});
if ($scope.coin === 'btc') { // if no specific coin is set or coin is set btc
$scope.walletsBtc = profileService.getWallets({coin: $scope.coin});
} else {
$scope.walletsBch = profileService.getWallets({coin: $scope.coin});
}
}
}
}
$scope.useWallet = function(wallet) {
var params = sendFlowService.state.getClone();
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
params.fromWalletId = wallet.id;
} else { // we're on the destination screen, set wallet to send to
params.toWalletId = wallet.id;
$scope.useWallet = function(wallet) {
var params = sendFlowService.state.getClone();
if ($scope.type === 'origin') { // we're on the origin screen, set wallet to send from
params.fromWalletId = wallet.id;
} else { // we're on the destination screen, set wallet to send to
params.toWalletId = wallet.id;
}
sendFlowService.goNext(params);
};
$scope.goBack = function() {
sendFlowService.router.goBack();
}
sendFlowService.goNext(params);
};
$scope.goBack = function() {
sendFlowService.router.goBack();
}
});
})();

View file

@ -12,6 +12,7 @@
totalBalanceSat: '@',
// The Wallet object is sometimes not stringify()-able, so not interpolatable,
// so can't be passed to a directive.
walletCoin: '@',
walletStatus: '@',
walletCachedBalance: '@',
walletCachedBalanceUpdatedOn: '@',
@ -31,7 +32,6 @@
});
function displayCryptoBalance(walletStatus, walletCachedBalance, walletCachedBalanceUpdatedOn, walletCachedStatus) {
console.log('displayCryptoBalance()');
if (walletStatus && walletStatus.isValid && walletStatus.totalBalanceStr) {
setDisplay(walletStatus.totalBalanceStr, '');
@ -52,7 +52,7 @@
setDisplay('', '');
}
function displayFiatBalance(walletStatus, walletCachedStatus) {
function displayFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var displayAmount = '';
if (walletStatus && walletStatus.isValid && walletStatus.alternativeBalanceAvailable) {
displayAmount = walletStatus.totalBalanceAlternative + ' ' + walletStatus.alternativeIsoCode;
@ -66,7 +66,7 @@
return;
}
getFiatBalance(wallet);
getFiatBalance(walletStatus, walletCachedStatus, walletCoin);
}
function formatBalance() {
@ -94,19 +94,30 @@
}
if (displayAsFiat) {
displayFiatBalance(walletStatusObj, walletCachedStatusObj);
displayFiatBalance(walletStatusObj, walletCachedStatusObj, $scope.walletCoin);
}
}
function getFiatBalance(wallet) {
if (!(wallet.status && wallet.status.isValid)) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status.');
function getFiatBalance(walletStatus, walletCachedStatus, walletCoin) {
var totalBalanceSat = null;
if (walletStatus && walletStatus.isValid) {
totalBalanceSat = walletStatus.totalBalanceSat
} else if (walletCachedStatus && walletCachedStatus.isValid) {
totalBalanceSat = walletCachedStatus.totalBalanceSat
}
// 0 is valid
if (totalBalanceSat === null) {
$log.warn('Abandoning call to get fiat balance, because no valid wallet status (cached or otherwise).');
return;
}
txFormatService.formatAlternativeStr(wallet.coin, wallet.status.totalBalanceSat, function onFormatAlernativeStr(formatted) {
txFormatService.formatAlternativeStr(walletCoin, totalBalanceSat, function onFormatAlernativeStr(formatted) {
if (formatted) {
setDisplay(formatted, '');
} else {
$log.error('Failed to format fiat balance of wallet.');
}
});
}

View file

@ -18,7 +18,7 @@ angular.module('copayApp.services').factory('configService', function(storageSer
},
bwscash: {
url: 'https://bwscash.bitcoin.com/bws/api'
url: 'https://bws.freepages.dk/bws/api'
},
download: {

View file

@ -12,6 +12,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
normal: gettext('Normal'),
economy: gettext('Economy'),
superEconomy: gettext('Super Economy'),
// free: gettext('No fee (works only for BCH)'),
custom: gettext('Custom')
};
@ -31,6 +32,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
root.getFeeRate = function(coin, network, feeLevel, cb) {
if (feeLevel == 'custom') return cb();
// if (feeLevel == 'free') return cb(null, 0);
network = network || 'livenet';
@ -48,9 +50,9 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
})
});
}
var feeRate = feeLevelRate.feePerKb;
if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKb / 1000).toFixed() + ' SAT/B');
return cb(null, feeRate);

View file

@ -75,9 +75,7 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
var showName = $filter('translate')(processNames[name] || name);
if (customHandler) {
customHandler(processName, showName, isOn);
} else if (root.onGoingProcessName) {
if (root.onGoingProcessName) {
var tmpl;
if (isWindowsPhoneApp) tmpl = '<div>' + showName + '</div>';
else tmpl = '<div class="item-icon-left">' + showName + '<ion-spinner class="spinner-stable" icon="lines"></ion-spinner></div>';
@ -87,6 +85,10 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
} else {
$ionicLoading.hide();
}
if (customHandler) {
customHandler(processName, showName, isOn);
}
};
return root;

View file

@ -5,7 +5,7 @@ angular.module('copayApp.services').factory('servicesService', function(configSe
name: 'shapeshift',
title: 'Shapeshift',
icon: 'icon-shapeshift',
sref: 'tabs.shapeshift',
href: 'https://shapeshift.io/'
}];
root.register = function(serviceInfo) {

View file

@ -27,20 +27,23 @@
function addEarlyTransactions(walletId, cachedTxs, newTxs) {
var cachedTxIds = {};
var cachedTxIndexFromId = {};
cachedTxs.forEach(function forCachedTx(tx){
cachedTxIds[tx.txid] = true;
cachedTxIndexFromId[tx.txid] = true;
});
var confirmationsUpdated = false;
var someTransactionsWereNew = false;
var overlappingTxsCount = 0;
newTxs.forEach(function forNewTx(tx){
if (cachedTxIds[tx.txid]) {
overlappingTxsCount++;
} else {
if (typeof cachedTxIndexFromId[tx.txid] === "undefined") {
someTransactionsWereNew = true;
cachedTxs.push(tx);
} else {
var txUpdated = updateCachedTx(cachedTxs, cachedTxIndexFromId, tx);
confirmationsUpdated = confirmationsUpdated || txUpdated;
overlappingTxsCount++;
}
});
@ -50,6 +53,8 @@
if (overlappingTxFraction >= MIN_KNOWN_TX_OVERLAP_FRACTION) { // We are good
if (someTransactionsWereNew) {
saveTxHistory(walletId, cachedTxs);
} else if (confirmationsUpdated) {
saveTxHistory(walletId, cachedTxs);
} else if (overlappingTxsCount === newTxs.length) {
allTransactionsFetched = true;
}
@ -65,21 +70,24 @@
}
function addLatestTransactions(walletId, cachedTxs, newTxs) {
var cachedTxIds = {};
cachedTxs.forEach(function forCachedTx(tx){
cachedTxIds[tx.txid] = true;
var cachedTxIndexFromId = {};
cachedTxs.forEach(function forCachedTx(tx, txIndex){
cachedTxIndexFromId[tx.txid] = txIndex;
});
var someTransactionsWereNew = false;
var confirmationsUpdated = false;
var overlappingTxsCount = 0;
var uniqueNewTxs = [];
newTxs.forEach(function forNewTx(tx){
if (cachedTxIds[tx.txid]) {
overlappingTxsCount++;
} else {
if (typeof cachedTxIndexFromId[tx.txid] === "undefined") {
someTransactionsWereNew = true;
uniqueNewTxs.push(tx);
} else {
var txUpdated = updateCachedTx(cachedTxs, cachedTxIndexFromId, tx);
confirmationsUpdated = confirmationsUpdated || txUpdated;
overlappingTxsCount++;
}
});
@ -91,6 +99,9 @@
saveTxHistory(walletId, allTxs);
return allTxs;
} else {
if (confirmationsUpdated) {
saveTxHistory(walletId, cachedTxs);
}
return cachedTxs;
}
} else {
@ -104,6 +115,8 @@
// Only clear the cache once we have received new transactions from the server.
/**
* @param wallet
* @param start
* @param {function(err, txs)} cb - transactions is always an array, may be empty
*/
function fetchTxHistoryByPage(wallet, start, cb) {
@ -134,6 +147,7 @@
* @param {function(error, txs)} cb - txs is always an array, may be empty
*/
function getCachedTxHistory(walletId, cb) {
console.log('txhistory updateLocalTxHistoryByPage()');
storageService.getTxHistory(walletId, function onGetTxHistory(err, txHistoryString){
if (err) {
return cb(err, []);
@ -187,7 +201,7 @@
});
return processedTxs;
};
}
function saveTxHistory(walletId, processedTxs) {
storageService.setTxHistory(processedTxs, walletId, function onSetTxHistory(error){
@ -197,9 +211,26 @@
});
}
/**
* Returns true if the cached tx was updated
* @param {*} cachedTxs
* @param {*} cachedTxIndexFromId - Indices for cachedTxs, based on txid
* @param {*} tx - The most recent tx info
*/
function updateCachedTx(cachedTxs, cachedTxIndexFromId, tx) {
var updated = false;
var txIndex = cachedTxIndexFromId[tx.txid];
var cachedTx = cachedTxs[txIndex];
if (cachedTx.confirmations < SAFE_CONFIRMATIONS && tx.confirmations > cachedTx.confirmations) {
cachedTxs[txIndex].confirmations = tx.confirmations;
updated = true;
}
return updated;
}
function updateLocalTxHistoryByPage(wallet, getLatest, flushCacheOnNew, cb) {
console.log('txhistory updaetLocalTxHistoryByPage()');
if (flushCacheOnNew) {
fetchTxHistoryByPage(wallet, 0, function onFetchTxHistory(err, txs){
if (err) {
@ -240,10 +271,5 @@
});
}
}
}
})();

View file

@ -10083,7 +10083,7 @@ ion-view.deflash-blue:before, ion-view#view-amount:before, ion-view#view-confirm
.onboarding .button.button-white.button-standard,
.onboarding .button.button-green.button-standard,
.onboarding .button.button-assertive.button-standard, #shapeshift .button-shapeshift {
width: 85%;
width: 90%;
max-width: 300px;
margin-left: auto;
margin-right: auto;
@ -10195,6 +10195,7 @@ ion-view.deflash-blue:before, ion-view#view-amount:before, ion-view#view-confirm
.button {
border-radius: 6px; }
.button.button-full {
border-radius: 0;
display: block; }
.button-green {
border-color: #FFF;
@ -10263,8 +10264,8 @@ ion-view.deflash-blue:before, ion-view#view-amount:before, ion-view#view-confirm
color: #FFFFFF;
text-decoration: none; }
.button-white-outline.active, .button-white-outline.activated {
border-color: #FFF;
background-color: #FAFAFA; }
border-color: #FFFFFF;
background-color: #FFFFFF; }
.button-white-outline.button-outline {
border-color: #FFFFFF;
background: transparent;
@ -10632,7 +10633,7 @@ qrcode {
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.long input, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.long .unit, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.long .primary-amount-display {
font-size: 2em; } }
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long input, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long .unit, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long .primary-amount-display {
font-size: 0.9em; }
font-size: 1.2em; }
@media (min-width: 375px) {
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long input, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long .unit, #view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount.very-long .primary-amount-display {
font-size: 1.3em; } }
@ -10659,7 +10660,8 @@ qrcode {
line-height: 1em; }
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .primary-amount .primary-amount-display {
margin-right: 5px;
word-break: break-all; }
word-break: break-all;
width: 100%; }
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .alternative-amount {
color: #6F6F70; }
#view-amount .scroll-content .send-amount .send-amount-tool .send-amount-tool-input .switch-currencies {
@ -10680,30 +10682,33 @@ qrcode {
justify-content: space-between;
margin: 0 14px; }
#view-amount .scroll-content .send-amount-extras .available-funds {
color: #6F6F70; }
color: #6F6F70;
text-align: left; }
#view-amount .scroll-content .send-amount-extras .change-currency {
text-align: right; }
#view-amount .scroll-content .send-amount-extras .warning {
color: #b7664d; }
#view-amount .scroll-content .send-amount-extras .extra,
#view-amount .scroll-content .send-amount-extras button.extra {
/*display: flex;*/
flex: 0 1 auto; }
#view-amount .scroll-content .send-amount-extras button.extra {
background: none;
border: none;
color: #000;
font-family: 'ProximaNova';
font-size: 14px;
line-height: normal;
min-height: auto;
min-width: auto;
padding: 0; }
#view-amount .scroll-content .send-amount-extras .button .icon:before {
font-size: 14px;
#view-amount .scroll-content .send-amount-extras .extra {
flex: 1;
line-height: normal; }
#view-amount .scroll-content .send-amount-extras .button span {
display: flex;
align-items: center;
justify-content: center; }
#view-amount .scroll-content .send-amount-extras .extra .button {
background: none;
border: none;
border-radius: 0;
color: #000;
font-family: 'ProximaNova';
font-size: 14px;
line-height: normal;
min-height: auto;
min-width: auto;
padding: 0; }
#view-amount .scroll-content .send-amount-extras .extra .button .icon:before {
font-size: 14px;
line-height: normal; }
#view-amount .scroll-content .send-amount-extras .extra .button span {
display: flex;
align-items: center;
justify-content: center; }
#view-amount .scroll-content .button.no-margin {
margin: 0; }
#view-amount .scroll-content .notification-warning {
@ -10939,14 +10944,14 @@ qrcode {
#tab-home .buttons .button {
border: 2px solid;
border-radius: 47px;
padding: 0 15px 0 15px;
padding: 8px 2px 8px 2px;
text-align: center;
width: 100%;
max-width: 300px;
font-size: 19px;
font-weight: bolder;
min-height: auto;
line-height: 36px; }
min-height: 0;
line-height: 19px; }
#tab-home .wallet-coin-logo {
vertical-align: middle;
@ -11013,6 +11018,10 @@ qrcode {
#tab-home .release .title {
font-weight: 700;
color: #444; }
#tab-home .release .release-notes {
white-space: pre;
white-space: pre-line;
text-align: left; }
#tab-home .release .button {
width: 100%;
border: none; }
@ -11025,6 +11034,14 @@ qrcode {
#tab-home .badge {
top: 11px; }
.popup-update .popup-buttons {
display: block; }
.popup-update .popup-buttons .button {
display: block;
min-width: 100% !important;
margin-top: 4px; }
#tab-receive .button-share {
color: #fff;
box-shadow: none;
@ -11101,6 +11118,8 @@ qrcode {
#tab-receive .payment-received-container {
margin: 0 20px; }
#tab-receive .payment-received-container svg {
max-height: 400px; }
#tab-receive .payment-received-container .payment-received-amount {
font-size: 1.8em;
display: block;
@ -11207,7 +11226,7 @@ qrcode {
margin: auto;
margin-top: 18px; }
#tab-send .send-wrapper .buttons .button {
height: 60px;
min-height: 65px;
line-height: 16px;
margin-right: 0px;
width: 95%;
@ -11284,7 +11303,9 @@ qrcode {
margin-top: 18px; }
#tab-send .sendTip .buttons .button {
font-weight: bold;
font-size: 19px; }
font-size: 19px;
line-height: 26px;
padding: 8px 6px; }
#tab-send .sendTip .button-first-contact img {
height: 19px;
width: 19px;
@ -11920,6 +11941,13 @@ qrcode {
#walletDetails .bp-content.status-bar {
margin-top: 20px;
margin-top: env(safe-area-inset-top); }
#walletDetails .bp-content.collapse ion-content {
margin-top: 40px; }
#walletDetails .bp-content.collapse .amount__scale, #walletDetails .bp-content.collapse .amount__error {
-webkit-transform: scale3d(0.5, 0.5, 0.5) translateY(0px);
transform: scale3d(0.5, 0.5, 0.5) translateY(0px); }
#walletDetails .bp-content.collapse .amount-alternative, #walletDetails .bp-content.collapse .send-receive-buttons, #walletDetails .bp-content.collapse .wallet-details-wallet-info {
opacity: 0; }
#walletDetails .bar-header {
border: 0;
background: #eeb640; }
@ -11932,9 +11960,12 @@ qrcode {
#walletDetails ion-content {
padding-top: 0;
top: 0;
transition: all 0.25s ease-in-out;
margin-top: 185px;
margin-bottom: 16px; }
#walletDetails ion-content.collapsible {
margin-top: 230px; }
@media only screen and (max-height: 500px) {
#walletDetails ion-content {
margin-top: 165px; } }
#walletDetails ion-content .scroll {
background: #f8f8f9;
min-height: 300px; }
@ -11965,38 +11996,45 @@ qrcode {
justify-content: space-evenly;
width: 100%;
position: absolute;
bottom: 20px; }
bottom: 20px;
transition: all 0.25s ease-in-out; }
#walletDetails .amount-wrapper .send-receive-buttons > .col {
padding: 5px 10px;
margin-bottom: 0; }
#walletDetails .amount-wrapper .send-receive-buttons .button {
border: 2px solid;
border-radius: 47px;
padding: 0 15px 0 15px;
padding: 6px 2px 6px 2px;
text-align: center;
width: 100%;
max-width: 300px;
font-size: 19px;
font-weight: bolder;
min-height: auto;
line-height: 36px; }
min-height: 0;
line-height: 19px; }
#walletDetails .amount {
width: 100%;
text-align: center;
color: #fff;
height: 230px;
padding-top: 40px;
display: block;
align-items: center;
justify-content: center; }
color: #fff;
display: block;
height: 230px;
justify-content: center;
padding-top: 40px;
text-align: center;
transition: all 0.25s ease-in-out;
width: 100%; }
@media only screen and (max-height: 500px) {
#walletDetails .amount {
height: 210px; } }
#walletDetails .amount__balance {
-webkit-transform: scale3d(1, 1, 1) translateY(45px);
transform: scale3d(1, 1, 1) translateY(45px); }
transform: scale3d(1, 1, 1) translateY(45px);
transition: all 0.25s ease-in-out; }
#walletDetails .amount__updating {
z-index: 999;
margin-top: -2.1rem; }
#walletDetails .amount-alternative {
line-height: 36px; }
line-height: 36px;
transition: all 0.25s ease-in-out; }
#walletDetails .amount__button-balance {
background-color: transparent;
border: 1px solid rgba(255, 255, 255, 0.25);
@ -12006,7 +12044,8 @@ qrcode {
vertical-align: middle; }
#walletDetails .amount__error {
font-size: 14px;
padding: 35px 20px; }
padding: 35px 20px;
opacity: 1; }
#walletDetails .no-alternative {
padding-top: 45px; }
#walletDetails .item.item-footer {
@ -12071,7 +12110,9 @@ a.item {
font-size: 0.9em; }
.loading-wallet svg {
margin-top: 0; }
margin-top: 0;
width: 16px;
height: 16px; }
#advanced-settings .list .item:before {
display: block;
@ -12125,7 +12166,9 @@ a.item {
margin-top: 18px; }
#shapeshift .empty-case .buttons .button {
font-weight: bold;
font-size: 19px; }
font-size: 19px;
line-height: 26px;
padding: 8px 6px; }
#shapeshift .empty-case .button-first-contact img {
height: 19px;
width: 19px;
@ -13812,6 +13855,7 @@ click-to-accept {
height: 92px;
width: 100%; }
click-to-accept .click-to-accept__button.button.button-primary.button-standard {
border-radius: 0;
height: 100%;
max-width: 9999px;
width: 100%; }
@ -13918,6 +13962,8 @@ slide-to-accept {
height: 92px;
width: 100%;
background: #494949; }
slide-to-accept .slide .button {
border-radius: 0; }
slide-to-accept .slide__listener {
height: 100%;
width: 100%;
@ -15349,20 +15395,25 @@ log-options #check-bar .checkbox-icon {
#cash-scan a {
cursor: pointer; }
#view-review {
background-color: #494949; }
#view-review slide-to-accept, #view-review slide-to-accept-success {
margin-bottom: constant(safe-area-inset-bottom);
/* iOS 11.0 */
margin-bottom: env(safe-area-inset-bottom);
/* iOS 11.2 */ }
#view-review .fee-summary {
position: absolute;
bottom: 92px; }
#view-review .shapeshift-banner, #view-review .bitpay-banner, #view-review .egifter-banner {
box-shadow: none; }
#view-review .warning {
color: #b7664d; }
#view-review slide-to-accept, #view-review slide-to-accept-success {
margin-bottom: constant(safe-area-inset-bottom);
/* iOS 11.0 */
margin-bottom: env(safe-area-inset-bottom);
/* iOS 11.2 */ }
#view-review .fee-summary {
bottom: 92px;
bottom: calc(92px + constant(safe-area-inset-bottom));
/* iOS 11.0 */
bottom: calc(92px + env(safe-area-inset-bottom));
/* iOS 11.2 */
position: absolute; }
#view-review .shapeshift-banner, #view-review .bitpay-banner, #view-review .egifter-banner {
box-shadow: none; }
#view-review .warning {
color: #b7664d; }
.gravatar {
border-radius: 3px;
@ -15395,6 +15446,7 @@ log-options #check-bar .checkbox-icon {
left: 13px;
top: 50%;
padding: 0;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%); }
.item .item-content.item-content-compact {
@ -15463,8 +15515,8 @@ ion-content.padded-bottom-cta-with-summary {
overflow: hidden;
text-overflow: ellipsis; }
.address-frame.expanded {
white-space: pre-wrap;
word-break: break-all; }
white-space: normal;
text-overflow: clip; }
.address-frame .prefix {
color: #000000; }
.address-frame .mid {
@ -15507,13 +15559,13 @@ ion-content.padded-bottom-cta-with-summary {
transform: scale(1, 1); }
.fee-summary {
position: relative;
background-color: #F2F2F2;
box-sizing: border-box;
display: flex;
flex-direction: column;
width: 100%;
padding: 5px 12px 15px;
box-sizing: border-box;
background-color: #F2F2F2; }
position: relative;
width: 100%; }
.fee-summary:before {
content: '';
position: absolute;
@ -15523,16 +15575,16 @@ ion-content.padded-bottom-cta-with-summary {
height: 15px;
background: linear-gradient(to bottom, rgba(242, 242, 242, 0) 0%, #f2f2f2 100%); }
.fee-summary .amount {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%; }
.fee-summary .amount .fee-fiat.positive {
color: #70955F; }
.fee-summary .amount .fee-fiat.negative {
color: #C24633; }
.fee-summary .amount .fee-fiat {
display: inline; }
.fee-summary .amount .fee-fiat.positive {
color: #70955F; }
.fee-summary .amount .fee-fiat.negative {
color: #C24633; }
.fee-summary .amount .fee-crypto {
color: #A7A7A7; }
color: #A7A7A7;
float: right; }
.formatted-amount {
display: inline-block; }
@ -15557,6 +15609,9 @@ ion-content.padded-bottom-cta-with-summary {
margin-left: 5px;
text-transform: uppercase; }
.wallet-balance-directive {
display: inline-block; }
/* This is for rules that don't yet have a home.
* Our goal is to delete this file. Search the regex: /class=".*CLASS.*?"/
*/

View file

@ -6,7 +6,14 @@
</div>
<div ng-show="!hide">
<div ng-repeat="service in services track by $index">
<a ui-sref="{{service.sref}}" id="home_{{service.name}}" title="{{service.title || service.name}}" class="track_link_click_out item item-sub item-icon-left item-big-icon-left item-icon-right next-step">
<a ng-if="service.sref" ui-sref="{{service.sref}}" id="home_{{service.name}}" title="{{service.title || service.name}}" class="track_link_click_out item item-sub item-icon-left item-big-icon-left item-icon-right next-step">
<i class="icon big-icon-svg theme-circle theme-circle-services">
<div class="bg {{service.icon}}"></div>
</i>
<span>{{service.title || service.name}}</span>
<i class="icon bp-arrow-right"></i>
</a>
<a ng-if="!service.sref" ng-click="open('{{service.href}}')" id="home_{{service.name}}" title="{{service.title || service.name}}" class="track_link_click_out item item-sub item-icon-left item-big-icon-left item-icon-right next-step">
<i class="icon big-icon-svg theme-circle theme-circle-services">
<div class="bg {{service.icon}}"></div>
</i>

View file

@ -18,13 +18,12 @@
<h2>{{fromWallet.name}}</h2>
<wallet-balance
display-as-fiat="{{displayBalanceAsFiat}}"
wallet-coin="{{fromWallet.coin}}"
wallet-status="{{fromWallet.status}}"
wallet-cached-balance="{{fromWallet.cachedBalance}}"
wallet-cached-balance-updated-on="{{fromWallet.cachedBalanceUpdatedOn}}"
wallet-cached-status="{{fromWallet.cachedStatus}}"
total-balance-sat="{{fromWallet.status.totalBalanceSat}}"></wallet-balance>
<!--<p ng-show="vm.origin.balanceAmount">{{vm.origin.balanceAmount}} {{vm.origin.balanceCurrency}}</p>-->
<!--<formatted-amount value="{{fromWallet.status.totalBalanceStr ? fromWallet.status.totalBalanceStr : ( fromWallet.cachedBalance ? fromWallet.cachedBalance + (fromWallet.cachedBalanceUpdatedOn ? ' &middot; ' + ( fromWallet.cachedBalanceUpdatedOn * 1000 | amTimeAgo) : '') : '' ) }}"></formatted-amount>-->
</div>
</div>
</div>

View file

@ -13,7 +13,7 @@
<div class="header--request__amount-alt" ng-show="requestAmountSecondary" translate>{{requestAmountSecondary}} {{requestCurrencySecondary}}</div>
</div>
<div class="wallets-header">
<div class="title">
<div class="title" ng-if="walletsBch.length > 0 || walletsBtc.length > 0 || walletsInsufficientFunds.length > 0">
{{headerTitle}}
</div>
</div>