Merge https://github.com/bitpay/copay into copay-cash
|
|
@ -1,13 +1,3 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# http://editorconfig.org
|
||||
|
||||
## Plugins
|
||||
# Atom (https://github.com/sindresorhus/atom-editorconfig)
|
||||
# Vim (https://github.com/editorconfig/editorconfig-vim)
|
||||
# Sublime (https://github.com/sindresorhus/editorconfig-sublime)
|
||||
;
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
|
|
@ -27,4 +17,3 @@ indent_style = tab
|
|||
[**.html]
|
||||
max_char = 78
|
||||
brace_style = expand
|
||||
|
||||
|
|
|
|||
3
.gitignore
vendored
|
|
@ -3,6 +3,9 @@ i18n/po/*.mo
|
|||
i18n/crowdin_api_key.txt
|
||||
src/js/translations.js
|
||||
|
||||
package-lock.json
|
||||
|
||||
|
||||
# cordova
|
||||
plugins
|
||||
platforms
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ module.exports = function(grunt) {
|
|||
grunt.registerTask('desktop', ['prod', 'nwjs', 'copy:linux', 'compress:linux']);
|
||||
grunt.registerTask('osx', ['prod', 'nwjs', 'exec:macos', 'exec:osxsign']);
|
||||
grunt.registerTask('osx-debug', ['default', 'nwjs']);
|
||||
grunt.registerTask('chrome', ['exec:chrome']);
|
||||
grunt.registerTask('chrome', ['default','exec:chrome']);
|
||||
grunt.registerTask('wp', ['prod', 'exec:wp']);
|
||||
grunt.registerTask('wp-copy', ['default', 'exec:wpcopy']);
|
||||
grunt.registerTask('wp-init', ['default', 'exec:wpinit']);
|
||||
|
|
|
|||
4
angular-bitcore-wallet-client/index.js
vendored
|
|
@ -13,6 +13,10 @@ bwcModule.provider("bwcService", function() {
|
|||
return Client.Bitcore;
|
||||
};
|
||||
|
||||
service.getBitcoreCash = function() {
|
||||
return Client.BitcoreCash;
|
||||
};
|
||||
|
||||
service.getErrors = function() {
|
||||
return Client.errors;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
"windowsAppId": "2d1002d7-ee34-4f60-bd29-0c871ba0c195",
|
||||
"pushSenderId": "1036948132229",
|
||||
"description": "Secure Bitcoin Wallet",
|
||||
"version": "3.7.1",
|
||||
"androidVersion": "371000",
|
||||
"version": "3.8.2",
|
||||
"androidVersion": "382001",
|
||||
"_extraCSS": null,
|
||||
"_enabledExtensions": {
|
||||
"coinbase": true,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
<plugin name="cordova-plugin-customurlscheme" spec="https://github.com/cmgustavo/Custom-URL-scheme.git">
|
||||
<variable name="URL_SCHEME" value="bitcoin" />
|
||||
<variable name="SECOND_URL_SCHEME" value="*APPURI*" />
|
||||
<variable name="THIRD_URL_SCHEME" value="bitcoincash" />
|
||||
</plugin>
|
||||
<plugin name="cordova-custom-config" spec="~3.0.5" />
|
||||
<plugin name="cordova-plugin-queries-schemes" spec="~0.1.5" />
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@
|
|||
"windowsAppId": "804636ee-b017-4cad-8719-e58ac97ffa5c",
|
||||
"pushSenderId": "1036948132229",
|
||||
"description": "A Secure Bitcoin Wallet",
|
||||
"version": "3.7.1",
|
||||
"androidVersion": "371000",
|
||||
"version": "3.8.2",
|
||||
"androidVersion": "382001",
|
||||
"_extraCSS": null,
|
||||
"_enabledExtensions": {
|
||||
"coinbase": true,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "*PACKAGENAME*",
|
||||
"description": "*DESCRIPTION*",
|
||||
"author": "Bitcoin.com",
|
||||
"author": "BitPay",
|
||||
"version": "*VERSION*",
|
||||
"keywords": [
|
||||
"bitcoin",
|
||||
|
|
@ -54,9 +54,9 @@
|
|||
"angular": "1.4.6",
|
||||
"angular-mocks": "1.4.10",
|
||||
"bezier-easing": "^2.0.3",
|
||||
"bhttp": "^1.2.1",
|
||||
"bhttp": "1.2.1",
|
||||
"bitauth": "^0.2.1",
|
||||
"bitcore-wallet-client": "5.3.0",
|
||||
"bitcore-wallet-client": "6.2.1",
|
||||
"bower": "^1.7.9",
|
||||
"cordova-android": "5.1.1",
|
||||
"cordova-custom-config": "^3.0.5",
|
||||
|
|
@ -107,10 +107,9 @@
|
|||
"run:android": "cordova run android --device",
|
||||
"run:android-release": "cordova run android --device --release",
|
||||
"log:android": "adb logcat | grep chromium",
|
||||
"sign:android": "rm -f platforms/android/build/outputs/apk/android-release-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../copay.keystore -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk bitcoin-com && ../android-sdk-macosx/build-tools/25.0.3/zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-signed-aligned.apk",
|
||||
"sign:android": "rm -f platforms/android/build/outputs/apk/android-release-signed-aligned.apk; jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore ../copay.keystore -signedjar platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-unsigned.apk copay_play && $ANDROID_HOME/build-tools/26.0.1/zipalign -v 4 platforms/android/build/outputs/apk/android-release-signed.apk platforms/android/build/outputs/apk/android-release-signed-aligned.apk",
|
||||
"apply:copay": "npm i fs-extra && cd app-template && node apply.js copay && npm i && cordova prepare",
|
||||
"apply:bitpay": "npm i fs-extra && cd app-template && node apply.js bitpay && npm i && cordova prepare",
|
||||
"apply:bitcoincom": "npm i fs-extra && cd app-template && node apply.js bitcoincom && npm i && cordova prepare",
|
||||
"test": "echo \"no package tests configured\"",
|
||||
"clean": "trash platforms && trash plugins && cordova prepare",
|
||||
"unstage-package": "git reset package.json",
|
||||
|
|
@ -119,9 +118,9 @@
|
|||
"devDependencies": {
|
||||
"cordova": "^6.3.1",
|
||||
"grunt": "^1.0.1",
|
||||
"ionic": "^2.1.0",
|
||||
"ionic": "^3.6.0",
|
||||
"trash-cli": "^1.4.0",
|
||||
"lodash": "^4.3.0",
|
||||
"lodash": "^4.17.4",
|
||||
"pre-commit": "^1.1.3"
|
||||
},
|
||||
"pre-commit": "unstage-package"
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"moment": "2.10.3",
|
||||
"ng-lodash": "0.2.3",
|
||||
"qrcode-decoder-js": "*",
|
||||
"trezor-connect": "*",
|
||||
"trezor-connect": "https://github.com/trezor/connect.git#c1a00f9f0f4a13239ba13ddd589c6ca61f2e7876",
|
||||
"ng-csv": "~0.3.6",
|
||||
"ionic-toast": "^0.4.1",
|
||||
"angular-clipboard": "^1.4.2",
|
||||
|
|
|
|||
23
i18n/docs/appstore_nl.txt
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Beveilig bitcoin op je eigen voorwaarden met een open source, meervoudige ondertekening-portemonnee van BitPay.
|
||||
Copay gebruikers kunnen individueel saldo beheren of veilig financiën delen met andere gebruikers door middel van portemonnees met meervoudige ondertekening, dit voorkomt ongeautoriseerde betalingen doordat meerdere goedkeuringen nodig zijn. Hier zijn een aantal manieren waarop Copay gebruikt kan worden met anderen:
|
||||
|
||||
Om te sparen voor vakanties of gezamenlijke aankopen met vrienden
|
||||
Voor het bijhouden van de familieuitgaven en zakgeld
|
||||
Voor het beheer van het saldo en de uitgaven van een bedrijf, club of organisatie
|
||||
|
||||
We hebben de volgende functies ingebouwd in deze versie van Copay voor een bitcoin portemonnee die niet inlevert op beveiliging of toegankelijkheid:
|
||||
|
||||
Het aanmaken en beheren van meerdere portemonnees binnen de app
|
||||
Intuïtieve meervoudige-ondertekening beveiliging voor persoonlijke of gedeelde portemonnees
|
||||
Eenvoudige bestedingsvoorstellen voor gedeelde portemonnees en groepsbetalingen
|
||||
Hiërarchisch deterministische (HD) adres generatie en portemonnee backups
|
||||
Apparaat gebaseerde beveiliging: alle privé sleutels worden lokaal opgeslagen, niet in de cloud
|
||||
Ondersteuning voor Bitcoin testnet portemonnees
|
||||
Gesynchroniseerde toegang vanaf alle grote mobiele en desktop platformen
|
||||
Ondersteuning voor betalings protocol (BIP70-BIP73): gemakkelijk te herkennen betalingsverzoeken en verifieerbaar veilige bitcoin betalingen
|
||||
Ondersteuning voor prijsweergave in 150+ valuta's en eenheid denominatie in BTC of bits
|
||||
Email meldingen voor betalingen en overdrachten
|
||||
Aanpasbare portemonnee namen en achtergrond kleuren
|
||||
10 ondersteunde talen (EN, CZ, FR, DE, IT, ES, JA, PL, RU, NL)
|
||||
|
||||
Copay is gratis open source software draaiend op niet-merkgebonden servers, dus het is niet nodig te vertrouwen op enig bedrijf voor blijvende ondersteuning. Iedereen kan de broncode van Copay inzien of er aan bijdragen via GitHub (https://github.com/bitpay/copay).
|
||||
0
i18n/docs/updateinfo_nl.txt
Normal file
1115
i18n/po/de.po
1121
i18n/po/es.po
1131
i18n/po/fr.po
1239
i18n/po/it.po
1205
i18n/po/ja.po
3630
i18n/po/nl.po
Normal file
1203
i18n/po/pl.po
1197
i18n/po/pt.po
1163
i18n/po/ru.po
1099
i18n/po/template.pot
1355
i18n/po/zh.po
|
|
@ -14,7 +14,7 @@ angular.module('copayApp.controllers').controller('addressbookAddController', fu
|
|||
$timeout(function() {
|
||||
var form = addressbookForm;
|
||||
if (data && form) {
|
||||
data = data.replace('bitcoin:', '');
|
||||
data = data.replace(/^bitcoin(cash)?:/, '');
|
||||
form.address.$setViewValue(data);
|
||||
form.address.$isValid = true;
|
||||
form.address.$render();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, $state, $timeout, $stateParams, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog) {
|
||||
angular.module('copayApp.controllers').controller('addressbookViewController', function($scope, $state, $timeout, lodash, addressbookService, popupService, $ionicHistory, platformInfo, gettextCatalog, bitcoreCash) {
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
$scope.addressbookEntry = {};
|
||||
$scope.addressbookEntry.name = $stateParams.name;
|
||||
$scope.addressbookEntry.email = $stateParams.email;
|
||||
$scope.addressbookEntry.address = $stateParams.address;
|
||||
var coin;
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.addressbookEntry = {};
|
||||
$scope.addressbookEntry.name = data.stateParams.name;
|
||||
$scope.addressbookEntry.email = data.stateParams.email;
|
||||
$scope.addressbookEntry.address = data.stateParams.address;
|
||||
|
||||
var cashAddress = bitcoreCash.Address.isValid($scope.addressbookEntry.address, 'livenet');
|
||||
if (cashAddress) {
|
||||
coin = 'bch';
|
||||
} else {
|
||||
coin = 'btc';
|
||||
}
|
||||
});
|
||||
|
||||
$scope.sendTo = function() {
|
||||
$ionicHistory.removeBackView();
|
||||
|
|
@ -14,7 +26,8 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
|
|||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: $scope.addressbookEntry.address,
|
||||
toName: $scope.addressbookEntry.name,
|
||||
toEmail: $scope.addressbookEntry.email
|
||||
toEmail: $scope.addressbookEntry.email,
|
||||
coin: coin
|
||||
});
|
||||
}, 100);
|
||||
};
|
||||
|
|
@ -31,7 +44,7 @@ angular.module('copayApp.controllers').controller('addressbookViewController', f
|
|||
}
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, configService, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) {
|
||||
angular.module('copayApp.controllers').controller('addressesController', function($scope, $log, $stateParams, $state, $timeout, $ionicHistory, $ionicScrollDelegate, popupService, gettextCatalog, ongoingProcess, lodash, profileService, walletService, bwcError, platformInfo, appConfigService, txFormatService, feeService) {
|
||||
var UNUSED_ADDRESS_LIMIT = 5;
|
||||
var BALANCE_ADDRESS_LIMIT = 5;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var unitName = config.unitName;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
var satToUnit = 1 / unitToSatoshi;
|
||||
var unitDecimals = config.unitDecimals;
|
||||
var withBalance, cachedWallet;
|
||||
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
|
|
@ -55,7 +50,7 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
$scope.latestWithBalance = lodash.slice(withBalance, 0, BALANCE_ADDRESS_LIMIT);
|
||||
|
||||
lodash.each(withBalance, function(a) {
|
||||
a.balanceStr = txFormatService.formatAmount(a.amount);
|
||||
a.balanceStr = txFormatService.formatAmountStr($scope.wallet.coin, a.amount);
|
||||
});
|
||||
|
||||
$scope.viewAll = {
|
||||
|
|
@ -75,11 +70,11 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
|
||||
|
||||
|
||||
feeService.getFeeLevels(function(err, levels){
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels){
|
||||
walletService.getLowUtxos($scope.wallet, levels, function(err, resp) {
|
||||
if (err) return;
|
||||
|
||||
if (resp.allUtxos && resp.allUtxos.length) {
|
||||
if (resp && resp.allUtxos && resp.allUtxos.length) {
|
||||
|
||||
|
||||
var allSum = lodash.sum(resp.allUtxos || 0, 'satoshis');
|
||||
|
|
@ -88,9 +83,9 @@ angular.module('copayApp.controllers').controller('addressesController', functio
|
|||
$scope.lowWarning = resp.warning;
|
||||
$scope.lowUtxosNb = resp.lowUtxos.length;
|
||||
$scope.allUtxosNb = resp.allUtxos.length;
|
||||
$scope.lowUtxosSum = txFormatService.formatAmountStr(lodash.sum(resp.lowUtxos || 0, 'satoshis'));
|
||||
$scope.allUtxosSum = txFormatService.formatAmountStr(allSum);
|
||||
$scope.minFee = txFormatService.formatAmountStr(resp.minFee || 0);
|
||||
$scope.lowUtxosSum = txFormatService.formatAmountStr($scope.wallet.coin, lodash.sum(resp.lowUtxos || 0, 'satoshis'));
|
||||
$scope.allUtxosSum = txFormatService.formatAmountStr($scope.wallet.coin, allSum);
|
||||
$scope.minFee = txFormatService.formatAmountStr($scope.wallet.coin, resp.minFee || 0);
|
||||
$scope.minFeePer = per.toFixed(2) + '%';
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService, platformInfo) {
|
||||
angular.module('copayApp.controllers').controller('advancedSettingsController', function($scope, $log, configService, platformInfo, externalLinkService, gettextCatalog) {
|
||||
|
||||
var updateConfig = function() {
|
||||
var config = configService.getSync();
|
||||
|
|
@ -14,6 +14,7 @@ angular.module('copayApp.controllers').controller('advancedSettingsController',
|
|||
$scope.hideNextSteps = {
|
||||
value: config.hideNextSteps.enabled
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
$scope.spendUnconfirmedChange = function() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
var SMALL_FONT_SIZE_LIMIT = 10;
|
||||
var LENGTH_EXPRESSION_LIMIT = 19;
|
||||
var isNW = platformInfo.isNW;
|
||||
|
||||
var unitIndex = 0;
|
||||
var altUnitIndex = 0;
|
||||
var availableUnits = [];
|
||||
var fiatCode;
|
||||
|
||||
var fixedUnit;
|
||||
|
||||
$scope.isChromeApp = platformInfo.isChromeApp;
|
||||
|
||||
$scope.$on('$ionicView.leave', function() {
|
||||
|
|
@ -16,19 +24,100 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
function setAvailableUnits() {
|
||||
|
||||
availableUnits = [];
|
||||
|
||||
var hasBTCWallets = profileService.getWallets({
|
||||
coin: 'btc'
|
||||
}).length;
|
||||
|
||||
if (hasBTCWallets) {
|
||||
availableUnits.push({
|
||||
name: 'Bitcoin',
|
||||
id: 'btc',
|
||||
shortName: 'BTC',
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var hasBCHWallets = profileService.getWallets({
|
||||
coin: 'bch'
|
||||
}).length;
|
||||
|
||||
|
||||
|
||||
if (hasBCHWallets) {
|
||||
availableUnits.push({
|
||||
name: 'Bitcoin Cash',
|
||||
id: 'bch',
|
||||
shortName: 'BCH',
|
||||
});
|
||||
};
|
||||
|
||||
unitIndex = 0;
|
||||
|
||||
if (data.stateParams.coin) {
|
||||
var coins = data.stateParams.coin.split(',');
|
||||
var newAvailableUnits = [];
|
||||
|
||||
lodash.each(coins, function(c) {
|
||||
var coin = lodash.find(availableUnits, {
|
||||
id: c
|
||||
});
|
||||
if (!coin) {
|
||||
$log.warn('Could not find desired coin:' + data.stateParams.coin)
|
||||
} else {
|
||||
newAvailableUnits.push(coin);
|
||||
}
|
||||
});
|
||||
|
||||
if (newAvailableUnits.length > 0) {
|
||||
availableUnits = newAvailableUnits;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// currency have preference
|
||||
var fiatName;
|
||||
if (data.stateParams.currency) {
|
||||
fiatCode = data.stateParams.currency;
|
||||
altUnitIndex = unitIndex
|
||||
unitIndex = availableUnits.length;
|
||||
} else {
|
||||
fiatCode = config.alternativeIsoCode || 'USD';
|
||||
fiatName = config.alternanativeName || fiatCode;
|
||||
altUnitIndex = availableUnits.length;
|
||||
}
|
||||
|
||||
availableUnits.push({
|
||||
name: fiatName || fiatCode,
|
||||
// TODO
|
||||
id: fiatCode,
|
||||
shortName: fiatCode,
|
||||
isFiat: true,
|
||||
});
|
||||
|
||||
if (data.stateParams.fixedUnit) {
|
||||
fixedUnit = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Go to...
|
||||
_id = data.stateParams.id; // Optional (BitPay Card ID or Wallet ID)
|
||||
$scope.nextStep = data.stateParams.nextStep;
|
||||
$scope.currency = data.stateParams.currency;
|
||||
$scope.forceCurrency = data.stateParams.forceCurrency;
|
||||
|
||||
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' ||
|
||||
$ionicHistory.backView().stateName == 'tabs.bitpayCard');
|
||||
|
||||
setAvailableUnits();
|
||||
updateUnitUI();
|
||||
|
||||
$scope.showMenu = $ionicHistory.backView() && ($ionicHistory.backView().stateName == 'tabs.send' || $ionicHistory.backView().stateName == 'tabs.bitpayCard');
|
||||
$scope.recipientType = data.stateParams.recipientType || null;
|
||||
$scope.toAddress = data.stateParams.toAddress;
|
||||
$scope.toName = data.stateParams.toName;
|
||||
$scope.toEmail = data.stateParams.toEmail;
|
||||
$scope.showAlternativeAmount = !!$scope.nextStep;
|
||||
$scope.toColor = data.stateParams.toColor;
|
||||
$scope.showSendMax = false;
|
||||
|
||||
|
|
@ -52,23 +141,13 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
} else if (e.key.match(reOp)) {
|
||||
$scope.pushOperator(e.key);
|
||||
} else if (e.keyCode === 86) {
|
||||
if (e.ctrlKey || e.metaKey)
|
||||
processClipboard();
|
||||
} else if (e.keyCode === 13)
|
||||
$scope.finish();
|
||||
if (e.ctrlKey || e.metaKey) processClipboard();
|
||||
} else if (e.keyCode === 13) $scope.finish();
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
|
||||
var config = configService.getSync().wallet.settings;
|
||||
$scope.unitName = config.unitName;
|
||||
if (data.stateParams.currency) {
|
||||
$scope.alternativeIsoCode = data.stateParams.currency;
|
||||
} else {
|
||||
$scope.alternativeIsoCode = config.alternativeIsoCode || 'USD';
|
||||
}
|
||||
$scope.specificAmount = $scope.specificAlternativeAmount = '';
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
unitToSatoshi = config.unitToSatoshi;
|
||||
|
|
@ -114,16 +193,59 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.finish();
|
||||
};
|
||||
|
||||
$scope.toggleAlternative = function() {
|
||||
if ($scope.forceCurrency) return;
|
||||
$scope.showAlternativeAmount = !$scope.showAlternativeAmount;
|
||||
|
||||
$scope.toggleAlternative = function() {
|
||||
if ($scope.amount && isExpression($scope.amount)) {
|
||||
var amount = evaluate(format($scope.amount));
|
||||
$scope.globalResult = '= ' + processResult(amount);
|
||||
}
|
||||
};
|
||||
|
||||
function updateUnitUI() {
|
||||
$scope.unit = availableUnits[unitIndex].shortName;
|
||||
$scope.alternativeUnit = availableUnits[altUnitIndex].shortName;
|
||||
|
||||
processAmount();
|
||||
$log.debug('Update unit coin @amount unit:' + $scope.unit + " alternativeUnit:" + $scope.alternativeUnit);
|
||||
};
|
||||
|
||||
$scope.changeUnit = function() {
|
||||
if (fixedUnit) return;
|
||||
|
||||
unitIndex++;
|
||||
if (unitIndex >= availableUnits.length) unitIndex = 0;
|
||||
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
// Always return to BTC... TODO?
|
||||
altUnitIndex = 0;
|
||||
} else {
|
||||
altUnitIndex = lodash.findIndex(availableUnits, {
|
||||
isFiat: true
|
||||
});
|
||||
}
|
||||
|
||||
updateUnitUI();
|
||||
};
|
||||
|
||||
|
||||
$scope.changeAlternativeUnit = function() {
|
||||
|
||||
// Do nothing is fiat is not main unit
|
||||
if (!availableUnits[unitIndex].isFiat) return;
|
||||
|
||||
var nextCoin = lodash.findIndex(availableUnits, function(x) {
|
||||
if (x.isFiat) return false;
|
||||
if (x.id == availableUnits[altUnitIndex].id) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (nextCoin >= 0) {
|
||||
altUnitIndex = nextCoin;
|
||||
updateUnitUI();
|
||||
}
|
||||
};
|
||||
|
||||
function checkFontSize() {
|
||||
if ($scope.amount && $scope.amount.length >= SMALL_FONT_SIZE_LIMIT) $scope.smallFont = true;
|
||||
else $scope.smallFont = false;
|
||||
|
|
@ -132,7 +254,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.pushDigit = function(digit) {
|
||||
if ($scope.amount && $scope.amount.length >= LENGTH_EXPRESSION_LIMIT) return;
|
||||
if ($scope.amount.indexOf('.') > -1 && digit == '.') return;
|
||||
if ($scope.showAlternativeAmount && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;
|
||||
if (availableUnits[unitIndex].isFiat && $scope.amount.indexOf('.') > -1 && $scope.amount[$scope.amount.indexOf('.') + 2]) return;
|
||||
|
||||
$scope.amount = ($scope.amount + digit).replace('..', '.');
|
||||
checkFontSize();
|
||||
|
|
@ -169,7 +291,7 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
};
|
||||
|
||||
$scope.resetAmount = function() {
|
||||
$scope.amount = $scope.alternativeResult = $scope.amountResult = $scope.globalResult = '';
|
||||
$scope.amount = $scope.alternativeAmount = $scope.globalResult = '';
|
||||
$scope.allowSend = false;
|
||||
checkFontSize();
|
||||
};
|
||||
|
|
@ -180,24 +302,39 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
$scope.allowSend = lodash.isNumber(result) && +result > 0;
|
||||
if (lodash.isNumber(result)) {
|
||||
$scope.globalResult = isExpression($scope.amount) ? '= ' + processResult(result) : '';
|
||||
$scope.amountResult = $filter('formatFiatAmount')(toFiat(result));
|
||||
$scope.alternativeResult = txFormatService.formatAmount(fromFiat(result) * unitToSatoshi, true);
|
||||
|
||||
if (availableUnits[unitIndex].isFiat) {
|
||||
|
||||
var a = fromFiat(result);
|
||||
if (a) {
|
||||
$scope.alternativeAmount = txFormatService.formatAmount(a * unitToSatoshi, true);
|
||||
} else {
|
||||
if (result) {
|
||||
$scope.alternativeAmount = 'N/A';
|
||||
} else {
|
||||
$scope.alternativeAmount = null;
|
||||
}
|
||||
$scope.allowSend = false;
|
||||
}
|
||||
} else {
|
||||
$scope.alternativeAmount = $filter('formatFiatAmount')(toFiat(result));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function processResult(val) {
|
||||
if ($scope.showAlternativeAmount)
|
||||
return $filter('formatFiatAmount')(val);
|
||||
else
|
||||
return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
|
||||
if (availableUnits[unitIndex].isFiat) return $filter('formatFiatAmount')(val);
|
||||
else return txFormatService.formatAmount(val.toFixed(unitDecimals) * unitToSatoshi, true);
|
||||
};
|
||||
|
||||
function fromFiat(val) {
|
||||
return parseFloat((rateService.fromFiat(val, $scope.alternativeIsoCode) * satToUnit).toFixed(unitDecimals));
|
||||
return parseFloat((rateService.fromFiat(val, fiatCode, availableUnits[altUnitIndex].id) * satToUnit).toFixed(unitDecimals));
|
||||
};
|
||||
|
||||
function toFiat(val) {
|
||||
return parseFloat((rateService.toFiat(val * unitToSatoshi, $scope.alternativeIsoCode)).toFixed(2));
|
||||
if (!rateService.getRate(fiatCode)) return;
|
||||
|
||||
return parseFloat((rateService.toFiat(val * unitToSatoshi, fiatCode, availableUnits[unitIndex].id)).toFixed(2));
|
||||
};
|
||||
|
||||
function evaluate(val) {
|
||||
|
|
@ -212,33 +349,50 @@ angular.module('copayApp.controllers').controller('amountController', function($
|
|||
};
|
||||
|
||||
function format(val) {
|
||||
if (!val) return;
|
||||
|
||||
var result = val.toString();
|
||||
|
||||
if (isOperator(lodash.last(val)))
|
||||
result = result.slice(0, -1);
|
||||
if (isOperator(lodash.last(val))) result = result.slice(0, -1);
|
||||
|
||||
return result.replace('x', '*');
|
||||
};
|
||||
|
||||
$scope.finish = function() {
|
||||
|
||||
var unit = availableUnits[unitIndex];
|
||||
var _amount = evaluate(format($scope.amount));
|
||||
var coin = unit.id;
|
||||
if (unit.isFiat) {
|
||||
coin = availableUnits[altUnitIndex].id;
|
||||
}
|
||||
|
||||
if ($scope.nextStep) {
|
||||
|
||||
$state.transitionTo($scope.nextStep, {
|
||||
id: _id,
|
||||
amount: $scope.useSendMax ? null : _amount,
|
||||
currency: $scope.showAlternativeAmount ? $scope.alternativeIsoCode : $scope.unitName,
|
||||
currency: unit.id.toUpperCase(),
|
||||
coin: coin,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
} else {
|
||||
var amount = $scope.showAlternativeAmount ? fromFiat(_amount) : _amount;
|
||||
var amount = _amount;
|
||||
|
||||
if (unit.isFiat) {
|
||||
amount = (fromFiat(amount) * unitToSatoshi).toFixed(0);
|
||||
} else {
|
||||
amount = (amount * unitToSatoshi).toFixed(0);
|
||||
}
|
||||
|
||||
$state.transitionTo('tabs.send.confirm', {
|
||||
recipientType: $scope.recipientType,
|
||||
toAmount: $scope.useSendMax ? null : (amount * unitToSatoshi).toFixed(0),
|
||||
toAmount: amount,
|
||||
toAddress: $scope.toAddress,
|
||||
toName: $scope.toName,
|
||||
toEmail: $scope.toEmail,
|
||||
toColor: $scope.toColor,
|
||||
coin: coin,
|
||||
useSendMax: $scope.useSendMax
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyAmazonController', function($scope, $log, $state, $timeout, $filter, $ionicHistory, $ionicConfig, lodash, amazonService, popupService, profileService, ongoingProcess, configService, walletService, payproService, bwcError, externalLinkService, platformInfo, gettextCatalog, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
var createdTx;
|
||||
|
|
@ -64,7 +65,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(sat, $scope.currencyIsoCode, function(value) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
|
@ -216,8 +217,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
});
|
||||
|
||||
var initialize = function(wallet) {
|
||||
var parsedAmount = txFormatService.parseAmount(amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.alternativeIsoCode;
|
||||
var parsedAmount = txFormatService.parseAmount(coin, amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
var dataSrc = {
|
||||
amount: parsedAmount.amount,
|
||||
|
|
@ -260,7 +261,7 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
invoiceUrl: invoice.url,
|
||||
invoiceTime: invoice.invoiceTime
|
||||
};
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount);
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
});
|
||||
});
|
||||
|
|
@ -292,7 +293,8 @@ angular.module('copayApp.controllers').controller('buyAmazonController', functio
|
|||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('No wallets available'));
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -33,6 +34,52 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
}
|
||||
};
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
|
||||
coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) {
|
||||
$scope.buyPrice = b.data || null;
|
||||
});
|
||||
|
||||
$scope.paymentMethods = [];
|
||||
$scope.selectedPaymentMethodId = { value : null };
|
||||
coinbaseService.getPaymentMethods(accessToken, function(err, p) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var hasPrimary;
|
||||
var pm;
|
||||
for(var i = 0; i < p.data.length; i++) {
|
||||
pm = p.data[i];
|
||||
if (pm.allow_buy) {
|
||||
$scope.paymentMethods.push(pm);
|
||||
}
|
||||
if (pm.allow_buy && pm.primary_buy) {
|
||||
hasPrimary = true;
|
||||
$scope.selectedPaymentMethodId.value = pm.id;
|
||||
}
|
||||
}
|
||||
if (lodash.isEmpty($scope.paymentMethods)) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack('No payment method available to buy');
|
||||
return;
|
||||
}
|
||||
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
|
||||
$scope.buyRequest();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
|
@ -42,81 +89,22 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
$scope.isFiat = data.stateParams.currency != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
// Buy always in BTC
|
||||
amount = (parsedAmount.amountSat / 100000000).toFixed(8);
|
||||
currency = 'BTC';
|
||||
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
ongoingProcess.set('calculatingFee', true);
|
||||
coinbaseService.checkEnoughFundsForFee(amount, function(err) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
if (err) {
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
|
||||
coinbaseService.buyPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, b) {
|
||||
$scope.buyPrice = b.data || null;
|
||||
});
|
||||
|
||||
$scope.paymentMethods = [];
|
||||
$scope.selectedPaymentMethodId = { value : null };
|
||||
coinbaseService.getPaymentMethods(accessToken, function(err, p) {
|
||||
if (err) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
var hasPrimary;
|
||||
var pm;
|
||||
for(var i = 0; i < p.data.length; i++) {
|
||||
pm = p.data[i];
|
||||
if (pm.allow_buy) {
|
||||
$scope.paymentMethods.push(pm);
|
||||
}
|
||||
if (pm.allow_buy && pm.primary_buy) {
|
||||
hasPrimary = true;
|
||||
$scope.selectedPaymentMethodId.value = pm.id;
|
||||
}
|
||||
}
|
||||
if (lodash.isEmpty($scope.paymentMethods)) {
|
||||
ongoingProcess.set('connectingCoinbase', false);
|
||||
showErrorAndBack('No payment method available to buy');
|
||||
return;
|
||||
}
|
||||
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
|
||||
$scope.buyRequest();
|
||||
});
|
||||
});
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.buyRequest = function() {
|
||||
|
|
@ -209,21 +197,31 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
});
|
||||
};
|
||||
|
||||
var _processBuyOrder = function() {
|
||||
coinbaseService.getBuyOrder(accessToken, accountId, b.data.id, function (err, buyResp) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var tx = buyResp.data ? buyResp.data.transaction : null;
|
||||
if (tx && tx.id) {
|
||||
processBuyTx(tx);
|
||||
} else {
|
||||
$timeout(function() {
|
||||
_processBuyOrder();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$timeout(function() {
|
||||
var tx = b.data ? b.data.transaction : null;
|
||||
if (tx) {
|
||||
if (tx && tx.id) {
|
||||
processBuyTx(tx);
|
||||
}
|
||||
else {
|
||||
coinbaseService.getBuyOrder(accessToken, accountId, b.data.id, function (err, buyResp) {
|
||||
if (err) {
|
||||
ongoingProcess.set('buyingBitcoin', false, statusChangeHandler);
|
||||
showError(err);
|
||||
return;
|
||||
}
|
||||
var tx = buyResp.data ? buyResp.data.transaction : null;
|
||||
processBuyTx(tx);
|
||||
});
|
||||
_processBuyOrder();
|
||||
}
|
||||
}, 8000);
|
||||
});
|
||||
|
|
@ -238,6 +236,25 @@ angular.module('copayApp.controllers').controller('buyCoinbaseController', funct
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
// Buy always in BTC
|
||||
amount = (parsedAmount.amountSat / 100000000).toFixed(8);
|
||||
currency = 'BTC';
|
||||
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
ongoingProcess.set('calculatingFee', true);
|
||||
coinbaseService.checkEnoughFundsForFee(amount, function(err) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
if (err) {
|
||||
showErrorAndBack(err);
|
||||
return;
|
||||
}
|
||||
processPaymentInfo();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('buyGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, platformInfo, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -35,36 +36,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
$scope.network = glideraService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
glideraService.init(function(err, data) {
|
||||
if (err) {
|
||||
|
|
@ -88,6 +60,33 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
$scope.buyInfo = buy;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
$scope.network = glideraService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('No wallets available');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
var ask2FaCode = function(mode, cb) {
|
||||
|
|
@ -105,7 +104,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
popupService.showPrompt(title, message, null, function(twoFaCode) {
|
||||
if (typeof twoFaCode == 'undefined') return cb();
|
||||
return cb(twoFaCode);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb();
|
||||
}
|
||||
|
|
@ -116,7 +115,7 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
var okText = 'Confirm';
|
||||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
if (!ok) return;
|
||||
ongoingProcess.set('buyingBitcoin', true, statusChangeHandler);
|
||||
glideraService.get2faCode($scope.token, function(err, tfa) {
|
||||
if (err) {
|
||||
|
|
@ -162,6 +161,15 @@ angular.module('copayApp.controllers').controller('buyGlideraController', functi
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
354
src/js/controllers/buyMercadoLibre.js
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('buyMercadoLibreController', function($scope, $log, $state, $timeout, $filter, $ionicHistory, $ionicConfig, lodash, mercadoLibreService, popupService, profileService, ongoingProcess, configService, walletService, payproService, bwcError, externalLinkService, platformInfo, txFormatService, gettextCatalog) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
var createdTx;
|
||||
var message;
|
||||
var invoiceId;
|
||||
var configWallet = configService.getSync().wallet;
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var _resetValues = function() {
|
||||
$scope.totalAmountStr = $scope.amount = $scope.invoiceFee = $scope.networkFee = $scope.totalAmount = $scope.wallet = null;
|
||||
createdTx = message = invoiceId = null;
|
||||
};
|
||||
|
||||
var showErrorAndBack = function(title, msg) {
|
||||
title = title || gettextCatalog.getString('Error');
|
||||
$scope.sendStatus = '';
|
||||
$log.error(msg);
|
||||
msg = (msg && msg.errors) ? msg.errors[0].message : msg;
|
||||
popupService.showAlert(title, msg, function() {
|
||||
$ionicHistory.goBack();
|
||||
});
|
||||
};
|
||||
|
||||
var showError = function(title, msg, cb) {
|
||||
cb = cb || function() {};
|
||||
title = title || gettextCatalog.getString('Error');
|
||||
$scope.sendStatus = '';
|
||||
$log.error(msg);
|
||||
msg = (msg && msg.errors) ? msg.errors[0].message : msg;
|
||||
popupService.showAlert(title, msg, cb);
|
||||
};
|
||||
|
||||
var publishAndSign = function(wallet, txp, onSendStatusChange, cb) {
|
||||
if (!wallet.canSign() && !wallet.isPrivKeyExternal()) {
|
||||
var err = 'No signing proposal: No private key';
|
||||
$log.info(err);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
walletService.publishAndSign(wallet, txp, function(err, txp) {
|
||||
if (err) return cb(err);
|
||||
return cb(null, txp);
|
||||
}, onSendStatusChange);
|
||||
};
|
||||
|
||||
var statusChangeHandler = function(processName, showName, isOn) {
|
||||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if (processName == 'Comprando Vale-Presente' && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
||||
var setTotalAmount = function(amountSat, invoiceFeeSat, networkFeeSat) {
|
||||
satToFiat(amountSat, function(a) {
|
||||
$scope.amount = Number(a);
|
||||
|
||||
satToFiat(invoiceFeeSat, function(i) {
|
||||
$scope.invoiceFee = Number(i);
|
||||
|
||||
satToFiat(networkFeeSat, function(n) {
|
||||
$scope.networkFee = Number(n);
|
||||
$scope.totalAmount = $scope.amount + $scope.invoiceFee + $scope.networkFee;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createInvoice = function(data, cb) {
|
||||
mercadoLibreService.createBitPayInvoice(data, function(err, dataInvoice) {
|
||||
if (err) {
|
||||
var err_title = gettextCatalog.getString('Error creating the invoice');
|
||||
var err_msg;
|
||||
if (err && err.message && err.message.match(/suspended/i)) {
|
||||
err_title = gettextCatalog.getString('Service not available');
|
||||
err_msg = gettextCatalog.getString('Mercadolibre Gift Card Service is not available at this moment. Please try back later.');
|
||||
} else if (err && err.message) {
|
||||
err_msg = err.message;
|
||||
} else {
|
||||
err_msg = gettextCatalog.getString('Could not access Gift Card Service');
|
||||
};
|
||||
|
||||
return cb({
|
||||
title: err_title,
|
||||
message: err_msg
|
||||
});
|
||||
}
|
||||
|
||||
var accessKey = dataInvoice ? dataInvoice.accessKey : null;
|
||||
|
||||
if (!accessKey) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString('No access key defined')
|
||||
});
|
||||
}
|
||||
|
||||
mercadoLibreService.getBitPayInvoice(dataInvoice.invoiceId, function(err, invoice) {
|
||||
if (err) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString('Could not get the invoice')
|
||||
});
|
||||
}
|
||||
|
||||
return cb(null, invoice, accessKey);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createTx = function(wallet, invoice, message, cb) {
|
||||
var payProUrl = (invoice && invoice.paymentUrls) ? invoice.paymentUrls.BIP73 : null;
|
||||
|
||||
if (!payProUrl) {
|
||||
return cb({
|
||||
title: gettextCatalog.getString('Error in Payment Protocol'),
|
||||
message: gettextCatalog.getString('Invalid URL')
|
||||
});
|
||||
}
|
||||
|
||||
var outputs = [];
|
||||
var toAddress = invoice.bitcoinAddress;
|
||||
var amountSat = parseInt((invoice.btcDue * 100000000).toFixed(0)); // BTC to Satoshi
|
||||
|
||||
outputs.push({
|
||||
'toAddress': toAddress,
|
||||
'amount': amountSat,
|
||||
'message': message
|
||||
});
|
||||
|
||||
var txp = {
|
||||
toAddress: toAddress,
|
||||
amount: amountSat,
|
||||
outputs: outputs,
|
||||
message: message,
|
||||
payProUrl: payProUrl,
|
||||
excludeUnconfirmedUtxos: configWallet.spendUnconfirmed ? false : true,
|
||||
feeLevel: configWallet.settings.feeLevel || 'normal'
|
||||
};
|
||||
|
||||
walletService.createTx(wallet, txp, function(err, ctxp) {
|
||||
if (err) {
|
||||
return cb({
|
||||
title: gettextCatalog.getString('Could not create transaction'),
|
||||
message: bwcError.msg(err)
|
||||
});
|
||||
}
|
||||
return cb(null, ctxp);
|
||||
});
|
||||
};
|
||||
|
||||
var checkTransaction = lodash.throttle(function(count, dataSrc) {
|
||||
mercadoLibreService.createGiftCard(dataSrc, function(err, giftCard) {
|
||||
$log.debug("creating gift card " + count);
|
||||
if (err) {
|
||||
$scope.sendStatus = '';
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
giftCard = {};
|
||||
giftCard.status = 'FAILURE';
|
||||
}
|
||||
|
||||
if (giftCard && giftCard.cardStatus && (giftCard.cardStatus != 'active' && giftCard.cardStatus != 'inactive' && giftCard.cardStatus != 'expired')) {
|
||||
$scope.sendStatus = '';
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
giftCard = {};
|
||||
giftCard.status = 'FAILURE';
|
||||
}
|
||||
|
||||
|
||||
if (giftCard.status == 'PENDING' && count < 3) {
|
||||
$log.debug("Waiting for payment confirmation");
|
||||
checkTransaction(count + 1, dataSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
var now = moment().unix() * 1000;
|
||||
|
||||
var newData = giftCard;
|
||||
newData['invoiceId'] = dataSrc.invoiceId;
|
||||
newData['accessKey'] = dataSrc.accessKey;
|
||||
newData['invoiceUrl'] = dataSrc.invoiceUrl;
|
||||
newData['amount'] = dataSrc.amount;
|
||||
newData['currency'] = dataSrc.currency;
|
||||
newData['date'] = dataSrc.invoiceTime || now;
|
||||
newData['uuid'] = dataSrc.uuid;
|
||||
|
||||
mercadoLibreService.savePendingGiftCard(newData, null, function(err) {
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
$log.debug("Saving new gift card with status: " + newData.status);
|
||||
$scope.mlGiftCard = newData;
|
||||
});
|
||||
});
|
||||
}, 8000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
var initialize = function(wallet) {
|
||||
var parsedAmount = txFormatService.parseAmount(coin, amount, currency);
|
||||
$scope.currencyIsoCode = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
var dataSrc = {
|
||||
amount: parsedAmount.amount,
|
||||
currency: parsedAmount.currency,
|
||||
uuid: wallet.id
|
||||
};
|
||||
ongoingProcess.set('loadingTxInfo', true);
|
||||
createInvoice(dataSrc, function(err, invoice, accessKey) {
|
||||
if (err) {
|
||||
ongoingProcess.set('loadingTxInfo', false);
|
||||
showErrorAndBack(err.title, err.message);
|
||||
return;
|
||||
}
|
||||
// Sometimes API does not return this element;
|
||||
invoice['buyerPaidBtcMinerFee'] = invoice.buyerPaidBtcMinerFee || 0;
|
||||
var invoiceFeeSat = (invoice.buyerPaidBtcMinerFee * 100000000).toFixed();
|
||||
|
||||
message = gettextCatalog.getString("{{amountStr}} for Mercado Livre Brazil Gift Card", {
|
||||
amountStr: $scope.amountUnitStr
|
||||
});
|
||||
|
||||
createTx(wallet, invoice, message, function(err, ctxp) {
|
||||
ongoingProcess.set('loadingTxInfo', false);
|
||||
if (err) {
|
||||
_resetValues();
|
||||
showError(err.title, err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save in memory
|
||||
createdTx = ctxp;
|
||||
invoiceId = invoice.id;
|
||||
|
||||
createdTx['giftData'] = {
|
||||
currency: dataSrc.currency,
|
||||
amount: dataSrc.amount,
|
||||
uuid: dataSrc.uuid,
|
||||
accessKey: accessKey,
|
||||
invoiceId: invoice.id,
|
||||
invoiceUrl: invoice.url,
|
||||
invoiceTime: invoice.invoiceTime
|
||||
};
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
if (amount > 2000 || amount < 50) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('Purchase amount must be a value between 50 and 2000'));
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.network = mercadoLibreService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
coin: coin
|
||||
});
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack(null, gettextCatalog.getString('No wallets available'));
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.buyConfirm = function() {
|
||||
|
||||
if (!createdTx) {
|
||||
showError(null, gettextCatalog.getString('Transaction has not been created'));
|
||||
return;
|
||||
}
|
||||
|
||||
var title = gettextCatalog.getString('Confirm');
|
||||
var okText = gettextCatalog.getString('Ok');
|
||||
var cancelText = gettextCatalog.getString('Cancel');
|
||||
popupService.showConfirm(title, message, okText, cancelText, function(ok) {
|
||||
if (!ok) {
|
||||
$scope.sendStatus = '';
|
||||
return;
|
||||
}
|
||||
|
||||
ongoingProcess.set('Comprando Vale-Presente', true, statusChangeHandler);
|
||||
publishAndSign($scope.wallet, createdTx, function() {}, function(err, txSent) {
|
||||
if (err) {
|
||||
ongoingProcess.set('Comprando Vale-Presente', false, statusChangeHandler);
|
||||
showError(gettextCatalog.getString('Could not send transaction'), err);
|
||||
return;
|
||||
}
|
||||
checkTransaction(1, createdTx.giftData);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showWalletSelector = function() {
|
||||
$scope.walletSelectorTitle = 'Buy from';
|
||||
$scope.showWallets = true;
|
||||
};
|
||||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
initialize(wallet);
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
$scope.sendStatus = '';
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.home').then(function() {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true
|
||||
});
|
||||
$state.transitionTo('tabs.giftcards.mercadoLibre').then(function() {
|
||||
$state.transitionTo('tabs.giftcards.mercadoLibre.cards', {
|
||||
invoiceId: invoiceId
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
});
|
||||
192
src/js/controllers/cashScan.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('cashScanController',
|
||||
function($rootScope, $timeout, $scope, $state, $ionicHistory, gettextCatalog, lodash, ongoingProcess, profileService, walletService, $log, txFormatService, bwcError, pushNotificationsService, bwcService, externalLinkService) {
|
||||
var wallet;
|
||||
var errors = bwcService.getErrors();
|
||||
$scope.error = null;
|
||||
$scope.walletDisabled = '#667';
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
updateAllWallets();
|
||||
});
|
||||
|
||||
$scope.openRecoveryToolLink = function() {
|
||||
var url = 'https://bitpay.github.io/copay-recovery/';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Open the recovery tool.');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
var goHome = function() {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$ionicHistory.clearHistory();
|
||||
$state.go('tabs.settings').then(function() {
|
||||
$state.transitionTo('tabs.home');
|
||||
});
|
||||
}
|
||||
|
||||
var updateAllWallets = function() {
|
||||
var walletsBTC = profileService.getWallets({
|
||||
coin: 'btc',
|
||||
onlyComplete: true,
|
||||
network: 'livenet'
|
||||
});
|
||||
|
||||
// Filter out already duplicated wallets
|
||||
var walletsBCH = profileService.getWallets({
|
||||
coin: 'bch',
|
||||
network: 'livenet'
|
||||
});
|
||||
var xPubKeyIndex = lodash.indexBy(walletsBCH, "credentials.xPubKey");
|
||||
|
||||
walletsBTC = lodash.filter(walletsBTC, function(w) {
|
||||
return !xPubKeyIndex[w.credentials.xPubKey];
|
||||
});
|
||||
|
||||
var availableWallets = [];
|
||||
var nonEligibleWallets = [];
|
||||
|
||||
lodash.each(walletsBTC, function(w) {
|
||||
if (w.credentials.derivationStrategy != 'BIP44') {
|
||||
w.excludeReason = gettextCatalog.getString('Non BIP44 wallet');
|
||||
nonEligibleWallets.push(w);
|
||||
} else if (!w.canSign()) {
|
||||
w.excludeReason = gettextCatalog.getString('Read only wallet');
|
||||
nonEligibleWallets.push(w);
|
||||
} else if (w.needsBackup) {
|
||||
w.excludeReason = gettextCatalog.getString('Backup needed');
|
||||
nonEligibleWallets.push(w);
|
||||
} else {
|
||||
availableWallets.push(w);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.availableWallets = availableWallets;
|
||||
$scope.nonEligibleWallets = nonEligibleWallets;
|
||||
|
||||
var i = availableWallets.length;
|
||||
var j = 0;
|
||||
lodash.each(availableWallets, function(wallet) {
|
||||
walletService.getBalance(wallet, {
|
||||
coin: 'bch'
|
||||
}, function(err, balance) {
|
||||
if (err) {
|
||||
wallet.error = (err === 'WALLET_NOT_REGISTERED') ? gettextCatalog.getString('Wallet not registered') : bwcError.msg(err);
|
||||
$log.error(err);
|
||||
return;
|
||||
}
|
||||
|
||||
wallet.error = null;
|
||||
wallet.bchBalance = txFormatService.formatAmountStr('bch', balance.availableAmount);
|
||||
if (++j == i) {
|
||||
//Done
|
||||
$timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.duplicate = function(wallet) {
|
||||
$scope.error = null;
|
||||
$log.debug('Duplicating wallet for BCH:' + wallet.id + ':' + wallet.name);
|
||||
|
||||
var opts = {};
|
||||
opts.name = wallet.name + '[BCH]';
|
||||
opts.m = wallet.m;
|
||||
opts.n = wallet.n;
|
||||
opts.myName = wallet.credentials.copayerName;
|
||||
opts.networkName = wallet.network;
|
||||
opts.coin = 'bch';
|
||||
opts.walletPrivKey = wallet.credentials.walletPrivKey;
|
||||
opts.compliantDerivation = wallet.credentials.compliantDerivation;
|
||||
|
||||
|
||||
function setErr(err, cb) {
|
||||
|
||||
if (!cb) cb = function() {};
|
||||
|
||||
$scope.error = bwcError.cb(err, gettextCatalog.getString('Could not duplicate'), function() {
|
||||
return cb(err);
|
||||
});
|
||||
$timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function importOrCreate(cb) {
|
||||
walletService.getStatus(wallet, {}, function(err, status) {
|
||||
if (err) return cb(err);
|
||||
|
||||
opts.singleAddress = status.wallet.singleAddress;
|
||||
|
||||
// first try to import
|
||||
profileService.importExtendedPrivateKey(opts.extendedPrivateKey, opts, function(err, newWallet) {
|
||||
if (err && !(err instanceof errors.NOT_AUTHORIZED)) {
|
||||
return setErr(err, cb);
|
||||
}
|
||||
if (err) {
|
||||
// create and store a wallet
|
||||
return profileService.createWallet(opts, function(err, newWallet) {
|
||||
if (err) return setErr(err, cb);
|
||||
return cb(null, newWallet, true);
|
||||
});
|
||||
}
|
||||
return cb(null, newWallet);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Multisig wallets? add Copayers
|
||||
function addCopayers(newWallet, isNew, cb) {
|
||||
if (!isNew) return cb();
|
||||
if (wallet.n == 1) return cb();
|
||||
|
||||
$log.info('Adding copayers for BCH wallet config:' + wallet.m + '-' + wallet.n);
|
||||
|
||||
walletService.copyCopayers(wallet, newWallet, function(err) {
|
||||
if (err) return setErr(err, cb);
|
||||
|
||||
return cb();
|
||||
});
|
||||
};
|
||||
|
||||
walletService.getKeys(wallet, function(err, keys) {
|
||||
if (err) {
|
||||
$scope.error = err;
|
||||
return $timeout(function() {
|
||||
$rootScope.$apply();
|
||||
}, 10);
|
||||
}
|
||||
opts.extendedPrivateKey = keys.xPrivKey;
|
||||
ongoingProcess.set('duplicatingWallet', true);
|
||||
importOrCreate(function(err, newWallet, isNew) {
|
||||
if (err) {
|
||||
ongoingProcess.set('duplicatingWallet', false);
|
||||
return;
|
||||
}
|
||||
walletService.updateRemotePreferences(newWallet);
|
||||
pushNotificationsService.updateSubscription(newWallet);
|
||||
|
||||
addCopayers(newWallet, isNew, function(err) {
|
||||
ongoingProcess.set('duplicatingWallet', false);
|
||||
if (err)
|
||||
return setErr(err);
|
||||
|
||||
if (isNew)
|
||||
walletService.startScan(newWallet, function() {});
|
||||
|
||||
goHome();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, rateService, $stateParams, $window, $state, $log, profileService, bitcore, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, txConfirmNotification) {
|
||||
angular.module('copayApp.controllers').controller('confirmController', function($rootScope, $scope, $interval, $filter, $timeout, $ionicScrollDelegate, gettextCatalog, walletService, platformInfo, lodash, configService, $stateParams, $window, $state, $log, profileService, bitcore, bitcoreCash, txFormatService, ongoingProcess, $ionicModal, popupService, $ionicHistory, $ionicConfig, payproService, feeService, bwcError, txConfirmNotification, externalLinkService) {
|
||||
|
||||
var countDown = null;
|
||||
var CONFIRM_LIMIT_USD = 20;
|
||||
|
|
@ -28,7 +28,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
function refresh() {
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
}, 1);
|
||||
}, 10);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -58,9 +58,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
});
|
||||
};
|
||||
|
||||
function setNoWallet(msg) {
|
||||
function setNoWallet(msg, criticalError) {
|
||||
$scope.wallet = null;
|
||||
$scope.noWalletMessage = msg;
|
||||
$scope.criticalError = criticalError;
|
||||
$log.warn('Not ready to make the payment:' + msg);
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
|
|
@ -69,18 +70,19 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
|
||||
function setWalletSelector(network, minAmount, cb) {
|
||||
function setWalletSelector(coin, network, minAmount, cb) {
|
||||
|
||||
// no min amount? (sendMax) => look for no empty wallets
|
||||
minAmount = minAmount || 1;
|
||||
|
||||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: network
|
||||
network: network,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (!$scope.wallets || !$scope.wallets.length) {
|
||||
setNoWallet(gettextCatalog.getString('No wallets available'));
|
||||
setNoWallet(gettextCatalog.getString('No wallets available'), true);
|
||||
return cb();
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +111,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
return cb('Could not update any wallet');
|
||||
|
||||
if (lodash.isEmpty(filteredWallets)) {
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'));
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'), true);
|
||||
}
|
||||
$scope.wallets = lodash.clone(filteredWallets);
|
||||
return cb();
|
||||
|
|
@ -120,6 +122,30 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
// Setup $scope
|
||||
|
||||
var B = data.stateParams.coin == 'bch' ? bitcoreCash : bitcore;
|
||||
var networkName;
|
||||
try {
|
||||
networkName = (new B.Address(data.stateParams.toAddress)).network.name;
|
||||
} catch(e) {
|
||||
var message = gettextCatalog.getString('Copay only supports Bitcoin Cash using new version numbers addresses');
|
||||
var backText = gettextCatalog.getString('Go back');
|
||||
var learnText = gettextCatalog.getString('Learn more');
|
||||
popupService.showConfirm(null, message, backText, learnText, function(back) {
|
||||
$ionicHistory.nextViewOptions({
|
||||
disableAnimate: true,
|
||||
historyRoot: true
|
||||
});
|
||||
$state.go('tabs.send').then(function() {
|
||||
$ionicHistory.clearHistory();
|
||||
if (!back) {
|
||||
var url = 'https://support.bitpay.com/hc/en-us/articles/115004671663';
|
||||
externalLinkService.open(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab stateParams
|
||||
tx = {
|
||||
toAmount: parseInt(data.stateParams.toAmount),
|
||||
|
|
@ -136,33 +162,32 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
toName: data.stateParams.toName,
|
||||
toEmail: data.stateParams.toEmail,
|
||||
toColor: data.stateParams.toColor,
|
||||
network: (new bitcore.Address(data.stateParams.toAddress)).network.name,
|
||||
network: networkName,
|
||||
coin: data.stateParams.coin,
|
||||
txp: {},
|
||||
};
|
||||
|
||||
if (tx.coin && tx.coin == 'bch') tx.feeLevel = 'normal';
|
||||
|
||||
// Other Scope vars
|
||||
$scope.isCordova = isCordova;
|
||||
$scope.isWindowsPhoneApp = isWindowsPhoneApp;
|
||||
$scope.showAddress = false;
|
||||
|
||||
updateTx(tx, null, {}, function() {
|
||||
$scope.walletSelectorTitle = gettextCatalog.getString('Send from');
|
||||
|
||||
$scope.walletSelectorTitle = gettextCatalog.getString('Send from');
|
||||
|
||||
setWalletSelector(tx.network, tx.toAmount, function(err) {
|
||||
if (err) {
|
||||
return exitWithError('Could not update wallets');
|
||||
}
|
||||
|
||||
if ($scope.wallets.length > 1) {
|
||||
$scope.showWalletSelector();
|
||||
} else if ($scope.wallets.length) {
|
||||
setWallet($scope.wallets[0], tx);
|
||||
}
|
||||
});
|
||||
setWalletSelector(tx.coin, tx.network, tx.toAmount, function(err) {
|
||||
if (err) {
|
||||
return exitWithError('Could not update wallets');
|
||||
}
|
||||
|
||||
if ($scope.wallets.length > 1) {
|
||||
$scope.showWalletSelector();
|
||||
} else if ($scope.wallets.length) {
|
||||
setWallet($scope.wallets[0], tx);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -227,6 +252,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
};
|
||||
|
||||
function updateTx(tx, wallet, opts, cb) {
|
||||
ongoingProcess.set('calculatingFee', true);
|
||||
|
||||
if (opts.clearCache) {
|
||||
tx.txp = {};
|
||||
|
|
@ -238,10 +264,10 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
if (!tx.toAmount) return;
|
||||
|
||||
// Amount
|
||||
tx.amountStr = txFormatService.formatAmountStr(tx.toAmount);
|
||||
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.toAmount);
|
||||
tx.amountValueStr = tx.amountStr.split(' ')[0];
|
||||
tx.amountUnitStr = tx.amountStr.split(' ')[1];
|
||||
txFormatService.formatAlternativeStr(tx.toAmount, function(v) {
|
||||
txFormatService.formatAlternativeStr(wallet.coin, tx.toAmount, function(v) {
|
||||
tx.alternativeAmountStr = v;
|
||||
});
|
||||
}
|
||||
|
|
@ -250,19 +276,23 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
refresh();
|
||||
|
||||
// End of quick refresh, before wallet is selected.
|
||||
if (!wallet) return cb();
|
||||
if (!wallet) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
return cb();
|
||||
}
|
||||
|
||||
feeService.getFeeRate(tx.network, tx.feeLevel, function(err, feeRate) {
|
||||
if (err) return cb(err);
|
||||
feeService.getFeeRate(wallet.coin, tx.network, tx.feeLevel, function(err, feeRate) {
|
||||
if (err) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
if (!usingCustomFee) tx.feeRate = feeRate;
|
||||
tx.feeLevelName = feeService.feeOpts[tx.feeLevel];
|
||||
|
||||
if (!wallet)
|
||||
return cb();
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -272,6 +302,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
$log.debug('Send max info', sendMaxInfo);
|
||||
|
||||
if (tx.sendMax && sendMaxInfo.amount == 0) {
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
setNoWallet(gettextCatalog.getString('Insufficient funds'));
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not enough funds for fee'));
|
||||
return cb('no_funds');
|
||||
|
|
@ -280,20 +311,27 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
tx.sendMaxInfo = sendMaxInfo;
|
||||
tx.toAmount = tx.sendMaxInfo.amount;
|
||||
updateAmount();
|
||||
showSendMaxWarning(sendMaxInfo);
|
||||
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);
|
||||
refresh();
|
||||
return cb();
|
||||
}
|
||||
|
||||
getTxp(lodash.clone(tx), wallet, opts.dryRun, function(err, txp) {
|
||||
if (err) return cb(err);
|
||||
ongoingProcess.set('calculatingFee', false);
|
||||
if (err) {
|
||||
return cb(err);
|
||||
}
|
||||
|
||||
txp.feeStr = txFormatService.formatAmountStr(txp.fee);
|
||||
txFormatService.formatAlternativeStr(txp.fee, function(v) {
|
||||
txp.feeStr = txFormatService.formatAmountStr(wallet.coin, txp.fee);
|
||||
txFormatService.formatAlternativeStr(wallet.coin, txp.fee, function(v) {
|
||||
txp.alternativeFeeStr = v;
|
||||
});
|
||||
|
||||
|
|
@ -321,14 +359,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
}
|
||||
|
||||
function setButtonText(isMultisig, isPayPro) {
|
||||
$scope.buttonText = gettextCatalog.getString(isCordova && !isWindowsPhoneApp ? 'Slide' : 'Click') + ' ';
|
||||
|
||||
if (isPayPro) {
|
||||
$scope.buttonText += gettextCatalog.getString('to pay');
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to pay');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to pay');
|
||||
}
|
||||
} else if (isMultisig) {
|
||||
$scope.buttonText += gettextCatalog.getString('to accept');
|
||||
} else
|
||||
$scope.buttonText += gettextCatalog.getString('to send');
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to accept');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to accept');
|
||||
}
|
||||
} else {
|
||||
if (isCordova && !isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to send');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to send');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -337,26 +387,26 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
};
|
||||
|
||||
|
||||
function showSendMaxWarning(sendMaxInfo) {
|
||||
function showSendMaxWarning(wallet, sendMaxInfo) {
|
||||
|
||||
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(sendMaxInfo.amountBelowFee)
|
||||
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(sendMaxInfo.amountAboveMaxSize)
|
||||
amountAboveMaxSizeStr: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.amountAboveMaxSize)
|
||||
}));
|
||||
}
|
||||
return warningMsg.join('\n');
|
||||
};
|
||||
|
||||
var msg = gettextCatalog.getString("{{fee}} will be deducted for bitcoin networking fees.", {
|
||||
fee: txFormatService.formatAmountStr(sendMaxInfo.fee)
|
||||
fee: txFormatService.formatAmountStr(wallet.coin, sendMaxInfo.fee)
|
||||
});
|
||||
var warningMsg = verifyExcludedUtxos();
|
||||
|
||||
|
|
@ -422,6 +472,11 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.wallet = wallet;
|
||||
|
||||
// If select another wallet
|
||||
tx.coin = wallet.coin;
|
||||
tx.feeLevel = wallet.coin == 'bch' ? 'normal' : configFeeLevel;
|
||||
usingCustomFee = null;
|
||||
|
||||
setButtonText(wallet.credentials.m > 1, !!tx.paypro);
|
||||
|
||||
if (tx.paypro)
|
||||
|
|
@ -483,7 +538,7 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
if (walletService.isEncrypted(wallet))
|
||||
return cb();
|
||||
|
||||
var amountUsd = parseFloat(txFormatService.formatToUSD(txp.amount));
|
||||
var amountUsd = parseFloat(txFormatService.formatToUSD(wallet.coin, txp.amount));
|
||||
if (amountUsd <= CONFIRM_LIMIT_USD)
|
||||
return cb();
|
||||
|
||||
|
|
@ -563,10 +618,13 @@ angular.module('copayApp.controllers').controller('confirmController', function(
|
|||
|
||||
$scope.chooseFeeLevel = function(tx, wallet) {
|
||||
|
||||
if (wallet.coin == 'bch') return;
|
||||
|
||||
var scope = $rootScope.$new(true);
|
||||
scope.network = tx.network;
|
||||
scope.feeLevel = tx.feeLevel;
|
||||
scope.noSave = true;
|
||||
scope.coin = wallet.coin;
|
||||
|
||||
if (usingCustomFee) {
|
||||
scope.customFeePerKB = tx.feeRate;
|
||||
|
|
|
|||
|
|
@ -22,11 +22,16 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.formData = {};
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
var tc = $state.current.name == 'tabs.add.create-personal' ? 1 : defaults.wallet.totalCopayers;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.TCValues = lodash.range(2, defaults.limits.totalCopayers + 1);
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.coin = data.stateParams.coin;
|
||||
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
|
||||
$scope.setTotalCopayers(tc);
|
||||
updateRCSelect(tc);
|
||||
resetPasswordFields();
|
||||
|
|
@ -133,10 +138,11 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
m: $scope.formData.requiredCopayers,
|
||||
n: $scope.formData.totalCopayers,
|
||||
myName: $scope.formData.totalCopayers > 1 ? $scope.formData.myName : null,
|
||||
networkName: $scope.formData.testnetEnabled ? 'testnet' : 'livenet',
|
||||
networkName: $scope.formData.testnetEnabled && $scope.formData.coin != 'bch' ? 'testnet' : 'livenet',
|
||||
bwsurl: $scope.formData.bwsurl,
|
||||
singleAddress: $scope.formData.singleAddressEnabled,
|
||||
walletPrivKey: $scope.formData._walletPrivKey, // Only for testing
|
||||
coin: $scope.formData.coin
|
||||
};
|
||||
|
||||
var setSeed = $scope.formData.seedSource.id == 'set';
|
||||
|
|
@ -170,6 +176,11 @@ angular.module('copayApp.controllers').controller('createController',
|
|||
}
|
||||
|
||||
if ($scope.formData.seedSource.id == walletService.externalSource.ledger.id || $scope.formData.seedSource.id == walletService.externalSource.trezor.id || $scope.formData.seedSource.id == walletService.externalSource.intelTEE.id) {
|
||||
if ($scope.formData.coin == 'bch') {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Hardware wallets are not yet supported with Bitcoin Cash'));
|
||||
return;
|
||||
}
|
||||
|
||||
var account = $scope.formData.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
});
|
||||
};
|
||||
|
||||
var setProtocolHandler = function() {
|
||||
$scope.protocolHandler = walletService.getProtocolHandler($scope.wallet);
|
||||
}
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var walletId = data.stateParams.id;
|
||||
|
||||
|
|
@ -15,21 +19,25 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
showErrorAndBack('Error', 'No wallet selected');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$scope.showShareButton = platformInfo.isCordova ? (platformInfo.isIOS ? 'iOS' : 'Android') : null;
|
||||
|
||||
$scope.wallet = profileService.getWallet(walletId);
|
||||
|
||||
setProtocolHandler();
|
||||
|
||||
walletService.getAddress($scope.wallet, false, function(err, addr) {
|
||||
if (!addr) {
|
||||
showErrorAndBack('Error', 'Could not get the address');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$scope.address = addr;
|
||||
|
||||
|
||||
$scope.coin = data.stateParams.coin;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
$scope.wallet.coin,
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
// Amount in USD or BTC
|
||||
|
|
@ -37,17 +45,17 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
var currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
if (currency != 'BTC') {
|
||||
// Convert to BTC
|
||||
if (currency != 'BTC' && currency != 'BCH') {
|
||||
// Convert to BTC or BCH
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var amountUnit = txFormatService.satToUnit(parsedAmount.amountSat);
|
||||
var btcParsedAmount = txFormatService.parseAmount(amountUnit, config.unitName);
|
||||
|
||||
var btcParsedAmount = txFormatService.parseAmount($scope.wallet.coin, amountUnit, $scope.wallet.coin);
|
||||
|
||||
$scope.amountBtc = btcParsedAmount.amount;
|
||||
$scope.altAmountStr = btcParsedAmount.amountUnitStr;
|
||||
} else {
|
||||
$scope.amountBtc = amount; // BTC
|
||||
$scope.altAmountStr = txFormatService.formatAlternativeStr(parsedAmount.amountSat);
|
||||
$scope.amountBtc = amount; // BTC or BCH
|
||||
$scope.altAmountStr = txFormatService.formatAlternativeStr($scope.wallet.coin, parsedAmount.amountSat);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -61,12 +69,16 @@ angular.module('copayApp.controllers').controller('customAmountController', func
|
|||
|
||||
$scope.shareAddress = function() {
|
||||
if (!platformInfo.isCordova) return;
|
||||
var data = 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
var data = protocol + ':' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
window.plugins.socialsharing.share(data, null, null, null);
|
||||
}
|
||||
|
||||
$scope.copyToClipboard = function() {
|
||||
return 'bitcoin:' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
return protocol + ':' + $scope.address + '?amount=' + $scope.amountBtc;
|
||||
};
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
|
||||
var reader = new FileReader();
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
var errors = bwcService.getErrors();
|
||||
|
||||
$scope.init = function() {
|
||||
|
|
@ -15,9 +16,14 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.coin = $stateParams.coin;
|
||||
$scope.importErr = false;
|
||||
$scope.isCopay = appConfigService.name == 'copay';
|
||||
$scope.fromHardwareWallet = { value: false };
|
||||
$scope.fromHardwareWallet = {
|
||||
value: false
|
||||
};
|
||||
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
|
||||
if ($stateParams.code)
|
||||
$scope.processWalletInfo($stateParams.code);
|
||||
|
|
@ -59,6 +65,15 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
});
|
||||
};
|
||||
|
||||
$scope.switchTestnetOff = function() {
|
||||
$scope.formData.testnetEnabled = false;
|
||||
$scope.setDerivationPath();
|
||||
$scope.resizeView();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.processWalletInfo = function(code) {
|
||||
if (!code) return;
|
||||
|
||||
|
|
@ -203,6 +218,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
|
||||
var opts = {};
|
||||
opts.bwsurl = $scope.formData.bwsurl;
|
||||
opts.coin = $scope.formData.coin;
|
||||
_importBlob(evt.target.result, opts);
|
||||
}
|
||||
}
|
||||
|
|
@ -228,6 +244,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
} else {
|
||||
var opts = {};
|
||||
opts.bwsurl = $scope.formData.bwsurl;
|
||||
opts.coin = $scope.formData.coin;
|
||||
_importBlob(backupText, opts);
|
||||
}
|
||||
};
|
||||
|
|
@ -253,6 +270,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
opts.account = pathData.account;
|
||||
opts.networkName = pathData.networkName;
|
||||
opts.derivationStrategy = pathData.derivationStrategy;
|
||||
opts.coin = $scope.formData.coin;
|
||||
|
||||
var words = $scope.formData.words || null;
|
||||
|
||||
|
|
@ -279,7 +297,7 @@ angular.module('copayApp.controllers').controller('importController',
|
|||
$log.warn('This wont work for Intel TEE wallets');
|
||||
|
||||
var id = $scope.formData.seedSourceAll.id;
|
||||
var isMultisig = opts.derivationStrategy =='BIP48';
|
||||
var isMultisig = opts.derivationStrategy == 'BIP48';
|
||||
var account = opts.account;
|
||||
opts.entropySourcePath = 'm/' + hwWallet.getEntropyPath(id, isMultisig, account);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,11 +5,14 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
var defaults = configService.getDefaults();
|
||||
var config = configService.getSync();
|
||||
$scope.formData = {};
|
||||
$scope.formData.bwsurl = defaults.bws.url;
|
||||
$scope.formData.derivationPath = derivationPathHelper.default;
|
||||
$scope.formData.account = 1;
|
||||
$scope.formData.secret = null;
|
||||
$scope.formData.coin = data.stateParams.coin;
|
||||
if (config.cashSupport) $scope.enableCash = true;
|
||||
resetPasswordFields();
|
||||
updateSeedSourceSelect();
|
||||
});
|
||||
|
|
@ -103,7 +106,8 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
var opts = {
|
||||
secret: $scope.formData.secret,
|
||||
myName: $scope.formData.myName,
|
||||
bwsurl: $scope.formData.bwsurl
|
||||
bwsurl: $scope.formData.bwsurl,
|
||||
coin: $scope.formData.coin
|
||||
}
|
||||
|
||||
var setSeed = $scope.formData.seedSource.id == 'set';
|
||||
|
|
@ -137,6 +141,11 @@ angular.module('copayApp.controllers').controller('joinController',
|
|||
}
|
||||
|
||||
if ($scope.formData.seedSource.id == walletService.externalSource.ledger.id || $scope.formData.seedSource.id == walletService.externalSource.trezor.id || $scope.formData.seedSource.id == walletService.externalSource.intelTEE.id) {
|
||||
if ($scope.formData.coin == 'bch') {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Hardware wallets are not yet supported with Bitcoin Cash'));
|
||||
return;
|
||||
}
|
||||
|
||||
var account = $scope.formData.account;
|
||||
if (!account || account < 1) {
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Invalid account number'));
|
||||
|
|
|
|||
24
src/js/controllers/mercadoLibre.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreController',
|
||||
function($scope, $timeout, $log, mercadoLibreService, externalLinkService, popupService) {
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var init = function() {
|
||||
mercadoLibreService.getPendingGiftCards(function(err, gcds) {
|
||||
if (err) $log.error(err);
|
||||
$scope.giftCards = gcds;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.network = mercadoLibreService.getNetwork();
|
||||
init();
|
||||
});
|
||||
});
|
||||
100
src/js/controllers/mercadoLibreCards.js
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreCardsController',
|
||||
function($scope, $timeout, $ionicModal, $log, $ionicScrollDelegate, lodash, mercadoLibreService, platformInfo, externalLinkService, popupService, ongoingProcess) {
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
var updateGiftCards = function(cb) {
|
||||
mercadoLibreService.getPendingGiftCards(function(err, gcds) {
|
||||
if (err) {
|
||||
popupService.showAlert('Could not get gift cards', err);
|
||||
if (cb) return cb();
|
||||
else return;
|
||||
}
|
||||
$scope.giftCards = gcds;
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
$ionicScrollDelegate.resize();
|
||||
if (cb) return cb();
|
||||
}, 100);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.updatePendingGiftCards = lodash.debounce(function() {
|
||||
updateGiftCards(function() {
|
||||
var index = 0;
|
||||
var gcds = $scope.giftCards;
|
||||
lodash.forEach(gcds, function(dataFromStorage) {
|
||||
if (dataFromStorage.status == 'PENDING') {
|
||||
$log.debug("Creating / Updating gift card");
|
||||
|
||||
mercadoLibreService.createGiftCard(dataFromStorage, function(err, giftCard) {
|
||||
|
||||
if (err) {
|
||||
popupService.showAlert('Error creating gift card', err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (giftCard.status != 'PENDING') {
|
||||
var newData = {};
|
||||
|
||||
if (!giftCard.status) dataFromStorage.status = null; // Fix error from server
|
||||
|
||||
var cardStatus = giftCard.cardStatus;
|
||||
if (cardStatus && (cardStatus != 'active' && cardStatus != 'inactive' && cardStatus != 'expired'))
|
||||
giftCard.status = 'FAILURE';
|
||||
|
||||
lodash.merge(newData, dataFromStorage, giftCard);
|
||||
|
||||
mercadoLibreService.savePendingGiftCard(newData, null, function(err) {
|
||||
$log.debug("Saving new gift card");
|
||||
updateGiftCards();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}, 1000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
$scope.openCardModal = function(card) {
|
||||
$scope.card = card;
|
||||
|
||||
$ionicModal.fromTemplateUrl('views/modals/mercadolibre-card-details.html', {
|
||||
scope: $scope
|
||||
}).then(function(modal) {
|
||||
$scope.mercadoLibreCardDetailsModal = modal;
|
||||
$scope.mercadoLibreCardDetailsModal.show();
|
||||
});
|
||||
|
||||
$scope.$on('modal.hidden', function() {
|
||||
$scope.updatePendingGiftCards();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.invoiceId = data.stateParams.invoiceId;
|
||||
updateGiftCards(function() {
|
||||
if ($scope.invoiceId) {
|
||||
var card = lodash.find($scope.giftCards, {
|
||||
invoiceId: $scope.invoiceId
|
||||
});
|
||||
if (lodash.isEmpty(card)) {
|
||||
popupService.showAlert(null, 'Card not found');
|
||||
return;
|
||||
}
|
||||
$scope.openCardModal(card);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.afterEnter", function(event, data) {
|
||||
$scope.updatePendingGiftCards();
|
||||
});
|
||||
});
|
||||
|
|
@ -18,14 +18,14 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'superEconomy'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
var getMaxRecommended = function() {
|
||||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'urgent'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
$scope.ok = function() {
|
||||
|
|
@ -61,7 +61,7 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
// If no custom fee
|
||||
if (value) {
|
||||
$scope.customFeePerKB = null;
|
||||
$scope.feePerSatByte = (value.feePerKB / 1000).toFixed();
|
||||
$scope.feePerSatByte = (value.feePerKb / 1000).toFixed();
|
||||
$scope.avgConfirmationTime = value.nbBlocks * 10;
|
||||
} else {
|
||||
$scope.avgConfirmationTime = null;
|
||||
|
|
@ -102,7 +102,7 @@ angular.module('copayApp.controllers').controller('feeLevelsController', functio
|
|||
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.loadingFee = true;
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.coin, function(err, levels) {
|
||||
$scope.loadingFee = false;
|
||||
if (err || lodash.isEmpty(levels)) {
|
||||
showErrorAndClose(null, err);
|
||||
|
|
|
|||
21
src/js/controllers/modals/mercadoLibreCardDetails.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('mercadoLibreCardDetailsController', function($scope, mercadoLibreService, externalLinkService) {
|
||||
|
||||
$scope.remove = function() {
|
||||
mercadoLibreService.savePendingGiftCard($scope.card, {
|
||||
remove: true
|
||||
}, function(err) {
|
||||
$scope.close();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
$scope.mercadoLibreCardDetailsModal.hide();
|
||||
};
|
||||
|
||||
$scope.openExternalLink = function(url) {
|
||||
externalLinkService.open(url);
|
||||
};
|
||||
|
||||
});
|
||||
|
|
@ -23,7 +23,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
};
|
||||
|
||||
function displayFeeValues() {
|
||||
txFormatService.formatAlternativeStr($scope.tx.fee, function(v) {
|
||||
txFormatService.formatAlternativeStr($scope.wallet.coin, $scope.tx.fee, function(v) {
|
||||
$scope.tx.feeFiatStr = v;
|
||||
});
|
||||
$scope.tx.feeRateStr = ($scope.tx.fee / ($scope.tx.amount + $scope.tx.fee) * 100).toFixed(2) + '%';
|
||||
|
|
@ -31,17 +31,23 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
};
|
||||
|
||||
function applyButtonText() {
|
||||
$scope.buttonText = $scope.isCordova && !$scope.isWindowsPhoneApp ? gettextCatalog.getString('Slide') + ' ' : gettextCatalog.getString('Click') + ' ';
|
||||
|
||||
var lastSigner = lodash.filter($scope.tx.actions, {
|
||||
type: 'accept'
|
||||
}).length == $scope.tx.requiredSignatures - 1;
|
||||
|
||||
if (lastSigner) {
|
||||
$scope.buttonText += gettextCatalog.getString('to send');
|
||||
if ($scope.isCordova && !$scope.isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to send');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to send');
|
||||
}
|
||||
$scope.successText = gettextCatalog.getString('Payment Sent');
|
||||
} else {
|
||||
$scope.buttonText += gettextCatalog.getString('to accept');
|
||||
if ($scope.isCordova && !$scope.isWindowsPhoneApp) {
|
||||
$scope.buttonText = gettextCatalog.getString('Slide to accept');
|
||||
} else {
|
||||
$scope.buttonText = gettextCatalog.getString('Click to accept');
|
||||
}
|
||||
$scope.successText = gettextCatalog.getString('Payment Accepted');
|
||||
}
|
||||
};
|
||||
|
|
@ -219,7 +225,7 @@ angular.module('copayApp.controllers').controller('txpDetailsController', functi
|
|||
copayerId: $scope.wallet.credentials.copayerId
|
||||
});
|
||||
|
||||
$scope.tx = txFormatService.processTx(tx);
|
||||
$scope.tx = txFormatService.processTx($scope.wallet.coin, tx);
|
||||
|
||||
if (!action && tx.status == 'pending')
|
||||
$scope.tx.pendingForUs = true;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ angular.module('copayApp.controllers').controller('tourController',
|
|||
rateService.whenAvailable(function() {
|
||||
var localCurrency = 'USD';
|
||||
var btcAmount = 1;
|
||||
var rate = rateService.toFiat(btcAmount * 1e8, localCurrency);
|
||||
var rate = rateService.toFiat(btcAmount * 1e8, localCurrency, 'btc');
|
||||
$scope.localCurrencySymbol = '$';
|
||||
$scope.localCurrencyPerBtc = $filter('formatFiatAmount')(parseFloat(rate.toFixed(2), 10));
|
||||
$timeout(function() {
|
||||
|
|
|
|||
|
|
@ -45,8 +45,7 @@ angular.module('copayApp.controllers').controller('paperWalletController',
|
|||
$scope.balanceSat = balance;
|
||||
if ($scope.balanceSat <= 0)
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Not funds found'));
|
||||
var config = configService.getSync().wallet.settings;
|
||||
$scope.balance = txFormatService.formatAmount(balance) + ' ' + config.unitName;
|
||||
$scope.balance = txFormatService.formatAmountStr($scope.wallet.coin, balance);
|
||||
}
|
||||
$scope.$apply();
|
||||
});
|
||||
|
|
@ -60,9 +59,9 @@ angular.module('copayApp.controllers').controller('paperWalletController',
|
|||
$scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, null, function(err, testTx) {
|
||||
if (err) return cb(err);
|
||||
var rawTxLength = testTx.serialize().length;
|
||||
feeService.getCurrentFeeRate('livenet', function(err, feePerKB) {
|
||||
feeService.getCurrentFeeRate('btc', 'livenet', function(err, feePerKb) {
|
||||
var opts = {};
|
||||
opts.fee = Math.round((feePerKB * rawTxLength) / 2000);
|
||||
opts.fee = Math.round((feePerKb * rawTxLength) / 2000);
|
||||
$scope.wallet.buildTxFromPrivateKey($scope.privateKey, destinationAddress, opts, function(err, tx) {
|
||||
if (err) return cb(err);
|
||||
$scope.wallet.broadcastRawTx({
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesController',
|
||||
function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService, platformInfo) {
|
||||
function($scope, $rootScope, $timeout, $log, $ionicHistory, configService, profileService, fingerprintService, walletService, platformInfo, externalLinkService, gettextCatalog) {
|
||||
var wallet;
|
||||
var walletId;
|
||||
|
||||
|
|
@ -58,6 +58,16 @@ angular.module('copayApp.controllers').controller('preferencesController',
|
|||
}
|
||||
};
|
||||
|
||||
$scope.openWikiSpendingPassword = function() {
|
||||
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#what-the-spending-password-does';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Read more in our Wiki');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
$scope.touchIdChange = function() {
|
||||
var newStatus = $scope.touchIdEnabled.value;
|
||||
walletService.setTouchId(wallet, !!newStatus, function(err) {
|
||||
|
|
|
|||
|
|
@ -43,8 +43,9 @@ angular.module('copayApp.controllers').controller('preferencesAltCurrencyControl
|
|||
$scope.findCurrency = function(search) {
|
||||
if (!search) init();
|
||||
$scope.altCurrencyList = lodash.filter(completeAlternativeList, function(item) {
|
||||
var val = item.name;
|
||||
return lodash.includes(val.toLowerCase(), search.toLowerCase());
|
||||
var val = item.name
|
||||
var val2 = item.isoCode;
|
||||
return lodash.includes(val.toLowerCase(), search.toLowerCase()) || lodash.includes(val2.toLowerCase(), search.toLowerCase());
|
||||
});
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
|
|
|
|||
42
src/js/controllers/preferencesCash.js
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesCashController', function($scope, $log, $timeout, appConfigService, configService, gettextCatalog, externalLinkService) {
|
||||
var updateConfig = function() {
|
||||
|
||||
var config = configService.getSync();
|
||||
$scope.appName = appConfigService.nameCase;
|
||||
|
||||
$scope.cashSupport = {
|
||||
value: config.cashSupport
|
||||
};
|
||||
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cashSupportChange = function() {
|
||||
var opts = {
|
||||
cashSupport: $scope.cashSupport.value
|
||||
};
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$scope.openBitcoinCashWeb = function() {
|
||||
var url = 'https://www.bitcoincash.org/';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Open bitcoincash.org?');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
updateConfig();
|
||||
});
|
||||
});
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('preferencesDeleteWalletController',
|
||||
function($scope, $ionicHistory, gettextCatalog, lodash, profileService, $state, ongoingProcess, popupService, pushNotificationsService) {
|
||||
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
if (!data.stateParams || !data.stateParams.walletId) {
|
||||
popupService.showAlert(null, gettextCatalog.getString('No wallet selected'), function() {
|
||||
|
|
@ -17,8 +17,7 @@ angular.module('copayApp.controllers').controller('preferencesDeleteWalletContro
|
|||
});
|
||||
return;
|
||||
}
|
||||
$scope.alias = lodash.isEqual($scope.wallet.name, $scope.wallet.credentials.walletName) ? null : $scope.wallet.name + ' ';
|
||||
$scope.walletName = $scope.wallet.credentials.walletName;
|
||||
$scope.walletName = $scope.wallet.name;
|
||||
});
|
||||
|
||||
$scope.showDeletePopup = function() {
|
||||
|
|
|
|||
|
|
@ -32,11 +32,12 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
});
|
||||
|
||||
$scope.init = function() {
|
||||
var coin = 'btc'; // TODO: only BTC in preferences
|
||||
$scope.network = $scope.network || 'livenet';
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.currentFeeLevel = $scope.feeLevel || feeService.getCurrentFeeLevel();
|
||||
$scope.loadingFee = true;
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels(coin, function(err, levels) {
|
||||
$scope.loadingFee = false;
|
||||
if (err) {
|
||||
//Error is already formatted
|
||||
|
|
@ -66,7 +67,7 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
return;
|
||||
}
|
||||
|
||||
$scope.feePerSatByte = (value.feePerKB / 1000).toFixed();
|
||||
$scope.feePerSatByte = (value.feePerKb / 1000).toFixed();
|
||||
$scope.avgConfirmationTime = value.nbBlocks * 10;
|
||||
$scope.invalidCustomFeeEntered = false;
|
||||
setMinWarning();
|
||||
|
|
@ -97,7 +98,7 @@ angular.module('copayApp.controllers').controller('preferencesFeeController', fu
|
|||
var value = lodash.find($scope.feeLevels[$scope.network], {
|
||||
level: 'superEconomy'
|
||||
});
|
||||
return parseInt((value.feePerKB / 1000).toFixed());
|
||||
return parseInt((value.feePerKb / 1000).toFixed());
|
||||
};
|
||||
|
||||
var setMinWarning = function() {
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('preferencesUnitController', function($scope, $log, configService, $ionicHistory, gettextCatalog, walletService, profileService) {
|
||||
|
||||
var config = configService.getSync();
|
||||
$scope.unitList = [{
|
||||
name: 'bits (1,000,000 bits = 1BTC)',
|
||||
shortName: 'bits',
|
||||
value: 100,
|
||||
decimals: 2,
|
||||
code: 'bit',
|
||||
}, {
|
||||
name: 'BTC',
|
||||
shortName: 'BTC',
|
||||
value: 100000000,
|
||||
decimals: 8,
|
||||
code: 'btc',
|
||||
}];
|
||||
|
||||
$scope.save = function(newUnit) {
|
||||
var opts = {
|
||||
wallet: {
|
||||
settings: {
|
||||
unitName: newUnit.shortName,
|
||||
unitToSatoshi: newUnit.value,
|
||||
unitDecimals: newUnit.decimals,
|
||||
unitCode: newUnit.code,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
configService.set(opts, function(err) {
|
||||
if (err) $log.warn(err);
|
||||
|
||||
$ionicHistory.goBack();
|
||||
walletService.updateRemotePreferences(profileService.getWallets())
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data){
|
||||
$scope.currentUnit = config.wallet.settings.unitCode;
|
||||
});
|
||||
});
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('sellCoinbaseController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicScrollDelegate, $ionicConfig, lodash, coinbaseService, popupService, profileService, ongoingProcess, walletService, appConfigService, configService, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -34,124 +35,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
}, onSendStatusChange);
|
||||
};
|
||||
|
||||
var checkTransaction = lodash.throttle(function(count, txp) {
|
||||
$log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5');
|
||||
// TX amount in BTC
|
||||
var satToBtc = 1 / 100000000;
|
||||
var amountBTC = (txp.amount * satToBtc).toFixed(8);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
$log.error(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
var sellPrice = null;
|
||||
|
||||
coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
sellPrice = sell.data;
|
||||
|
||||
coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
|
||||
var coinbaseTransactions = ctxs.data;
|
||||
var txFound = false;
|
||||
var ctx;
|
||||
for(var i = 0; i < coinbaseTransactions.length; i++) {
|
||||
ctx = coinbaseTransactions[i];
|
||||
if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) {
|
||||
$log.warn('Transaction found!', ctx);
|
||||
txFound = true;
|
||||
$log.debug('Saving transaction to process later...');
|
||||
ctx['payment_method'] = $scope.selectedPaymentMethodId.value;
|
||||
ctx['status'] = 'pending'; // Forcing "pending" status to process later
|
||||
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
|
||||
ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : '';
|
||||
ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD';
|
||||
ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name;
|
||||
coinbaseService.savePendingTransaction(ctx, null, function(err) {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!txFound) {
|
||||
// Transaction sent, but could not be verified by Coinbase.com
|
||||
$log.warn('Transaction not found in Coinbase.');
|
||||
if (count < 5) {
|
||||
checkTransaction(count + 1, txp);
|
||||
} else {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError('No transaction found');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 8000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
var statusChangeHandler = function (processName, showName, isOn) {
|
||||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if ( processName == 'sellingBitcoin' && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
$scope.priceSensitivity = coinbaseService.priceSensitivity;
|
||||
$scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity };
|
||||
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
minAmount: parsedAmount.amountSat
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingCoinbase', true);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
|
|
@ -193,7 +77,121 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
if (!hasPrimary) $scope.selectedPaymentMethodId.value = $scope.paymentMethods[0].id;
|
||||
$scope.sellRequest();
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var checkTransaction = lodash.throttle(function(count, txp) {
|
||||
$log.warn('Check if transaction has been received by Coinbase. Try ' + count + '/5');
|
||||
// TX amount in BTC
|
||||
var satToBtc = 1 / 100000000;
|
||||
var amountBTC = (txp.amount * satToBtc).toFixed(8);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
$log.error(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
var accessToken = res.accessToken;
|
||||
var accountId = res.accountId;
|
||||
var sellPrice = null;
|
||||
|
||||
coinbaseService.sellPrice(accessToken, coinbaseService.getAvailableCurrency(), function(err, sell) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
sellPrice = sell.data;
|
||||
|
||||
coinbaseService.getTransactions(accessToken, accountId, function(err, ctxs) {
|
||||
if (err) {
|
||||
$log.debug(err);
|
||||
checkTransaction(count, txp);
|
||||
return;
|
||||
}
|
||||
|
||||
var coinbaseTransactions = ctxs.data;
|
||||
var txFound = false;
|
||||
var ctx;
|
||||
for(var i = 0; i < coinbaseTransactions.length; i++) {
|
||||
ctx = coinbaseTransactions[i];
|
||||
if (ctx.type == 'send' && ctx.from && ctx.amount.amount == amountBTC ) {
|
||||
$log.warn('Transaction found!', ctx);
|
||||
txFound = true;
|
||||
$log.debug('Saving transaction to process later...');
|
||||
ctx['payment_method'] = $scope.selectedPaymentMethodId.value;
|
||||
ctx['status'] = 'pending'; // Forcing "pending" status to process later
|
||||
ctx['price_sensitivity'] = $scope.selectedPriceSensitivity.data;
|
||||
ctx['sell_price_amount'] = sellPrice ? sellPrice.amount : '';
|
||||
ctx['sell_price_currency'] = sellPrice ? sellPrice.currency : 'USD';
|
||||
ctx['description'] = appConfigService.nameCase + ' Wallet: ' + $scope.wallet.name;
|
||||
coinbaseService.savePendingTransaction(ctx, null, function(err) {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
if (err) $log.debug(err);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!txFound) {
|
||||
// Transaction sent, but could not be verified by Coinbase.com
|
||||
$log.warn('Transaction not found in Coinbase.');
|
||||
if (count < 5) {
|
||||
checkTransaction(count + 1, txp);
|
||||
} else {
|
||||
ongoingProcess.set('sellingBitcoin', false, statusChangeHandler);
|
||||
showError('No transaction found');
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}, 8000, {
|
||||
'leading': true
|
||||
});
|
||||
|
||||
var statusChangeHandler = function (processName, showName, isOn) {
|
||||
$log.debug('statusChangeHandler: ', processName, showName, isOn);
|
||||
if ( processName == 'sellingBitcoin' && !isOn) {
|
||||
$scope.sendStatus = 'success';
|
||||
$timeout(function() {
|
||||
$scope.$digest();
|
||||
}, 100);
|
||||
} else if (showName) {
|
||||
$scope.sendStatus = showName;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
$scope.priceSensitivity = coinbaseService.priceSensitivity;
|
||||
$scope.selectedPriceSensitivity = { data: coinbaseService.selectedPriceSensitivity };
|
||||
|
||||
$scope.network = coinbaseService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
$scope.sellRequest = function() {
|
||||
|
|
@ -236,7 +234,7 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
|
||||
|
||||
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
|
||||
coinbaseService.init(function(err, res) {
|
||||
if (err) {
|
||||
|
|
@ -294,8 +292,8 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
checkTransaction(1, txSent);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -306,6 +304,15 @@ angular.module('copayApp.controllers').controller('sellCoinbaseController', func
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
angular.module('copayApp.controllers').controller('sellGlideraController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, glideraService, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, txFormatService) {
|
||||
|
||||
var coin = 'btc';
|
||||
var amount;
|
||||
var currency;
|
||||
|
||||
|
|
@ -35,39 +36,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
}
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'bits' && data.stateParams.currency != 'BTC' ? true : false;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
data.stateParams.amount,
|
||||
data.stateParams.currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
|
||||
$scope.network = glideraService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
minAmount: parsedAmount.amountSat
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.wallet = $scope.wallets[0]; // Default first wallet
|
||||
|
||||
var processPaymentInfo = function() {
|
||||
ongoingProcess.set('connectingGlidera', true);
|
||||
glideraService.init(function(err, data) {
|
||||
if (err) {
|
||||
|
|
@ -91,6 +60,35 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
$scope.sellInfo = sell;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on("$ionicView.beforeLeave", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(true);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
$ionicConfig.views.swipeBackEnabled(false);
|
||||
});
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
$scope.isFiat = data.stateParams.currency != 'BTC' ? true : false;
|
||||
amount = data.stateParams.amount;
|
||||
currency = data.stateParams.currency;
|
||||
|
||||
$scope.network = glideraService.getNetwork();
|
||||
$scope.wallets = profileService.getWallets({
|
||||
m: 1, // Only 1-signature wallet
|
||||
onlyComplete: true,
|
||||
network: $scope.network,
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
showErrorAndBack('Insufficient funds');
|
||||
return;
|
||||
}
|
||||
$scope.onWalletSelect($scope.wallets[0]); // Default first wallet
|
||||
});
|
||||
|
||||
var ask2FaCode = function(mode, cb) {
|
||||
|
|
@ -108,7 +106,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
popupService.showPrompt(title, message, null, function(twoFaCode) {
|
||||
if (typeof twoFaCode == 'undefined') return cb();
|
||||
return cb(twoFaCode);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return cb();
|
||||
}
|
||||
|
|
@ -119,7 +117,7 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
var okText = 'Confirm';
|
||||
var cancelText = 'Cancel';
|
||||
popupService.showConfirm(null, message, okText, cancelText, function(ok) {
|
||||
if (!ok) return;
|
||||
if (!ok) return;
|
||||
ongoingProcess.set('sellingBitcoin', true, statusChangeHandler);
|
||||
glideraService.get2faCode($scope.token, function(err, tfa) {
|
||||
if (err) {
|
||||
|
|
@ -231,6 +229,15 @@ angular.module('copayApp.controllers').controller('sellGlideraController', funct
|
|||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
var parsedAmount = txFormatService.parseAmount(
|
||||
coin,
|
||||
amount,
|
||||
currency);
|
||||
|
||||
amount = parsedAmount.amount;
|
||||
currency = parsedAmount.currency;
|
||||
$scope.amountUnitStr = parsedAmount.amountUnitStr;
|
||||
processPaymentInfo();
|
||||
};
|
||||
|
||||
$scope.goBackHome = function() {
|
||||
|
|
|
|||
|
|
@ -206,14 +206,24 @@ angular.module('copayApp.controllers').controller('tabHomeController',
|
|||
};
|
||||
|
||||
var updateAllWallets = function() {
|
||||
$scope.wallets = profileService.getWallets();
|
||||
if (lodash.isEmpty($scope.wallets)) return;
|
||||
var wallets = [];
|
||||
$scope.walletsBtc = profileService.getWallets({coin: 'btc'});
|
||||
$scope.walletsBch = profileService.getWallets({coin: 'bch'});
|
||||
|
||||
var i = $scope.wallets.length;
|
||||
lodash.each($scope.walletsBtc, function(wBtc) {
|
||||
wallets.push(wBtc);
|
||||
});
|
||||
|
||||
lodash.each($scope.walletsBch, function(wBch) {
|
||||
wallets.push(wBch);
|
||||
});
|
||||
|
||||
if (lodash.isEmpty(wallets)) return;
|
||||
|
||||
var i = wallets.length;
|
||||
var j = 0;
|
||||
var timeSpan = 60 * 60 * 24 * 7;
|
||||
|
||||
lodash.each($scope.wallets, function(wallet) {
|
||||
lodash.each(wallets, function(wallet) {
|
||||
walletService.getStatus(wallet, {}, function(err, status) {
|
||||
if (err) {
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
|
||||
$scope.requestSpecificAmount = function() {
|
||||
$state.go('tabs.paymentRequest.amount', {
|
||||
id: $scope.wallet.credentials.walletId
|
||||
id: $scope.wallet.credentials.walletId,
|
||||
coin: $scope.wallet.coin
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -123,8 +124,13 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
return wallet;
|
||||
}
|
||||
|
||||
var setProtocolHandler = function() {
|
||||
$scope.protocolHandler = walletService.getProtocolHandler($scope.wallet);
|
||||
}
|
||||
|
||||
$scope.onWalletSelect = function(wallet) {
|
||||
$scope.wallet = wallet;
|
||||
setProtocolHandler();
|
||||
$scope.setAddress();
|
||||
};
|
||||
|
||||
|
|
@ -136,6 +142,8 @@ angular.module('copayApp.controllers').controller('tabReceiveController', functi
|
|||
|
||||
$scope.shareAddress = function() {
|
||||
if (!$scope.isCordova) return;
|
||||
window.plugins.socialsharing.share('bitcoin:' + $scope.addr, null, null, null);
|
||||
var protocol = 'bitcoin';
|
||||
if ($scope.wallet.coin == 'bch') protocol += 'cash';
|
||||
window.plugins.socialsharing.share(protocol + ':' + $scope.addr, null, null, null);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService) {
|
||||
angular.module('copayApp.controllers').controller('tabSendController', function($scope, $rootScope, $log, $timeout, $ionicScrollDelegate, addressbookService, profileService, lodash, $state, walletService, incomingData, popupService, platformInfo, bwcError, gettextCatalog, scannerService, bitcoreCash) {
|
||||
|
||||
var originalList;
|
||||
var CONTACTS_SHOW_LIMIT;
|
||||
|
|
@ -76,6 +76,8 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
color: v.color,
|
||||
name: v.name,
|
||||
recipientType: 'wallet',
|
||||
coin: v.coin,
|
||||
network: v.network,
|
||||
getAddress: function(cb) {
|
||||
walletService.getAddress(v, false, cb);
|
||||
},
|
||||
|
|
@ -85,6 +87,14 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
}
|
||||
}
|
||||
|
||||
var getCoin = function(address) {
|
||||
var cashAddress = bitcoreCash.Address.isValid(address, 'livenet');
|
||||
if (cashAddress) {
|
||||
return 'bch';
|
||||
}
|
||||
return 'btc';
|
||||
};
|
||||
|
||||
var updateContactsList = function(cb) {
|
||||
addressbookService.list(function(err, ab) {
|
||||
if (err) $log.error(err);
|
||||
|
|
@ -99,6 +109,7 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
address: k,
|
||||
email: lodash.isObject(v) ? v.email : null,
|
||||
recipientType: 'contact',
|
||||
coin: getCoin(k),
|
||||
getAddress: function(cb) {
|
||||
return cb(null, k);
|
||||
},
|
||||
|
|
@ -186,7 +197,8 @@ angular.module('copayApp.controllers').controller('tabSendController', function(
|
|||
toAddress: addr,
|
||||
toName: item.name,
|
||||
toEmail: item.email,
|
||||
toColor: item.color
|
||||
toColor: item.color,
|
||||
coin: item.coin
|
||||
})
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
$scope.currentLanguageName = uxLanguage.getCurrentLanguageName();
|
||||
$scope.feeOpts = feeService.feeOpts;
|
||||
$scope.currentFeeLevel = feeService.getCurrentFeeLevel();
|
||||
$scope.wallets = profileService.getWallets();
|
||||
$scope.walletsBtc = profileService.getWallets({ coin: 'btc' });
|
||||
$scope.walletsBch = profileService.getWallets({ coin: 'bch' });
|
||||
$scope.buyAndSellServices = buyAndSellService.getLinked();
|
||||
|
||||
configService.whenAvailable(function(config) {
|
||||
$scope.unitName = config.wallet.settings.unitName;
|
||||
$scope.selectedAlternative = {
|
||||
name: config.wallet.settings.alternativeName,
|
||||
isoCode: config.wallet.settings.alternativeIsoCode
|
||||
|
|
@ -26,6 +26,11 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
}, 10);
|
||||
});
|
||||
|
||||
$scope.cashSupport = {
|
||||
value: config.cashSupport
|
||||
};
|
||||
|
||||
|
||||
// TODO move this to a generic service
|
||||
bitpayCardService.getCards(function(err, cards) {
|
||||
if (err) $log.error(err);
|
||||
|
|
@ -63,6 +68,8 @@ angular.module('copayApp.controllers').controller('tabSettingsController', funct
|
|||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
$scope.$on("$ionicView.enter", function(event, data) {
|
||||
updateConfig();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
angular.module('copayApp.controllers').controller('topUpController', function($scope, $log, $state, $timeout, $ionicHistory, $ionicConfig, lodash, popupService, profileService, ongoingProcess, walletService, configService, platformInfo, bitpayService, bitpayCardService, payproService, bwcError, txFormatService, sendMaxService, gettextCatalog) {
|
||||
|
||||
$scope.isCordova = platformInfo.isCordova;
|
||||
var coin = 'btc';
|
||||
var cardId;
|
||||
var useSendMax;
|
||||
var amount;
|
||||
|
|
@ -36,7 +37,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
};
|
||||
|
||||
var satToFiat = function(sat, cb) {
|
||||
txFormatService.toFiat(sat, $scope.currencyIsoCode, function(value) {
|
||||
txFormatService.toFiat(coin, sat, $scope.currencyIsoCode, function(value) {
|
||||
return cb(value);
|
||||
});
|
||||
};
|
||||
|
|
@ -218,7 +219,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
// Save TX in memory
|
||||
createdTx = ctxp;
|
||||
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(ctxp.amount);
|
||||
$scope.totalAmountStr = txFormatService.formatAmountStr(coin, ctxp.amount);
|
||||
|
||||
setTotalAmount(parsedAmount.amountSat, invoiceFeeSat, ctxp.fee);
|
||||
|
||||
|
|
@ -256,7 +257,8 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
$scope.wallets = profileService.getWallets({
|
||||
onlyComplete: true,
|
||||
network: bitpayService.getEnvironment().network,
|
||||
hasFunds: true
|
||||
hasFunds: true,
|
||||
coin: coin
|
||||
});
|
||||
|
||||
if (lodash.isEmpty($scope.wallets)) {
|
||||
|
|
@ -319,7 +321,7 @@ angular.module('copayApp.controllers').controller('topUpController', function($s
|
|||
});
|
||||
return;
|
||||
}
|
||||
var parsedAmount = txFormatService.parseAmount(a, c);
|
||||
var parsedAmount = txFormatService.parseAmount(coin, a, c);
|
||||
initializeTopUp(wallet, parsedAmount);
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
var txId;
|
||||
var listeners = [];
|
||||
var config = configService.getSync();
|
||||
var blockexplorerUrl;
|
||||
|
||||
$scope.$on("$ionicView.beforeEnter", function(event, data) {
|
||||
txId = data.stateParams.txid;
|
||||
|
|
@ -15,6 +16,12 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
$scope.isShared = $scope.wallet.credentials.n > 1;
|
||||
$scope.txsUnsubscribedForNotifications = config.confirmedTxsNotifications ? !config.confirmedTxsNotifications.enabled : true;
|
||||
|
||||
if ($scope.wallet.coin == 'bch') {
|
||||
blockexplorerUrl = 'bch-insight.bitpay.com';
|
||||
} else {
|
||||
blockexplorerUrl = 'insight.bitpay.com';
|
||||
}
|
||||
|
||||
txConfirmNotification.checkIfEnabled(txId, function(res) {
|
||||
$scope.txNotification = {
|
||||
value: res
|
||||
|
|
@ -40,6 +47,16 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
});
|
||||
});
|
||||
|
||||
$scope.readMore = function() {
|
||||
var url = 'https://github.com/bitpay/copay/wiki/COPAY---FAQ#amount-too-low-to-spend';
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('Read more in our Wiki');
|
||||
var okText = gettextCatalog.getString('Open');
|
||||
var cancelText = gettextCatalog.getString('Go Back');
|
||||
externalLinkService.open(url, optIn, title, message, okText, cancelText);
|
||||
};
|
||||
|
||||
function updateMemo() {
|
||||
walletService.getTxNote($scope.wallet, $scope.btx.txid, function(err, note) {
|
||||
if (err) {
|
||||
|
|
@ -102,8 +119,8 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
return popupService.showAlert(gettextCatalog.getString('Error'), gettextCatalog.getString('Transaction not available at this time'));
|
||||
}
|
||||
|
||||
$scope.btx = txFormatService.processTx(tx);
|
||||
txFormatService.formatAlternativeStr(tx.fees, function(v) {
|
||||
$scope.btx = txFormatService.processTx($scope.wallet.coin, tx);
|
||||
txFormatService.formatAlternativeStr($scope.wallet.coin, tx.fees, function(v) {
|
||||
$scope.btx.feeFiatStr = v;
|
||||
$scope.btx.feeRateStr = ($scope.btx.fees / ($scope.btx.amount + $scope.btx.fees) * 100).toFixed(2) + '%';
|
||||
});
|
||||
|
|
@ -121,7 +138,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
$scope.$digest();
|
||||
});
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
if (err) return;
|
||||
walletService.getLowAmount($scope.wallet, levels, function(err, amount) {
|
||||
if (err) return;
|
||||
|
|
@ -168,10 +185,7 @@ angular.module('copayApp.controllers').controller('txDetailsController', functio
|
|||
|
||||
$scope.viewOnBlockchain = function() {
|
||||
var btx = $scope.btx;
|
||||
var url = 'https://blockchain.info/tx/' + btx.txid;
|
||||
if ($scope.getShortNetworkName() == 'test') {
|
||||
url = "https://test-insight.bitpay.com/tx/" + btx.txid;
|
||||
}
|
||||
var url = 'https://' + ($scope.getShortNetworkName() == 'test' ? 'test-' : '') + blockexplorerUrl + '/tx/' + btx.txid;
|
||||
var optIn = true;
|
||||
var title = null;
|
||||
var message = gettextCatalog.getString('View Transaction on Insight');
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
var analyzeUtxos = function() {
|
||||
if (analyzeUtxosDone) return;
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
if (err) return;
|
||||
walletService.getLowUtxos($scope.wallet, levels, function(err, resp) {
|
||||
if (err || !resp) return;
|
||||
|
|
@ -156,9 +156,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
|
||||
var updateTxHistory = function(cb) {
|
||||
if (!cb) cb = function() {};
|
||||
if ($scope.updatingTxHistory) return;
|
||||
|
||||
$scope.updatingTxHistory = true;
|
||||
$scope.updateTxHistoryError = false;
|
||||
$scope.updatingTxHistoryProgress = 0;
|
||||
|
||||
|
|
@ -171,7 +169,7 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
});
|
||||
};
|
||||
|
||||
feeService.getFeeLevels(function(err, levels) {
|
||||
feeService.getFeeLevels($scope.wallet.coin, function(err, levels) {
|
||||
walletService.getTxHistory($scope.wallet, {
|
||||
progressFn: progressFn,
|
||||
feeLevels: levels,
|
||||
|
|
@ -184,7 +182,9 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
}
|
||||
$scope.completeTxHistory = txHistory;
|
||||
$scope.showHistory();
|
||||
$scope.$apply();
|
||||
$timeout(function() {
|
||||
$scope.$apply();
|
||||
});
|
||||
return cb();
|
||||
});
|
||||
});
|
||||
|
|
@ -356,6 +356,8 @@ angular.module('copayApp.controllers').controller('walletDetailsController', fun
|
|||
if (!$scope.wallet) return;
|
||||
$scope.requiresMultipleSignatures = $scope.wallet.credentials.m > 1;
|
||||
|
||||
$scope.updatingTxHistory = true;
|
||||
|
||||
addressbookService.list(function(err, ab) {
|
||||
if (err) $log.error(err);
|
||||
$scope.addressbook = ab || {};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,18 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.directives')
|
||||
.directive('validAddress', ['$rootScope', 'bitcore',
|
||||
function($rootScope, bitcore) {
|
||||
.directive('validAddress', ['$rootScope', 'bitcore', 'bitcoreCash',
|
||||
function($rootScope, bitcore, bitcoreCash) {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elem, attrs, ctrl) {
|
||||
// Bitcoin address
|
||||
var URI = bitcore.URI;
|
||||
var Address = bitcore.Address
|
||||
|
||||
// Bitcoin Cash address
|
||||
var URICash = bitcoreCash.URI;
|
||||
var AddressCash = bitcoreCash.Address
|
||||
|
||||
var validator = function(value) {
|
||||
|
||||
// Regular url
|
||||
|
|
@ -16,8 +22,8 @@ angular.module('copayApp.directives')
|
|||
}
|
||||
|
||||
// Bip21 uri
|
||||
var uri, isAddressValidLivenet, isAddressValidTestnet;
|
||||
if (/^bitcoin:/.test(value)) {
|
||||
var uri, isAddressValidLivenet, isAddressValidTestnet;
|
||||
var isUriValid = URI.isValid(value);
|
||||
if (isUriValid) {
|
||||
uri = new URI(value);
|
||||
|
|
@ -26,6 +32,14 @@ angular.module('copayApp.directives')
|
|||
}
|
||||
ctrl.$setValidity('validAddress', isUriValid && (isAddressValidLivenet || isAddressValidTestnet));
|
||||
return value;
|
||||
} else if (/^bitcoincash:/.test(value)) {
|
||||
var isUriValid = URICash.isValid(value);
|
||||
if (isUriValid) {
|
||||
uri = new URICash(value);
|
||||
isAddressValidLivenet = AddressCash.isValid(uri.address.toString(), 'livenet')
|
||||
}
|
||||
ctrl.$setValidity('validAddress', isUriValid && (isAddressValidLivenet));
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value == 'undefined') {
|
||||
|
|
@ -33,10 +47,11 @@ angular.module('copayApp.directives')
|
|||
return;
|
||||
}
|
||||
|
||||
// Regular Address
|
||||
// Regular Address: try Bitcoin and Bitcoin Cash
|
||||
var regularAddressLivenet = Address.isValid(value, 'livenet');
|
||||
var regularAddressTestnet = Address.isValid(value, 'testnet');
|
||||
ctrl.$setValidity('validAddress', (regularAddressLivenet || regularAddressTestnet));
|
||||
var regularAddressCashLivenet = AddressCash.isValid(value, 'livenet');
|
||||
ctrl.$setValidity('validAddress', (regularAddressLivenet || regularAddressTestnet || regularAddressCashLivenet));
|
||||
return value;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -27,12 +27,10 @@ angular.module('copayApp.filters', [])
|
|||
}
|
||||
})
|
||||
.filter('formatFiatAmount', ['$filter', '$locale', 'configService',
|
||||
function(filter, locale, configService) {
|
||||
function(filter, locale) {
|
||||
var numberFilter = filter('number');
|
||||
var formats = locale.NUMBER_FORMATS;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
return function(amount) {
|
||||
if (!config) return amount;
|
||||
|
||||
var fractionSize = 2;
|
||||
var value = numberFilter(amount, fractionSize);
|
||||
|
|
|
|||
107
src/js/routes.js
|
|
@ -287,7 +287,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
*/
|
||||
|
||||
.state('tabs.send.amount', {
|
||||
url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor',
|
||||
url: '/amount/:recipientType/:toAddress/:toName/:toEmail/:toColor/:coin/:fixedUnit',
|
||||
views: {
|
||||
'tab-send@tabs': {
|
||||
controller: 'amountController',
|
||||
|
|
@ -296,7 +296,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
.state('tabs.send.confirm', {
|
||||
url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:useSendMax',
|
||||
url: '/confirm/:recipientType/:toAddress/:toName/:toAmount/:toEmail/:toColor/:description/:coin/:useSendMax',
|
||||
views: {
|
||||
'tab-send@tabs': {
|
||||
controller: 'confirmController',
|
||||
|
|
@ -329,6 +329,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
'tab-home@tabs': {
|
||||
templateUrl: 'views/add.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc'
|
||||
}
|
||||
})
|
||||
.state('tabs.add.join', {
|
||||
|
|
@ -374,6 +377,16 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
*
|
||||
*/
|
||||
|
||||
.state('tabs.preferencesCash', {
|
||||
url: '/preferencesCash',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesCashController',
|
||||
templateUrl: 'views/preferencesCash.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
.state('tabs.notifications', {
|
||||
url: '/notifications',
|
||||
views: {
|
||||
|
|
@ -392,15 +405,6 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.unit', {
|
||||
url: '/unit',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'preferencesUnitController',
|
||||
templateUrl: 'views/preferencesUnit.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
.state('tabs.fee', {
|
||||
url: '/fee',
|
||||
views: {
|
||||
|
|
@ -474,6 +478,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Wallet preferences
|
||||
|
|
@ -589,6 +594,16 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
|
||||
.state('tabs.preferencesCash.scan', {
|
||||
url: '/cashScan',
|
||||
views: {
|
||||
'tab-settings@tabs': {
|
||||
controller: 'cashScanController',
|
||||
templateUrl: 'views/cashScan.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Addressbook
|
||||
|
|
@ -676,12 +691,12 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
abstract: true,
|
||||
params: {
|
||||
id: null,
|
||||
nextStep: 'tabs.paymentRequest.confirm'
|
||||
nextStep: 'tabs.paymentRequest.confirm',
|
||||
}
|
||||
})
|
||||
|
||||
.state('tabs.paymentRequest.amount', {
|
||||
url: '/amount',
|
||||
url: '/amount/:coin',
|
||||
views: {
|
||||
'tab-receive@tabs': {
|
||||
controller: 'amountController',
|
||||
|
|
@ -690,7 +705,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
})
|
||||
.state('tabs.paymentRequest.confirm', {
|
||||
url: '/confirm/:amount/:currency',
|
||||
url: '/confirm/:amount/:currency/:coin',
|
||||
views: {
|
||||
'tab-receive@tabs': {
|
||||
controller: 'customAmountController',
|
||||
|
|
@ -923,6 +938,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
controllerAs: 'glidera',
|
||||
templateUrl: 'views/glidera.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc',
|
||||
}
|
||||
})
|
||||
.state('tabs.buyandsell.glidera.amount', {
|
||||
|
|
@ -976,6 +994,9 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
controllerAs: 'coinbase',
|
||||
templateUrl: 'views/coinbase.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
coin: 'btc',
|
||||
}
|
||||
})
|
||||
.state('tabs.preferences.coinbase', {
|
||||
|
|
@ -1026,36 +1047,54 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
abstract: true
|
||||
})
|
||||
|
||||
/*
|
||||
*
|
||||
* Mercado Libre Gift Card
|
||||
*
|
||||
*/
|
||||
|
||||
/* Explore Bitcoin.com */
|
||||
.state('tabs.bitcoin-com', {
|
||||
url: '/bitcoincom',
|
||||
.state('tabs.giftcards.mercadoLibre', {
|
||||
url: '/mercadoLibre',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'bitcoincomController',
|
||||
templateUrl: 'views/bitcoincom.html'
|
||||
controller: 'mercadoLibreController',
|
||||
templateUrl: 'views/mercadoLibre.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/* buy.Bitcoin.com */
|
||||
.state('tabs.buyandsell.bitcoindotcom', {
|
||||
url: '/buyBitcoindotcom',
|
||||
.state('tabs.giftcards.mercadoLibre.cards', {
|
||||
url: '/cards',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'buyBitcoindotcomController',
|
||||
templateUrl: 'views/buyBitcoindotcom.html'
|
||||
controller: 'mercadoLibreCardsController',
|
||||
templateUrl: 'views/mercadoLibreCards.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
invoiceId: null
|
||||
}
|
||||
})
|
||||
|
||||
/* Price Chart */
|
||||
.state('tabs.pricechart', {
|
||||
url: '/pricechart',
|
||||
.state('tabs.giftcards.mercadoLibre.amount', {
|
||||
url: '/amount',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'pricechartController',
|
||||
templateUrl: 'views/pricechart.html'
|
||||
controller: 'amountController',
|
||||
templateUrl: 'views/amount.html'
|
||||
}
|
||||
},
|
||||
params: {
|
||||
nextStep: 'tabs.giftcards.mercadoLibre.buy',
|
||||
currency: 'BRL',
|
||||
coin: 'btc',
|
||||
fixedUnit: 1,
|
||||
}
|
||||
})
|
||||
.state('tabs.giftcards.mercadoLibre.buy', {
|
||||
url: '/buy/:amount/:currency',
|
||||
views: {
|
||||
'tab-home@tabs': {
|
||||
controller: 'buyMercadoLibreController',
|
||||
templateUrl: 'views/buyMercadoLibre.html'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1098,7 +1137,8 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
params: {
|
||||
nextStep: 'tabs.giftcards.amazon.buy',
|
||||
currency: 'USD',
|
||||
forceCurrency: true
|
||||
coin: 'btc',
|
||||
fixedUnit: true,
|
||||
}
|
||||
})
|
||||
.state('tabs.giftcards.amazon.buy', {
|
||||
|
|
@ -1138,6 +1178,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
params: {
|
||||
id: null,
|
||||
currency: 'USD',
|
||||
coin: 'btc',
|
||||
useSendMax: null
|
||||
}
|
||||
})
|
||||
|
|
@ -1169,7 +1210,7 @@ angular.module('copayApp').config(function(historicLogProvider, $provide, $logPr
|
|||
}
|
||||
});
|
||||
})
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, startupService, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ glideraService, buydotbitcoindotcomService, amazonService, bitpayCardService, applicationService) {
|
||||
.run(function($rootScope, $state, $location, $log, $timeout, startupService, ionicToast, fingerprintService, $ionicHistory, $ionicPlatform, $window, appConfigService, lodash, platformInfo, profileService, uxLanguage, gettextCatalog, openURLService, storageService, scannerService, configService, emailService, /* plugins START HERE => */ coinbaseService, glideraService, amazonService, bitpayCardService, applicationService, mercadoLibreService) {
|
||||
|
||||
uxLanguage.init();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,19 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('addressbookService', function(bitcore, storageService, lodash) {
|
||||
angular.module('copayApp.services').factory('addressbookService', function($log, bitcore, bitcoreCash, storageService, lodash) {
|
||||
var root = {};
|
||||
|
||||
var getNetwork = function(address) {
|
||||
var network;
|
||||
try {
|
||||
network = (new bitcore.Address(address)).network.name;
|
||||
} catch(e) {
|
||||
$log.warn('No valid bitcoin address. Trying bitcoin cash...');
|
||||
network = (new bitcoreCash.Address(address)).network.name;
|
||||
}
|
||||
return network;
|
||||
};
|
||||
|
||||
root.get = function(addr, cb) {
|
||||
storageService.getAddressbook('testnet', function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -35,7 +46,8 @@ angular.module('copayApp.services').factory('addressbookService', function(bitco
|
|||
};
|
||||
|
||||
root.add = function(entry, cb) {
|
||||
var network = (new bitcore.Address(entry.address)).network.name;
|
||||
var network = getNetwork(entry.address);
|
||||
if (lodash.isEmpty(network)) return cb('Not valid bitcoin address');
|
||||
storageService.getAddressbook(network, function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
if (ab) ab = JSON.parse(ab);
|
||||
|
|
@ -53,7 +65,8 @@ angular.module('copayApp.services').factory('addressbookService', function(bitco
|
|||
};
|
||||
|
||||
root.remove = function(addr, cb) {
|
||||
var network = (new bitcore.Address(addr)).network.name;
|
||||
var network = getNetwork(addr);
|
||||
if (lodash.isEmpty(network)) return cb('Not valid bitcoin address');
|
||||
storageService.getAddressbook(network, function(err, ab) {
|
||||
if (err) return cb(err);
|
||||
if (ab) ab = JSON.parse(ab);
|
||||
|
|
|
|||
6
src/js/services/bitcoreCash.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services')
|
||||
.factory('bitcoreCash', function bitcoreFactory(bwcService) {
|
||||
var bitcoreCash = bwcService.getBitcoreCash();
|
||||
return bitcoreCash;
|
||||
});
|
||||
|
|
@ -53,6 +53,7 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
'wallet:sells:create,' +
|
||||
'wallet:transactions:read,' +
|
||||
'wallet:transactions:send,' +
|
||||
'wallet:transactions:send:bypass-2fa,' +
|
||||
'wallet:payment-methods:read';
|
||||
|
||||
// NW has a bug with Window Object
|
||||
|
|
@ -169,9 +170,9 @@ angular.module('copayApp.services').factory('coinbaseService', function($http, $
|
|||
var _getNetAmount = function(amount, cb) {
|
||||
// Fee Normal for a single transaction (450 bytes)
|
||||
var txNormalFeeKB = 450 / 1000;
|
||||
feeService.getFeeRate(null, 'normal', function(err, feePerKB) {
|
||||
feeService.getFeeRate('btc', 'livenet', 'normal', function(err, feePerKb) {
|
||||
if (err) return cb(err);
|
||||
var feeBTC = (feePerKB * txNormalFeeKB / 100000000).toFixed(8);
|
||||
var feeBTC = (feePerKb * txNormalFeeKB / 100000000).toFixed(8);
|
||||
|
||||
return cb(null, amount - feeBTC, feeBTC);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -69,7 +69,8 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
bannedUntil: null,
|
||||
},
|
||||
|
||||
// External services
|
||||
cashSupport: false,
|
||||
|
||||
recentTransactions: {
|
||||
enabled: true,
|
||||
},
|
||||
|
|
@ -141,6 +142,11 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
configCache.hideNextSteps = defaultConfig.hideNextSteps;
|
||||
}
|
||||
|
||||
|
||||
if (!configCache.cashSupport) {
|
||||
configCache.cashSupport = defaultConfig.cashSupport;
|
||||
}
|
||||
|
||||
if (!configCache.recentTransactions) {
|
||||
configCache.recentTransactions = defaultConfig.recentTransactions;
|
||||
}
|
||||
|
|
@ -151,6 +157,14 @@ angular.module('copayApp.services').factory('configService', function(storageSer
|
|||
configCache.bitpayAccount = defaultConfig.bitpayAccount;
|
||||
}
|
||||
|
||||
if (configCache.wallet.settings.unitCode == 'bit') {
|
||||
// Convert to BTC. Bits will be disabled
|
||||
configCache.wallet.settings.unitName = defaultConfig.wallet.settings.unitName;
|
||||
configCache.wallet.settings.unitToSatoshi = defaultConfig.wallet.settings.unitToSatoshi;
|
||||
configCache.wallet.settings.unitDecimals = defaultConfig.wallet.settings.unitDecimals;
|
||||
configCache.wallet.settings.unitCode = defaultConfig.wallet.settings.unitCode;
|
||||
}
|
||||
|
||||
} else {
|
||||
configCache = lodash.clone(defaultConfig);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
|
||||
var cache = {
|
||||
updateTs: 0,
|
||||
coin: ''
|
||||
};
|
||||
|
||||
root.getCurrentFeeLevel = function() {
|
||||
|
|
@ -24,20 +25,20 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
};
|
||||
|
||||
|
||||
root.getFeeRate = function(network, feeLevel, cb) {
|
||||
root.getFeeRate = function(coin, network, feeLevel, cb) {
|
||||
|
||||
if (feeLevel == 'custom') return cb();
|
||||
|
||||
network = network || 'livenet';
|
||||
|
||||
root.getFeeLevels(function(err, levels, fromCache) {
|
||||
root.getFeeLevels(coin, function(err, levels, fromCache) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var feeLevelRate = lodash.find(levels[network], {
|
||||
level: feeLevel
|
||||
});
|
||||
|
||||
if (!feeLevelRate || !feeLevelRate.feePerKB) {
|
||||
if (!feeLevelRate || !feeLevelRate.feePerKb) {
|
||||
return cb({
|
||||
message: gettextCatalog.getString("Could not get dynamic fee for level: {{feeLevel}}", {
|
||||
feeLevel: feeLevel
|
||||
|
|
@ -45,34 +46,35 @@ angular.module('copayApp.services').factory('feeService', function($log, $timeou
|
|||
});
|
||||
}
|
||||
|
||||
var feeRate = feeLevelRate.feePerKB;
|
||||
var feeRate = feeLevelRate.feePerKb;
|
||||
|
||||
if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKB / 1000).toFixed() + ' SAT/B');
|
||||
if (!fromCache) $log.debug('Dynamic fee: ' + feeLevel + '/' + network + ' ' + (feeLevelRate.feePerKb / 1000).toFixed() + ' SAT/B');
|
||||
|
||||
return cb(null, feeRate);
|
||||
});
|
||||
};
|
||||
|
||||
root.getCurrentFeeRate = function(network, cb) {
|
||||
return root.getFeeRate(network, root.getCurrentFeeLevel(), cb);
|
||||
root.getCurrentFeeRate = function(coin, network, cb) {
|
||||
return root.getFeeRate(coin, network, root.getCurrentFeeLevel(), cb);
|
||||
};
|
||||
|
||||
root.getFeeLevels = function(cb) {
|
||||
root.getFeeLevels = function(coin, cb) {
|
||||
coin = coin || 'btc';
|
||||
|
||||
if (cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) {
|
||||
if (cache.coin == coin && cache.updateTs > Date.now() - CACHE_TIME_TS * 1000) {
|
||||
return cb(null, cache.data, true);
|
||||
}
|
||||
|
||||
var walletClient = bwcService.getClient();
|
||||
var unitName = configService.getSync().wallet.settings.unitName;
|
||||
|
||||
walletClient.getFeeLevels('livenet', function(errLivenet, levelsLivenet) {
|
||||
walletClient.getFeeLevels('testnet', function(errTestnet, levelsTestnet) {
|
||||
walletClient.getFeeLevels(coin, 'livenet', function(errLivenet, levelsLivenet) {
|
||||
walletClient.getFeeLevels('btc', 'testnet', function(errTestnet, levelsTestnet) {
|
||||
if (errLivenet || errTestnet) {
|
||||
return cb(gettextCatalog.getString('Could not get dynamic fee'));
|
||||
}
|
||||
|
||||
cache.updateTs = Date.now();
|
||||
cache.coin = coin;
|
||||
cache.data = {
|
||||
'livenet': levelsLivenet,
|
||||
'testnet': levelsTestnet
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ angular.module('copayApp.services')
|
|||
};
|
||||
|
||||
root.add = function(level, msg) {
|
||||
msg = msg.replace('/xpriv.*/', 'xpriv[Hidden]');
|
||||
logs.push({
|
||||
timestamp: new Date().toISOString(),
|
||||
level: level,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, $rootScope, payproService, scannerService, appConfigService, popupService, gettextCatalog) {
|
||||
angular.module('copayApp.services').factory('incomingData', function($log, $state, $timeout, $ionicHistory, bitcore, bitcoreCash, $rootScope, payproService, scannerService, appConfigService, popupService, gettextCatalog) {
|
||||
|
||||
var root = {};
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
return true;
|
||||
}
|
||||
|
||||
function goSend(addr, amount, message) {
|
||||
function goSend(addr, amount, message, coin) {
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
|
|
@ -57,18 +57,20 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
$state.transitionTo('tabs.send.confirm', {
|
||||
toAmount: amount,
|
||||
toAddress: addr,
|
||||
description: message
|
||||
description: message,
|
||||
coin: coin
|
||||
});
|
||||
} else {
|
||||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: addr
|
||||
toAddress: addr,
|
||||
coin: coin
|
||||
});
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
// data extensions for Payment Protocol with non-backwards-compatible request
|
||||
if ((/^bitcoin:\?r=[\w+]/).exec(data)) {
|
||||
data = decodeURIComponent(data.replace('bitcoin:?r=', ''));
|
||||
if ((/^bitcoin(cash)?:\?r=[\w+]/).exec(data)) {
|
||||
data = decodeURIComponent(data.replace(/bitcoin(cash)?:\?r=/, ''));
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
|
|
@ -82,27 +84,97 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
|
||||
data = sanitizeUri(data);
|
||||
|
||||
// BIP21
|
||||
// Bitcoin URL
|
||||
if (bitcore.URI.isValid(data)) {
|
||||
var parsed = new bitcore.URI(data);
|
||||
var coin = 'btc';
|
||||
var parsed = new bitcore.URI(data);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount) goSend(addr, amount, message);
|
||||
else popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
} else handlePayPro(details);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message);
|
||||
}
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount) goSend(addr, amount, message, coin);
|
||||
else popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
} else handlePayPro(details);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
return true;
|
||||
// Cash URI
|
||||
} else if (bitcoreCash.URI.isValid(data)) {
|
||||
var coin = 'bch';
|
||||
var parsed = new bitcoreCash.URI(data);
|
||||
|
||||
var addr = parsed.address ? parsed.address.toString() : '';
|
||||
var message = parsed.message;
|
||||
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
// paypro not yet supported on cash
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount)
|
||||
goSend(addr, amount, message, coin);
|
||||
else
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
}
|
||||
handlePayPro(details, coin);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
return true;
|
||||
|
||||
// Cash URI with bitcoin core address version number?
|
||||
} else if (bitcore.URI.isValid(data.replace(/^bitcoincash:/,'bitcoin:'))) {
|
||||
$log.debug('Handling bitcoincash URI with legacy address');
|
||||
var coin = 'bch';
|
||||
var parsed = new bitcore.URI(data.replace(/^bitcoincash:/,'bitcoin:'));
|
||||
|
||||
var oldAddr = parsed.address ? parsed.address.toString() : '';
|
||||
if (!oldAddr) return false;
|
||||
|
||||
var addr = '';
|
||||
|
||||
var a = bitcore.Address(oldAddr).toObject();
|
||||
addr = bitcoreCash.Address.fromObject(a).toString();
|
||||
|
||||
// Translate address
|
||||
$log.debug('address transalated to:' + addr);
|
||||
popupService.showConfirm(
|
||||
gettextCatalog.getString('Bitcoin cash Payment'),
|
||||
gettextCatalog.getString('Payment address was translated to new Bitcoin Cash address format: ' + addr),
|
||||
gettextCatalog.getString('OK'),
|
||||
gettextCatalog.getString('Cancel'),
|
||||
function(ret) {
|
||||
if (!ret) return false;
|
||||
|
||||
var message = parsed.message;
|
||||
var amount = parsed.amount ? parsed.amount : '';
|
||||
|
||||
// paypro not yet supported on cash
|
||||
if (parsed.r) {
|
||||
payproService.getPayProDetails(parsed.r, function(err, details) {
|
||||
if (err) {
|
||||
if (addr && amount)
|
||||
goSend(addr, amount, message, coin);
|
||||
else
|
||||
popupService.showAlert(gettextCatalog.getString('Error'), err);
|
||||
}
|
||||
handlePayPro(details, coin);
|
||||
});
|
||||
} else {
|
||||
goSend(addr, amount, message, coin);
|
||||
}
|
||||
}
|
||||
);
|
||||
return true;
|
||||
|
||||
// Plain URL
|
||||
} else if (/^https?:\/\//.test(data)) {
|
||||
|
||||
|
|
@ -127,6 +199,16 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
} else {
|
||||
goToAmountPage(data);
|
||||
}
|
||||
} else if (bitcoreCash.Address.isValid(data, 'livenet')) {
|
||||
if ($state.includes('tabs.scan')) {
|
||||
root.showMenu({
|
||||
data: data,
|
||||
type: 'bitcoinAddress',
|
||||
coin: 'bch',
|
||||
});
|
||||
} else {
|
||||
goToAmountPage(data, 'bch');
|
||||
}
|
||||
} else if (data && data.indexOf(appConfigService.name + '://glidera') === 0) {
|
||||
var code = getParameterByName('code', data);
|
||||
$ionicHistory.nextViewOptions({
|
||||
|
|
@ -236,29 +318,29 @@ angular.module('copayApp.services').factory('incomingData', function($log, $stat
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
function goToAmountPage(toAddress) {
|
||||
function goToAmountPage(toAddress, coin) {
|
||||
$state.go('tabs.send', {}, {
|
||||
'reload': true,
|
||||
'notify': $state.current.name == 'tabs.send' ? false : true
|
||||
});
|
||||
$timeout(function() {
|
||||
$state.transitionTo('tabs.send.amount', {
|
||||
toAddress: toAddress
|
||||
toAddress: toAddress,
|
||||
coin: coin,
|
||||
});
|
||||
}, 100);
|
||||
}
|
||||
|
||||
function handlePayPro(payProDetails) {
|
||||
function handlePayPro(payProDetails, coin) {
|
||||
var stateParams = {
|
||||
toAmount: payProDetails.amount,
|
||||
toAddress: payProDetails.toAddress,
|
||||
description: payProDetails.memo,
|
||||
paypro: payProDetails
|
||||
paypro: payProDetails,
|
||||
coin: coin,
|
||||
};
|
||||
scannerService.pausePreview();
|
||||
$state.go('tabs.send', {}, {
|
||||
|
|
|
|||
183
src/js/services/mercadoLibreService.js
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services').factory('mercadoLibreService', function($http, $log, lodash, moment, storageService, configService, platformInfo, nextStepsService, homeIntegrationsService) {
|
||||
var root = {};
|
||||
var credentials = {};
|
||||
|
||||
// Not used yet
|
||||
var availableCountries = [{
|
||||
'country': 'Brazil',
|
||||
'currency': 'BRL',
|
||||
'name': 'Mercado Livre',
|
||||
'url': 'https://www.mercadolivre.com.br'
|
||||
}];
|
||||
|
||||
/*
|
||||
* Development: 'testnet'
|
||||
* Production: 'livenet'
|
||||
*/
|
||||
credentials.NETWORK = 'livenet';
|
||||
//credentials.NETWORK = 'testnet';
|
||||
|
||||
if (credentials.NETWORK == 'testnet') {
|
||||
credentials.BITPAY_API_URL = "https://test.bitpay.com";
|
||||
} else {
|
||||
credentials.BITPAY_API_URL = "https://bitpay.com";
|
||||
};
|
||||
|
||||
var homeItem = {
|
||||
name: 'mercadoLibre',
|
||||
title: 'Vales-Presente do Mercado Livre Brasil',
|
||||
icon: 'icon-ml',
|
||||
sref: 'tabs.giftcards.mercadoLibre',
|
||||
};
|
||||
|
||||
var nextStepItem = {
|
||||
name: 'mercadoLibre',
|
||||
title: 'Comprar um Vale-Presente Mercado Livre',
|
||||
icon: 'icon-ml',
|
||||
sref: 'tabs.giftcards.mercadoLibre',
|
||||
};
|
||||
|
||||
var _getBitPay = function(endpoint) {
|
||||
return {
|
||||
method: 'GET',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var _postBitPay = function(endpoint, data) {
|
||||
return {
|
||||
method: 'POST',
|
||||
url: credentials.BITPAY_API_URL + endpoint,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
data: data
|
||||
};
|
||||
};
|
||||
|
||||
root.getNetwork = function() {
|
||||
return credentials.NETWORK;
|
||||
};
|
||||
|
||||
root.savePendingGiftCard = function(gc, opts, cb) {
|
||||
var network = root.getNetwork();
|
||||
storageService.getMercadoLibreGiftCards(network, function(err, oldGiftCards) {
|
||||
if (lodash.isString(oldGiftCards)) {
|
||||
oldGiftCards = JSON.parse(oldGiftCards);
|
||||
}
|
||||
if (lodash.isString(gc)) {
|
||||
gc = JSON.parse(gc);
|
||||
}
|
||||
var inv = oldGiftCards || {};
|
||||
inv[gc.invoiceId] = gc;
|
||||
if (opts && (opts.error || opts.status)) {
|
||||
inv[gc.invoiceId] = lodash.assign(inv[gc.invoiceId], opts);
|
||||
}
|
||||
if (opts && opts.remove) {
|
||||
delete(inv[gc.invoiceId]);
|
||||
}
|
||||
|
||||
inv = JSON.stringify(inv);
|
||||
|
||||
|
||||
storageService.setMercadoLibreGiftCards(network, inv, function(err) {
|
||||
|
||||
homeIntegrationsService.register(homeItem);
|
||||
nextStepsService.unregister(nextStepItem.name);
|
||||
return cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
root.getPendingGiftCards = function(cb) {
|
||||
var network = root.getNetwork();
|
||||
storageService.getMercadoLibreGiftCards(network, function(err, giftCards) {
|
||||
var _gcds = giftCards ? JSON.parse(giftCards) : null;
|
||||
return cb(err, _gcds);
|
||||
});
|
||||
};
|
||||
|
||||
root.createBitPayInvoice = function(data, cb) {
|
||||
var dataSrc = {
|
||||
currency: data.currency,
|
||||
amount: data.amount,
|
||||
clientId: data.uuid
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/pay', dataSrc)).then(function(data) {
|
||||
$log.info('BitPay Create Invoice: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('BitPay Create Invoice: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
root.getBitPayInvoice = function(id, cb) {
|
||||
$http(_getBitPay('/invoices/' + id)).then(function(data) {
|
||||
$log.info('BitPay Get Invoice: SUCCESS');
|
||||
return cb(null, data.data.data);
|
||||
}, function(data) {
|
||||
$log.error('BitPay Get Invoice: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
root.createGiftCard = function(data, cb) {
|
||||
var dataSrc = {
|
||||
"clientId": data.uuid,
|
||||
"invoiceId": data.invoiceId,
|
||||
"accessKey": data.accessKey
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/redeem', dataSrc)).then(function(data) {
|
||||
var status = data.data.status == 'new' ? 'PENDING' : (data.data.status == 'paid') ? 'PENDING' : data.data.status;
|
||||
data.data.status = status;
|
||||
$log.info('Mercado Libre Gift Card Create/Update: ' + status);
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Mercado Libre Gift Card Create/Update: ERROR', JSON.stringify(data.data));
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Disabled for now *
|
||||
*/
|
||||
/*
|
||||
root.cancelGiftCard = function(data, cb) {
|
||||
|
||||
var dataSrc = {
|
||||
"clientId": data.uuid,
|
||||
"invoiceId": data.invoiceId,
|
||||
"accessKey": data.accessKey
|
||||
};
|
||||
|
||||
$http(_postBitPay('/mercado-libre-gift/cancel', dataSrc)).then(function(data) {
|
||||
$log.info('Mercado Libre Gift Card Cancel: SUCCESS');
|
||||
return cb(null, data.data);
|
||||
}, function(data) {
|
||||
$log.error('Mercado Libre Gift Card Cancel: ' + data.data.message);
|
||||
return cb(data.data);
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
var register = function() {
|
||||
storageService.getMercadoLibreGiftCards(root.getNetwork(), function(err, giftCards) {
|
||||
if (giftCards) {
|
||||
homeIntegrationsService.register(homeItem);
|
||||
} else {
|
||||
nextStepsService.register(nextStepItem);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Hide Mercado Libre
|
||||
// register();
|
||||
return root;
|
||||
});
|
||||
|
|
@ -45,7 +45,8 @@ angular.module('copayApp.services').factory('ongoingProcess', function($log, $ti
|
|||
'cancelingGiftCard': 'Canceling Gift Card...',
|
||||
'creatingGiftCard': 'Creating Gift Card...',
|
||||
'buyingGiftCard': 'Buying Gift Card...',
|
||||
'topup': gettext('Top up in progress...')
|
||||
'topup': gettext('Top up in progress...'),
|
||||
'duplicatingWallet': gettext('Duplicating wallet...'),
|
||||
};
|
||||
|
||||
root.clear = function() {
|
||||
|
|
|
|||
|
|
@ -57,10 +57,10 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
|
||||
// This event is sent to an existent instance of Copay (only for standalone apps)
|
||||
gui.App.on('open', function(pathData) {
|
||||
if (pathData.indexOf('bitcoin:') != -1) {
|
||||
if (pathData.indexOf(/^bitcoin(cash)?:/) != -1) {
|
||||
$log.debug('Bitcoin URL found');
|
||||
handleOpenURL({
|
||||
url: pathData.substring(pathData.indexOf('bitcoin:'))
|
||||
url: pathData.substring(pathData.indexOf(/^bitcoin(cash)?:/))
|
||||
});
|
||||
} else if (pathData.indexOf(appConfigService.name + '://') != -1) {
|
||||
$log.debug(appConfigService.name + ' URL found');
|
||||
|
|
@ -84,6 +84,7 @@ angular.module('copayApp.services').factory('openURLService', function($rootScop
|
|||
if (navigator.registerProtocolHandler) {
|
||||
$log.debug('Registering Browser handlers base:' + base);
|
||||
navigator.registerProtocolHandler('bitcoin', url, 'Copay Bitcoin Handler');
|
||||
navigator.registerProtocolHandler('web+bitcoincash', url, 'Copay Bitcoin Cash Handler');
|
||||
navigator.registerProtocolHandler('web+copay', url, 'Copay Wallet Handler');
|
||||
navigator.registerProtocolHandler('web+bitpay', url, 'BitPay Wallet Handler');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
angular.module('copayApp.services')
|
||||
.factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, sjcl, lodash, storageService, bwcService, configService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, $state) {
|
||||
.factory('profileService', function profileServiceFactory($rootScope, $timeout, $filter, $log, $state, sjcl, lodash, storageService, bwcService, configService, gettextCatalog, bwcError, uxLanguage, platformInfo, txFormatService, appConfigService) {
|
||||
|
||||
|
||||
var isChromeApp = platformInfo.isChromeApp;
|
||||
|
|
@ -89,6 +89,7 @@ angular.module('copayApp.services')
|
|||
wallet.copayerId = wallet.credentials.copayerId;
|
||||
wallet.m = wallet.credentials.m;
|
||||
wallet.n = wallet.credentials.n;
|
||||
wallet.coin = wallet.credentials.coin;
|
||||
|
||||
root.updateWalletSettings(wallet);
|
||||
root.wallet[walletId] = wallet;
|
||||
|
|
@ -222,11 +223,12 @@ angular.module('copayApp.services')
|
|||
return ((config.bwsFor && config.bwsFor[walletId]) || defaults.bws.url);
|
||||
};
|
||||
|
||||
|
||||
var client = bwcService.getClient(JSON.stringify(credentials), {
|
||||
bwsurl: getBWSURL(credentials.walletId),
|
||||
});
|
||||
|
||||
|
||||
|
||||
var skipKeyValidation = shouldSkipValidation(credentials.walletId);
|
||||
if (!skipKeyValidation)
|
||||
root.runValidation(client, 500);
|
||||
|
|
@ -328,6 +330,7 @@ angular.module('copayApp.services')
|
|||
passphrase: opts.passphrase,
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
});
|
||||
|
||||
} catch (ex) {
|
||||
|
|
@ -336,7 +339,12 @@ angular.module('copayApp.services')
|
|||
}
|
||||
} else if (opts.extendedPrivateKey) {
|
||||
try {
|
||||
walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey);
|
||||
walletClient.seedFromExtendedPrivateKey(opts.extendedPrivateKey, {
|
||||
network: network,
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin,
|
||||
});
|
||||
} catch (ex) {
|
||||
$log.warn(ex);
|
||||
return cb(gettextCatalog.getString('Could not create using the specified extended private key'));
|
||||
|
|
@ -346,6 +354,7 @@ angular.module('copayApp.services')
|
|||
walletClient.seedFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, {
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
});
|
||||
walletClient.credentials.hwInfo = opts.hwInfo;
|
||||
} catch (ex) {
|
||||
|
|
@ -360,6 +369,7 @@ angular.module('copayApp.services')
|
|||
passphrase: opts.passphrase,
|
||||
language: lang,
|
||||
account: 0,
|
||||
coin: opts.coin
|
||||
});
|
||||
} catch (e) {
|
||||
$log.info('Error creating recovery phrase: ' + e.message);
|
||||
|
|
@ -369,6 +379,7 @@ angular.module('copayApp.services')
|
|||
network: network,
|
||||
passphrase: opts.passphrase,
|
||||
account: 0,
|
||||
coin: opts.coin
|
||||
});
|
||||
} else {
|
||||
return cb(e);
|
||||
|
|
@ -380,7 +391,11 @@ angular.module('copayApp.services')
|
|||
|
||||
// Creates a wallet on BWC/BWS
|
||||
var doCreateWallet = function(opts, cb) {
|
||||
$log.debug('Creating Wallet:', opts);
|
||||
var showOpts = lodash.clone(opts);
|
||||
if (showOpts.extendedPrivateKey) showOpts.extendedPrivateKey='[hidden]';
|
||||
if (showOpts.mnemonic) showOpts.mnemonic='[hidden]';
|
||||
|
||||
$log.debug('Creating Wallet:', showOpts);
|
||||
$timeout(function() {
|
||||
seedWallet(opts, function(err, walletClient) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -392,6 +407,7 @@ angular.module('copayApp.services')
|
|||
network: opts.networkName,
|
||||
singleAddress: opts.singleAddress,
|
||||
walletPrivKey: opts.walletPrivKey,
|
||||
coin: opts.coin
|
||||
}, function(err, secret) {
|
||||
if (err) return bwcError.cb(err, gettextCatalog.getString('Error creating wallet'), cb);
|
||||
return cb(null, walletClient, secret);
|
||||
|
|
@ -435,7 +451,9 @@ angular.module('copayApp.services')
|
|||
seedWallet(opts, function(err, walletClient) {
|
||||
if (err) return cb(err);
|
||||
|
||||
walletClient.joinWallet(opts.secret, opts.myName || 'me', {}, function(err) {
|
||||
walletClient.joinWallet(opts.secret, opts.myName || 'me', {
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) return bwcError.cb(err, gettextCatalog.getString('Could not join wallet'), cb);
|
||||
addAndBindWalletClient(walletClient, {
|
||||
bwsurl: opts.bwsurl
|
||||
|
|
@ -495,7 +513,9 @@ angular.module('copayApp.services')
|
|||
var walletId = client.credentials.walletId
|
||||
|
||||
if (!root.profile.addWallet(JSON.parse(client.export())))
|
||||
return cb(gettextCatalog.getString('Wallet already in Copay'));
|
||||
return cb(gettextCatalog.getString("Wallet already in {{appName}}", {
|
||||
appName: appConfigService.nameCase
|
||||
}));
|
||||
|
||||
|
||||
var skipKeyValidation = shouldSkipValidation(walletId);
|
||||
|
|
@ -621,6 +641,7 @@ angular.module('copayApp.services')
|
|||
entropySourcePath: opts.entropySourcePath,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
account: opts.account || 0,
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
if (err instanceof errors.NOT_AUTHORIZED)
|
||||
|
|
@ -642,6 +663,7 @@ angular.module('copayApp.services')
|
|||
walletClient.importFromExtendedPublicKey(opts.extendedPublicKey, opts.externalSource, opts.entropySource, {
|
||||
account: opts.account || 0,
|
||||
derivationStrategy: opts.derivationStrategy || 'BIP44',
|
||||
coin: opts.coin
|
||||
}, function(err) {
|
||||
if (err) {
|
||||
|
||||
|
|
@ -682,6 +704,7 @@ angular.module('copayApp.services')
|
|||
opts.m = 1;
|
||||
opts.n = 1;
|
||||
opts.networkName = 'livenet';
|
||||
opts.coin = 'btc';
|
||||
root.createWallet(opts, cb);
|
||||
};
|
||||
|
||||
|
|
@ -747,6 +770,12 @@ angular.module('copayApp.services')
|
|||
|
||||
var ret = lodash.values(root.wallet);
|
||||
|
||||
if (opts.coin) {
|
||||
ret = lodash.filter(ret, function(x) {
|
||||
return (x.credentials.coin == opts.coin);
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.network) {
|
||||
ret = lodash.filter(ret, function(x) {
|
||||
return (x.credentials.network == opts.network);
|
||||
|
|
@ -767,12 +796,14 @@ angular.module('copayApp.services')
|
|||
|
||||
if (opts.hasFunds) {
|
||||
ret = lodash.filter(ret, function(w) {
|
||||
if (!w.status) return;
|
||||
return (w.status.availableBalanceSat > 0);
|
||||
});
|
||||
}
|
||||
|
||||
if (opts.minAmount) {
|
||||
ret = lodash.filter(ret, function(w) {
|
||||
if (!w.status) return;
|
||||
return (w.status.availableBalanceSat > opts.minAmount);
|
||||
});
|
||||
}
|
||||
|
|
@ -857,7 +888,7 @@ angular.module('copayApp.services')
|
|||
x.types = [x.type];
|
||||
|
||||
if (x.data && x.data.amount)
|
||||
x.amountStr = txFormatService.formatAmountStr(x.data.amount);
|
||||
x.amountStr = txFormatService.formatAmountStr(x.wallet.coin, x.data.amount);
|
||||
|
||||
x.action = function() {
|
||||
// TODO?
|
||||
|
|
|
|||
|
|
@ -25,9 +25,10 @@ var RateService = function(opts) {
|
|||
self._isAvailable = false;
|
||||
self._rates = {};
|
||||
self._alternatives = [];
|
||||
self._ratesBCH = {};
|
||||
self._queued = [];
|
||||
|
||||
self._fetchCurrencies();
|
||||
self.updateRates();
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -39,14 +40,20 @@ RateService.singleton = function(opts) {
|
|||
return _instance;
|
||||
};
|
||||
|
||||
RateService.prototype._fetchCurrencies = function() {
|
||||
RateService.prototype.updateRates = function() {
|
||||
var self = this;
|
||||
|
||||
var backoffSeconds = 5;
|
||||
var updateFrequencySeconds = 5 * 60;
|
||||
var rateServiceUrl = 'https://bitpay.com/api/rates';
|
||||
var bchRateServiceUrl = 'https://api.kraken.com/0/public/Ticker?pair=BCHUSD,BCHEUR';
|
||||
|
||||
|
||||
function getBTC(cb, tries) {
|
||||
tries = tries || 0;
|
||||
if (!self.httprequest) return;
|
||||
if (tries > 5) return cb('could not get BTC rates');
|
||||
|
||||
var retrieve = function() {
|
||||
//log.info('Fetching exchange rates');
|
||||
self.httprequest.get(rateServiceUrl).success(function(res) {
|
||||
self.lodash.each(res, function(currency) {
|
||||
|
|
@ -57,27 +64,64 @@ RateService.prototype._fetchCurrencies = function() {
|
|||
rate: currency.rate
|
||||
});
|
||||
});
|
||||
|
||||
return cb();
|
||||
}).error(function() {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
getBTC(cb, tries++);
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
})
|
||||
}
|
||||
|
||||
function getBCH(cb, tries) {
|
||||
tries = tries || 0;
|
||||
if (!self.httprequest) return;
|
||||
if (tries > 5) return cb('could not get BCH rates');
|
||||
|
||||
function retry(tries) {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
getBTC(cb, tries++);
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
self.httprequest.get(bchRateServiceUrl).success(function(res) {
|
||||
self.lodash.each(res.result, function(data, paircode) {
|
||||
var code = paircode.substr(3,3);
|
||||
var rate =data.c[0];
|
||||
self._ratesBCH[code] = rate;
|
||||
})
|
||||
return cb();
|
||||
}).error(function() {
|
||||
return retry(tries);
|
||||
})
|
||||
}
|
||||
|
||||
getBTC(function(err) {
|
||||
if (err) return;
|
||||
getBCH(function(err) {
|
||||
if (err) return;
|
||||
|
||||
self._isAvailable = true;
|
||||
self.lodash.each(self._queued, function(callback) {
|
||||
setTimeout(callback, 1);
|
||||
});
|
||||
setTimeout(retrieve, updateFrequencySeconds * 1000);
|
||||
}).error(function(err) {
|
||||
//log.debug('Error fetching exchange rates', err);
|
||||
setTimeout(function() {
|
||||
backoffSeconds *= 1.5;
|
||||
retrieve();
|
||||
}, backoffSeconds * 1000);
|
||||
return;
|
||||
});
|
||||
setTimeout( self.updateRates , updateFrequencySeconds * 1000);
|
||||
})
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
retrieve();
|
||||
};
|
||||
|
||||
RateService.prototype.getRate = function(code) {
|
||||
return this._rates[code];
|
||||
RateService.prototype.getRate = function(code, chain) {
|
||||
if (chain == 'bch')
|
||||
return this._ratesBCH[code];
|
||||
else
|
||||
return this._rates[code];
|
||||
};
|
||||
|
||||
RateService.prototype.getAlternatives = function() {
|
||||
|
|
@ -90,25 +134,25 @@ RateService.prototype.isAvailable = function() {
|
|||
|
||||
RateService.prototype.whenAvailable = function(callback) {
|
||||
if (this.isAvailable()) {
|
||||
setTimeout(callback, 1);
|
||||
setTimeout(callback, 10);
|
||||
} else {
|
||||
this._queued.push(callback);
|
||||
}
|
||||
};
|
||||
|
||||
RateService.prototype.toFiat = function(satoshis, code) {
|
||||
RateService.prototype.toFiat = function(satoshis, code, chain) {
|
||||
if (!this.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return satoshis * this.SAT_TO_BTC * this.getRate(code);
|
||||
return satoshis * this.SAT_TO_BTC * this.getRate(code, chain);
|
||||
};
|
||||
|
||||
RateService.prototype.fromFiat = function(amount, code) {
|
||||
RateService.prototype.fromFiat = function(amount, code, chain) {
|
||||
if (!this.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
return amount / this.getRate(code) * this.BTC_TO_SAT;
|
||||
return amount / this.getRate(code, chain) * this.BTC_TO_SAT;
|
||||
};
|
||||
|
||||
RateService.prototype.listAlternatives = function(sort) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ angular.module('copayApp.services').service('sendMaxService', function(feeServic
|
|||
*
|
||||
*/
|
||||
this.getInfo = function(wallet, cb) {
|
||||
feeService.getCurrentFeeRate(wallet.credentials.network, function(err, feePerKb) {
|
||||
feeService.getCurrentFeeRate(wallet.coin, wallet.credentials.network, function(err, feePerKb) {
|
||||
if (err) return cb(err);
|
||||
|
||||
var config = configService.getSync().wallet;
|
||||
|
|
|
|||
|
|
@ -610,5 +610,17 @@ angular.module('copayApp.services')
|
|||
storage.remove('txConfirmNotif-' + txid, cb);
|
||||
};
|
||||
|
||||
root.setMercadoLibreGiftCards = function(network, gcs, cb) {
|
||||
storage.set('mercadoLibreGiftCards-' + network, gcs, cb);
|
||||
};
|
||||
|
||||
root.getMercadoLibreGiftCards = function(network, cb) {
|
||||
storage.get('mercadoLibreGiftCards-' + network, cb);
|
||||
};
|
||||
|
||||
root.removeMercadoLibreGiftCards = function(network, cb) {
|
||||
storage.remove('MercadoLibreGiftCards-' + network, cb);
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
|
||||
|
||||
root.formatAmount = function(satoshis, fullPrecision) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var config = configService.getDefaults().wallet.settings;
|
||||
if (config.unitCode == 'sat') return satoshis;
|
||||
|
||||
//TODO : now only works for english, specify opts to change thousand separator and decimal separator
|
||||
|
|
@ -17,16 +17,15 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return this.Utils.formatAmount(satoshis, config.unitCode, opts);
|
||||
};
|
||||
|
||||
root.formatAmountStr = function(satoshis) {
|
||||
root.formatAmountStr = function(coin, satoshis) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
return root.formatAmount(satoshis) + ' ' + config.unitName;
|
||||
return root.formatAmount(satoshis) + ' ' + (coin).toUpperCase();
|
||||
};
|
||||
|
||||
root.toFiat = function(satoshis, code, cb) {
|
||||
root.toFiat = function(coin, satoshis, code, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var val = function() {
|
||||
var v1 = rateService.toFiat(satoshis, code);
|
||||
var v1 = rateService.toFiat(satoshis, code, coin);
|
||||
if (!v1) return null;
|
||||
|
||||
return v1.toFixed(2);
|
||||
|
|
@ -43,10 +42,10 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.formatToUSD = function(satoshis, cb) {
|
||||
root.formatToUSD = function(coin, satoshis, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var val = function() {
|
||||
var v1 = rateService.toFiat(satoshis, 'USD');
|
||||
var v1 = rateService.toFiat(satoshis, 'USD', coin);
|
||||
if (!v1) return null;
|
||||
|
||||
return v1.toFixed(2);
|
||||
|
|
@ -63,12 +62,12 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.formatAlternativeStr = function(satoshis, cb) {
|
||||
root.formatAlternativeStr = function(coin, satoshis, cb) {
|
||||
if (isNaN(satoshis)) return;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
var val = function() {
|
||||
var v1 = parseFloat((rateService.toFiat(satoshis, config.alternativeIsoCode)).toFixed(2));
|
||||
var v1 = parseFloat((rateService.toFiat(satoshis, config.alternativeIsoCode, coin)).toFixed(2));
|
||||
v1 = $filter('formatFiatAmount')(v1);
|
||||
if (!v1) return null;
|
||||
|
||||
|
|
@ -86,7 +85,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
};
|
||||
};
|
||||
|
||||
root.processTx = function(tx) {
|
||||
root.processTx = function(coin, tx) {
|
||||
if (!tx || tx.action == 'invalid')
|
||||
return tx;
|
||||
|
||||
|
|
@ -101,17 +100,17 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
tx.hasMultiplesOutputs = true;
|
||||
}
|
||||
tx.amount = lodash.reduce(tx.outputs, function(total, o) {
|
||||
o.amountStr = root.formatAmountStr(o.amount);
|
||||
o.alternativeAmountStr = root.formatAlternativeStr(o.amount);
|
||||
o.amountStr = root.formatAmountStr(coin, o.amount);
|
||||
o.alternativeAmountStr = root.formatAlternativeStr(coin, o.amount);
|
||||
return total + o.amount;
|
||||
}, 0);
|
||||
}
|
||||
tx.toAddress = tx.outputs[0].toAddress;
|
||||
}
|
||||
|
||||
tx.amountStr = root.formatAmountStr(tx.amount);
|
||||
tx.alternativeAmountStr = root.formatAlternativeStr(tx.amount);
|
||||
tx.feeStr = root.formatAmountStr(tx.fee || tx.fees);
|
||||
tx.amountStr = root.formatAmountStr(coin, tx.amount);
|
||||
tx.alternativeAmountStr = root.formatAlternativeStr(coin, tx.amount);
|
||||
tx.feeStr = root.formatAmountStr(coin, tx.fee || tx.fees);
|
||||
|
||||
if (tx.amountStr) {
|
||||
tx.amountValueStr = tx.amountStr.split(' ')[0];
|
||||
|
|
@ -145,8 +144,6 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
|
||||
lodash.each(txps, function(tx) {
|
||||
|
||||
tx = txFormatService.processTx(tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.createdOn > now)
|
||||
tx.createdOn = now;
|
||||
|
|
@ -157,6 +154,8 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return;
|
||||
}
|
||||
|
||||
tx = txFormatService.processTx(tx.wallet.coin, tx);
|
||||
|
||||
var action = lodash.find(tx.actions, {
|
||||
copayerId: tx.wallet.copayerId
|
||||
});
|
||||
|
|
@ -180,7 +179,7 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
return txps;
|
||||
};
|
||||
|
||||
root.parseAmount = function(amount, currency) {
|
||||
root.parseAmount = function(coin, amount, currency) {
|
||||
var config = configService.getSync().wallet.settings;
|
||||
var satToBtc = 1 / 100000000;
|
||||
var unitToSatoshi = config.unitToSatoshi;
|
||||
|
|
@ -189,21 +188,21 @@ angular.module('copayApp.services').factory('txFormatService', function($filter,
|
|||
var alternativeIsoCode = config.alternativeIsoCode;
|
||||
|
||||
// If fiat currency
|
||||
if (currency != 'bits' && currency != 'BTC' && currency != 'sat') {
|
||||
if (currency != 'BCH' && currency != 'BTC' && currency != 'sat') {
|
||||
amountUnitStr = $filter('formatFiatAmount')(amount) + ' ' + currency;
|
||||
amountSat = rateService.fromFiat(amount, currency).toFixed(0);
|
||||
amountSat = rateService.fromFiat(amount, currency, coin).toFixed(0);
|
||||
} else if (currency == 'sat') {
|
||||
amountSat = amount;
|
||||
amountUnitStr = root.formatAmountStr(amountSat);
|
||||
// convert sat to BTC
|
||||
amountUnitStr = root.formatAmountStr(coin, amountSat);
|
||||
// convert sat to BTC or BCH
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
currency = (coin).toUpperCase();
|
||||
} else {
|
||||
amountSat = parseInt((amount * unitToSatoshi).toFixed(0));
|
||||
amountUnitStr = root.formatAmountStr(amountSat);
|
||||
// convert unit to BTC
|
||||
amountUnitStr = root.formatAmountStr(coin, amountSat);
|
||||
// convert unit to BTC or BCH
|
||||
amount = (amountSat * satToBtc).toFixed(8);
|
||||
currency = 'BTC';
|
||||
currency = (coin).toUpperCase();
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,9 @@ angular.module('copayApp.services')
|
|||
}, {
|
||||
name: 'Italiano',
|
||||
isoCode: 'it',
|
||||
}, {
|
||||
name: 'Nederlands',
|
||||
isoCode: 'nl',
|
||||
}, {
|
||||
name: 'Polski',
|
||||
isoCode: 'pl',
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
angular.module('copayApp.services').factory('walletService', function($log, $timeout, lodash, trezor, ledger, intelTEE, storageService, configService, rateService, uxLanguage, $filter, gettextCatalog, bwcError, $ionicPopup, fingerprintService, ongoingProcess, gettext, $rootScope, txFormatService, $ionicModal, $state, bwcService, bitcore, popupService) {
|
||||
|
||||
// Ratio low amount warning (fee/amount) in incoming TX
|
||||
var LOW_AMOUNT_RATIO = 0.15;
|
||||
// Ratio low amount warning (fee/amount) in incoming TX
|
||||
var LOW_AMOUNT_RATIO = 0.15;
|
||||
|
||||
// Ratio of "many utxos" warning in total balance (fee/amount)
|
||||
var TOTAL_LOW_WARNING_RATIO = .3;
|
||||
|
|
@ -104,7 +104,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
root.getStatus = function(wallet, opts, cb) {
|
||||
opts = opts || {};
|
||||
|
||||
var walletId = wallet.id;
|
||||
|
||||
function processPendingTxps(status) {
|
||||
var txps = status.pendingTxps;
|
||||
|
|
@ -130,7 +130,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
lodash.each(txps, function(tx) {
|
||||
|
||||
tx = txFormatService.processTx(tx);
|
||||
tx = txFormatService.processTx(wallet.coin, tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.createdOn > now)
|
||||
|
|
@ -213,14 +213,13 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
// Selected unit
|
||||
cache.unitToSatoshi = config.settings.unitToSatoshi;
|
||||
cache.satToUnit = 1 / cache.unitToSatoshi;
|
||||
cache.unitName = config.settings.unitName;
|
||||
|
||||
//STR
|
||||
cache.totalBalanceStr = txFormatService.formatAmount(cache.totalBalanceSat) + ' ' + cache.unitName;
|
||||
cache.lockedBalanceStr = txFormatService.formatAmount(cache.lockedBalanceSat) + ' ' + cache.unitName;
|
||||
cache.availableBalanceStr = txFormatService.formatAmount(cache.availableBalanceSat) + ' ' + cache.unitName;
|
||||
cache.spendableBalanceStr = txFormatService.formatAmount(cache.spendableAmount) + ' ' + cache.unitName;
|
||||
cache.pendingBalanceStr = txFormatService.formatAmount(cache.pendingAmount) + ' ' + cache.unitName;
|
||||
cache.totalBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.totalBalanceSat);
|
||||
cache.lockedBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.lockedBalanceSat);
|
||||
cache.availableBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.availableBalanceSat);
|
||||
cache.spendableBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.spendableAmount);
|
||||
cache.pendingBalanceStr = txFormatService.formatAmountStr(wallet.coin, cache.pendingAmount);
|
||||
|
||||
cache.alternativeName = config.settings.alternativeName;
|
||||
cache.alternativeIsoCode = config.settings.alternativeIsoCode;
|
||||
|
|
@ -238,11 +237,11 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
rateService.whenAvailable(function() {
|
||||
|
||||
var totalBalanceAlternative = rateService.toFiat(cache.totalBalanceSat, cache.alternativeIsoCode);
|
||||
var pendingBalanceAlternative = rateService.toFiat(cache.pendingAmount, cache.alternativeIsoCode);
|
||||
var lockedBalanceAlternative = rateService.toFiat(cache.lockedBalanceSat, cache.alternativeIsoCode);
|
||||
var spendableBalanceAlternative = rateService.toFiat(cache.spendableAmount, cache.alternativeIsoCode);
|
||||
var alternativeConversionRate = rateService.toFiat(100000000, cache.alternativeIsoCode);
|
||||
var totalBalanceAlternative = rateService.toFiat(cache.totalBalanceSat, cache.alternativeIsoCode, wallet.coin);
|
||||
var pendingBalanceAlternative = rateService.toFiat(cache.pendingAmount, cache.alternativeIsoCode, wallet.coin);
|
||||
var lockedBalanceAlternative = rateService.toFiat(cache.lockedBalanceSat, cache.alternativeIsoCode, wallet.coin);
|
||||
var spendableBalanceAlternative = rateService.toFiat(cache.spendableAmount, cache.alternativeIsoCode, wallet.coin);
|
||||
var alternativeConversionRate = rateService.toFiat(100000000, cache.alternativeIsoCode, wallet.coin);
|
||||
|
||||
cache.totalBalanceAlternative = $filter('formatFiatAmount')(totalBalanceAlternative);
|
||||
cache.pendingBalanceAlternative = $filter('formatFiatAmount')(pendingBalanceAlternative);
|
||||
|
|
@ -260,6 +259,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
};
|
||||
|
||||
function cacheStatus(status) {
|
||||
if (status.wallet && status.wallet.scanStatus == 'running') return;
|
||||
|
||||
wallet.cachedStatus = status || {};
|
||||
var cache = wallet.cachedStatus;
|
||||
cache.statusUpdatedOn = Date.now();
|
||||
|
|
@ -304,6 +305,8 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
|
||||
cacheStatus(status);
|
||||
|
||||
wallet.scanning = status.wallet && status.wallet.scanStatus == 'running';
|
||||
|
||||
return cb(null, status);
|
||||
});
|
||||
};
|
||||
|
|
@ -366,7 +369,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
wallet.hasUnsafeConfirmed = false;
|
||||
|
||||
lodash.each(txs, function(tx) {
|
||||
tx = txFormatService.processTx(tx);
|
||||
tx = txFormatService.processTx(wallet.coin, tx);
|
||||
|
||||
// no future transactions...
|
||||
if (tx.time > now)
|
||||
|
|
@ -400,7 +403,6 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var LIMIT = 50;
|
||||
var requestLimit = FIRST_LIMIT;
|
||||
var walletId = wallet.credentials.walletId;
|
||||
var config = configService.getSync().wallet.settings;
|
||||
|
||||
var opts = opts || {};
|
||||
var progressFn = opts.progressFn || function() {};
|
||||
|
|
@ -414,18 +416,16 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var fixTxsUnit = function(txs) {
|
||||
if (!txs || !txs[0] || !txs[0].amountStr) return;
|
||||
|
||||
var cacheUnit = txs[0].amountStr.split(' ')[1];
|
||||
var cacheCoin = txs[0].amountStr.split(' ')[1];
|
||||
|
||||
if (cacheUnit == config.unitName)
|
||||
return;
|
||||
if (cacheCoin == 'bits') {
|
||||
|
||||
var name = ' ' + config.unitName;
|
||||
|
||||
$log.debug('Fixing Tx Cache Unit to:' + name)
|
||||
lodash.each(txs, function(tx) {
|
||||
tx.amountStr = txFormatService.formatAmount(tx.amount) + name;
|
||||
tx.feeStr = txFormatService.formatAmount(tx.fees) + name;
|
||||
});
|
||||
$log.debug('Fixing Tx Cache Unit to: ' + wallet.coin)
|
||||
lodash.each(txs, function(tx) {
|
||||
tx.amountStr = txFormatService.formatAmountStr(wallet.coin, tx.amount);
|
||||
tx.feeStr = txFormatService.formatAmountStr(wallet.coin, tx.fees);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
getSavedTxs(walletId, function(err, txsFromLocal) {
|
||||
|
|
@ -788,7 +788,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
//prefs.email (may come from arguments)
|
||||
prefs.email = config.emailNotifications.email;
|
||||
prefs.language = uxLanguage.getCurrentLanguage();
|
||||
prefs.unit = walletSettings.unitCode;
|
||||
// prefs.unit = walletSettings.unitCode; // TODO: remove, not used
|
||||
|
||||
updateRemotePreferencesFor(lodash.clone(clients), prefs, function(err) {
|
||||
if (err) return cb(err);
|
||||
|
|
@ -820,13 +820,10 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
$log.debug('Scanning wallet ' + wallet.id);
|
||||
if (!wallet.isComplete()) return;
|
||||
|
||||
wallet.updating = true;
|
||||
ongoingProcess.set('scanning', true);
|
||||
wallet.scanning = true;
|
||||
wallet.startScan({
|
||||
includeCopayerBranches: true,
|
||||
}, function(err) {
|
||||
wallet.updating = false;
|
||||
ongoingProcess.set('scanning', false);
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
|
@ -922,28 +919,30 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
};
|
||||
|
||||
|
||||
// Approx utxo amount, from which the uxto is economically redeemable
|
||||
// Approx utxo amount, from which the uxto is economically redeemable
|
||||
root.getMinFee = function(wallet, feeLevels, nbOutputs) {
|
||||
var lowLevelRate = (lodash.find(feeLevels[wallet.network], {
|
||||
level: 'normal',
|
||||
}).feePerKB / 1000).toFixed(0);
|
||||
}).feePerKb / 1000).toFixed(0);
|
||||
|
||||
var size = root.getEstimatedTxSize(wallet, nbOutputs);
|
||||
return size * lowLevelRate;
|
||||
};
|
||||
|
||||
|
||||
// Approx utxo amount, from which the uxto is economically redeemable
|
||||
// Approx utxo amount, from which the uxto is economically redeemable
|
||||
root.getLowAmount = function(wallet, feeLevels, nbOutputs) {
|
||||
var minFee = root.getMinFee(wallet,feeLevels, nbOutputs);
|
||||
return parseInt( minFee / LOW_AMOUNT_RATIO);
|
||||
var minFee = root.getMinFee(wallet, feeLevels, nbOutputs);
|
||||
return parseInt(minFee / LOW_AMOUNT_RATIO);
|
||||
};
|
||||
|
||||
|
||||
|
||||
root.getLowUtxos = function(wallet, levels, cb) {
|
||||
|
||||
wallet.getUtxos({}, function(err, resp) {
|
||||
wallet.getUtxos({
|
||||
coin: wallet.coin
|
||||
}, function(err, resp) {
|
||||
if (err || !resp || !resp.length) return cb();
|
||||
|
||||
var minFee = root.getMinFee(wallet, levels, resp.length);
|
||||
|
|
@ -959,7 +958,7 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
var totalLow = lodash.sum(lowUtxos, 'satoshis');
|
||||
|
||||
return cb(err, {
|
||||
allUtxos: resp || [],
|
||||
allUtxos: resp || [],
|
||||
lowUtxos: lowUtxos || [],
|
||||
warning: minFee / balance > TOTAL_LOW_WARNING_RATIO,
|
||||
minFee: minFee,
|
||||
|
|
@ -1236,5 +1235,38 @@ angular.module('copayApp.services').factory('walletService', function($log, $tim
|
|||
});
|
||||
};
|
||||
|
||||
root.getProtocolHandler = function(wallet) {
|
||||
if (wallet.coin== 'bch') return 'bitcoincash';
|
||||
else return 'bitcoin';
|
||||
}
|
||||
|
||||
|
||||
root.copyCopayers = function(wallet, newWallet, cb) {
|
||||
var c = wallet.credentials;
|
||||
|
||||
var walletPrivKey = bitcore.PrivateKey.fromString(c.walletPrivKey);
|
||||
|
||||
var copayer = 1,
|
||||
i = 0,
|
||||
l = c.publicKeyRing.length;
|
||||
var mainErr = null;
|
||||
|
||||
lodash.each(c.publicKeyRing, function(item) {
|
||||
var name = item.copayerName || ('copayer ' + copayer++);
|
||||
newWallet._doJoinWallet(newWallet.credentials.walletId, walletPrivKey, item.xPubKey, item.requestPubKey, name, {
|
||||
coin: newWallet.credentials.coin,
|
||||
}, function(err) {
|
||||
//Ignore error is copayer already in wallet
|
||||
if (err && !(err instanceof errors.COPAYER_IN_WALLET)) {
|
||||
mainErr = err;
|
||||
}
|
||||
|
||||
if (++i == l) {
|
||||
return cb(mainErr);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return root;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -139,6 +139,19 @@
|
|||
}
|
||||
}
|
||||
.amount {
|
||||
.icon-toggle {
|
||||
font-size: 1.2em;
|
||||
width: auto;
|
||||
margin: 0.8em auto;
|
||||
border: 1px solid $v-subtle-gray;
|
||||
color: $v-dark-gray;
|
||||
border-radius: 3px;
|
||||
padding: 0 10px;
|
||||
cursor: pointer;
|
||||
@media(max-height: 280px) {
|
||||
margin: 0.1em auto;
|
||||
}
|
||||
}
|
||||
&__editable {
|
||||
&--minimize {
|
||||
font-size: 22px;
|
||||
|
|
@ -187,7 +200,7 @@
|
|||
&__result {
|
||||
color: $v-light-gray;
|
||||
font-size: .9em;
|
||||
margin-bottom: -.9em;
|
||||
//margin-bottom: -.9em; TODO matias
|
||||
line-height: 1;
|
||||
@media(max-height: 480px) {
|
||||
margin-bottom: 0;
|
||||
|
|
@ -196,7 +209,6 @@
|
|||
&__result-equiv {
|
||||
color: $v-mid-gray;
|
||||
font-size: 1.2em;
|
||||
margin-top: 2rem;
|
||||
@media(max-height: 480px) {
|
||||
margin-top: 0;
|
||||
font-size: 16px;
|
||||
|
|
|
|||
43
src/sass/views/cashScan.scss
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#cash-scan {
|
||||
.comment {
|
||||
color: #667;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.item {
|
||||
color: $v-dark-gray;
|
||||
padding-top: 1.3rem;
|
||||
padding-bottom: 1.3rem;
|
||||
}
|
||||
|
||||
.heading {
|
||||
font-size: 17px;
|
||||
color: $v-dark-gray;
|
||||
margin: 1rem 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.text-disabled {
|
||||
color: $v-light-gray;
|
||||
}
|
||||
|
||||
.supported {
|
||||
display: flex;
|
||||
|
||||
.wallet-content {
|
||||
padding-left: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.duplicate-button {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
padding-top: .5rem;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +99,9 @@
|
|||
i {
|
||||
padding-right: 20px;
|
||||
}
|
||||
span {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
.toggle-unconfirmed {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,17 @@ wallet-selector {
|
|||
padding-right: .75rem;
|
||||
}
|
||||
|
||||
.subheader {
|
||||
margin: 20px 0 10px 0;
|
||||
font-weight: bold;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #EFEFEF;
|
||||
.wallet-coin-logo {
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-selector {
|
||||
.wallet {
|
||||
border: 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@import "coinbase";
|
||||
@import "glidera";
|
||||
@import "amazon";
|
||||
@import "mercadolibre";
|
||||
|
||||
#coinbase, #glidera {
|
||||
.button-small {
|
||||
|
|
|
|||
202
src/sass/views/integrations/mercadolibre.scss
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
#mercadolibre {
|
||||
$item-lateral-padding: 20px;
|
||||
$item-vertical-padding: 10px;
|
||||
$item-border-color: #EFEFEF;
|
||||
$item-label-color: #6C6C6E;
|
||||
@extend .deflash-blue;
|
||||
.icon-amazon {
|
||||
background-image: url("../img/mercado-libre/icon-ml.svg");
|
||||
}
|
||||
.spinner svg {
|
||||
stroke: black;
|
||||
fill: black;
|
||||
}
|
||||
|
||||
.add-bottom-for-cta {
|
||||
bottom: 92px;
|
||||
}
|
||||
.head {
|
||||
padding: 30px $item-lateral-padding 4rem;
|
||||
border-top: 0;
|
||||
|
||||
.sending-label {
|
||||
display: flex;
|
||||
font-size: 18px;
|
||||
align-items: center;
|
||||
margin-bottom: 1.8rem;
|
||||
|
||||
img {
|
||||
margin-right: 1rem;
|
||||
height: 35px;
|
||||
width: 35px;
|
||||
}
|
||||
|
||||
span {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.big-icon-svg {
|
||||
padding: 0 7px 0 0;
|
||||
margin-right: 0.6rem;
|
||||
}
|
||||
|
||||
.big-icon-svg > .bg {
|
||||
height: 28px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
}
|
||||
.amount-label{
|
||||
line-height: 30px;
|
||||
.amount{
|
||||
font-size: 38px;
|
||||
margin-bottom: .5rem;
|
||||
|
||||
> .unit {
|
||||
font-family: "Roboto-Light";
|
||||
}
|
||||
}
|
||||
.alternative {
|
||||
font-size: 12px;
|
||||
font-family: "Roboto-Light";
|
||||
color: #9B9B9B;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item {
|
||||
border-color: $item-border-color;
|
||||
}
|
||||
.info {
|
||||
.badge {
|
||||
border-radius: 0;
|
||||
padding: .5rem;
|
||||
}
|
||||
.item {
|
||||
color: #4A4A4A;
|
||||
padding-top: $item-vertical-padding;
|
||||
padding-bottom: $item-vertical-padding;
|
||||
padding-left: $item-lateral-padding;
|
||||
|
||||
&:not(.item-icon-right) {
|
||||
padding-right: $item-lateral-padding;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: $item-label-color;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.capitalized {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.wallet .big-icon-svg > .bg {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
padding: 2px;
|
||||
box-shadow: none;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.total-amount {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&.single-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 17px;
|
||||
padding-bottom: 17px;
|
||||
|
||||
.label {
|
||||
margin: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
.item-divider {
|
||||
padding-top: 1.2rem;
|
||||
color: $item-label-color;
|
||||
font-size: 15px;
|
||||
}
|
||||
.wallet {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: .2rem 0;
|
||||
margin-bottom: 5px;
|
||||
|
||||
~ .bp-arrow-right {
|
||||
top: 14px;
|
||||
}
|
||||
|
||||
> i {
|
||||
padding: 0;
|
||||
position: static;
|
||||
|
||||
> img {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
padding: 2px;
|
||||
margin-right: .7rem;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#meli-list-cards {
|
||||
img.item-logo {
|
||||
width: auto;
|
||||
height: auto;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#meli-card {
|
||||
.card-head {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
.date {
|
||||
font-size: 12px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.amount {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.card-status {
|
||||
text-align: center;
|
||||
margin-bottom: 25px;
|
||||
.card-status-desc {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: $v-text-secondary-color;
|
||||
}
|
||||
.redeem-pin {
|
||||
font-weight: bold;
|
||||
font-size: 22px;
|
||||
}
|
||||
.button-redeem {
|
||||
margin-top: 10px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
color: $v-text-accent-color;
|
||||
}
|
||||
}
|
||||
.card-remove {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
.button-remove {
|
||||
margin-top: 10px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
font-size: 12px;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -17,6 +17,11 @@
|
|||
.icon-amazon {
|
||||
background-image: url("../img/icon-amazon.svg");
|
||||
}
|
||||
.icon-ml {
|
||||
background-image: url("../img/mercado-libre/icon-ml.svg");
|
||||
background-position: center;
|
||||
background-size: 85%;
|
||||
}
|
||||
.bg {
|
||||
&.wallet {
|
||||
padding: .25rem
|
||||
|
|
@ -54,6 +59,10 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
.wallet-coin-logo {
|
||||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.wallet-details__item.item {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
|
|
|||
|
|
@ -20,6 +20,12 @@
|
|||
.has-comment {
|
||||
border-bottom: 0 none;
|
||||
}
|
||||
.scan-label {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
color: $link-color;
|
||||
font-weight: bold;
|
||||
}
|
||||
.comment {
|
||||
padding: 15px;
|
||||
background-color: #fff;
|
||||
|
|
@ -34,6 +40,9 @@
|
|||
width: 20px;
|
||||
}
|
||||
}
|
||||
a {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
&-explanation, &-button-group {
|
||||
padding: 0 1rem;
|
||||
|
|
@ -137,6 +146,14 @@
|
|||
.log-level {
|
||||
font-weight: bold;
|
||||
}
|
||||
.alt-currency-radio {
|
||||
.item-content {
|
||||
padding-right: 16px;
|
||||
}
|
||||
.radio-icon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#tab-settings {
|
||||
|
|
@ -149,6 +166,13 @@
|
|||
border-radius: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
& > .bch {
|
||||
background-color: #9b9bab;
|
||||
border-radius: 1rem;
|
||||
}
|
||||
& > .bch-enabled {
|
||||
background-color: #ff9900 !important;
|
||||
}
|
||||
&.circle{
|
||||
left:8px;
|
||||
.bg {
|
||||
|
|
|
|||
|
|
@ -50,3 +50,4 @@
|
|||
@import "includes/pin";
|
||||
@import "includes/logOptions";
|
||||
@import "includes/checkBar";
|
||||
@import "cashScan";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,22 @@
|
|||
#wallet-backup-phrase {
|
||||
.comment {
|
||||
color: #667;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.item {
|
||||
color: $v-dark-gray;
|
||||
padding-top: 1.3rem;
|
||||
padding-bottom: 1.3rem;
|
||||
border: none;
|
||||
}
|
||||
.heading {
|
||||
font-size: 17px;
|
||||
color: $v-dark-gray;
|
||||
margin: 1rem 0;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
border: none;
|
||||
}
|
||||
h3 {
|
||||
padding: 15px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,6 +88,27 @@
|
|||
padding: 1rem;
|
||||
background: #f8f8f9;
|
||||
}
|
||||
|
||||
&__no-transaction {
|
||||
color: $v-mid-gray;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
&__no-update-history {
|
||||
color: $v-error-color;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
&__updating-history {
|
||||
color: $v-mid-gray;
|
||||
font-size: 12.5px;
|
||||
text-align: center;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
#walletDetails {
|
||||
|
|
@ -177,10 +198,6 @@
|
|||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.collapsible {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
&__balance {
|
||||
-webkit-transform: scale3d(1, 1, 1) translateY(45px);
|
||||
transform: scale3d(1, 1, 1) translateY(45px);
|
||||
|
|
@ -198,8 +215,21 @@
|
|||
&__button-balance {
|
||||
background-color: transparent;
|
||||
border: 1px solid rgba(255,255,255,0.25);
|
||||
margin-top: 10px;
|
||||
i.icon {
|
||||
margin-right: 7px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&__error {
|
||||
font-size: 14px;
|
||||
padding: 35px 20px;
|
||||
}
|
||||
|
||||
}
|
||||
.no-alternative {
|
||||
padding-top: 45px;
|
||||
}
|
||||
.item.item-footer {
|
||||
font-weight: lighter;
|
||||
|
|
@ -237,6 +267,17 @@
|
|||
font-size: 20px;
|
||||
color: #fff;
|
||||
width:95%;
|
||||
|
||||
.actions{
|
||||
float: right;
|
||||
a {
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wallet-not-backed-up-warning {
|
||||
|
|
|
|||
18
www/img/bitcoin-cash-logo.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="49px" height="33px" viewBox="0 0 49 33" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 4</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Home/Overview" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-4" transform="translate(0.000000, -6.000000)" fill-rule="nonzero">
|
||||
<g id="element-icon-bitcoin" transform="translate(24.500000, 22.000000) rotate(-26.000000) translate(-24.500000, -22.000000) translate(8.000000, 6.000000)">
|
||||
<g id="bitcoin" transform="translate(0.000000, -0.000000)">
|
||||
<path d="M32.1867932,19.8608311 C30.0167764,28.4289206 21.2022608,33.6584288 12.4778868,31.5222983 C3.77643011,29.3856664 -1.5352984,20.7067588 0.634718392,12.1386692 C2.80422591,3.57108109 11.6192507,-1.65842708 20.3207074,0.477703406 C29.0450815,2.59177057 34.3563007,11.2932429 32.1867932,19.8608311" id="Shape" fill="#09C286"></path>
|
||||
<path d="M20.8680125,13.6901518 C20.3834958,15.7120375 17.1993056,14.7348781 16.1611297,14.4850856 L17.0381466,10.8958545 C18.0529285,11.1456469 21.3754035,11.5776651 20.8680125,13.6901518 L20.8680125,13.6901518 Z M20.3601017,19.4829825 C19.8298366,21.7091043 15.9994508,20.5507429 14.7767218,20.255394 L15.7228811,16.3027353 C16.9684843,16.5980842 20.9137609,17.1432255 20.3601017,19.4829825 Z M24.4670572,13.6901518 C24.7670209,11.5090745 23.0826493,10.3732354 20.7754761,9.60082384 L21.4908141,6.64784689 L19.6681577,6.21634063 L18.9762137,9.1012389 C18.4916969,8.98760381 18.0071801,8.87396871 17.5226634,8.78336775 L18.2146074,5.89795761 L16.3690768,5.46645136 L15.6537387,8.41994018 C15.2612385,8.32882735 14.8692582,8.26074867 14.4767581,8.16963584 L11.9621576,7.57944995 L11.500515,9.48770061 C11.500515,9.48770061 12.8620487,9.78253763 12.8157805,9.80557177 C13.5539927,9.98728555 13.6922776,10.4643482 13.6694034,10.8277758 L12.8620487,14.1897367 C12.9077971,14.2127709 12.9774594,14.2127709 13.0466018,14.2578154 C12.9774594,14.2352931 12.9311911,14.2352931 12.8620487,14.2127709 L11.7542105,18.914807 C11.6621939,19.1420772 11.4313726,19.4599483 10.9239817,19.3468251 C10.9468558,19.3693474 9.58584199,19.0284421 9.58584199,19.0284421 L8.70882504,21.0958842 L11.0851407,21.6410256 C11.5239091,21.7546607 11.9621576,21.8452617 12.377532,21.9588968 L11.6621939,24.9349079 L13.4848503,25.3664141 L14.2001884,22.4134371 C14.7075794,22.5495945 15.1920961,22.6632296 15.6537387,22.7768647 L14.9384006,25.7073194 L16.7610571,26.1388257 L17.4763951,23.1633264 C20.590923,23.7084678 22.9209704,23.4581634 23.8671298,20.664378 C24.6287361,18.4377443 23.7979873,17.1657478 22.1370098,16.3252576 C23.3597388,16.052431 24.2362359,15.2805313 24.4670572,13.6901518 L24.4670572,13.6901518 Z" id="Shape" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
<path d="M15.921528,5.99999821 L0,5.99999821 L0,37.9999982 L15.913948,37.9999982 C8.54220902,34.2663545 4.45416261,25.9154102 6.54600075,17.6560011 C7.87168946,12.4207324 11.4030305,8.29337503 15.921528,5.99999821 Z M32.6737493,5.99999821 L49,5.99999821 L49,37.9999982 L32.6621291,37.9999982 C37.1847176,35.7065678 40.716075,31.5790477 42.0420849,26.3434332 C44.1319349,18.09042 40.0515857,9.72697744 32.6737493,5.99999821 Z" id="Combined-Shape" fill="#09C286"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
12
www/img/icon-bch.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<g id="Fondo" transform="matrix(0.0814451,-0.0296277,0.0296277,0.0814451,-44.594,-27.3805)">
|
||||
<g transform="matrix(10.8433,3.94452,-3.94452,10.8433,375.543,472.796)">
|
||||
<use xlink:href="#_Image1" x="7.552" y="5.557" width="23.603px" height="28.885px" transform="matrix(0.983467,0,0,0.996049,0,0)"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<image id="_Image1" width="24px" height="29px" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAdCAYAAACwuqxLAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACgUlEQVRIia2WzYuPURTHP88Y7zNEaWJKppnEUKRkM5shdlIipSSDSLazQFYkK/EXeMnChsWUkvK2mCJvWXgpZczGa6EmJn7Mx+K50zzu3OeZ35Tv6t5zzj3fc8859wUmAbVJbZjMmnqcZuo69ZT6XN31v5wuV+eE+XXH8FptrNfXP9tVZ6n7gD7gLrA6qO4BhnEHME1dpk6bbORz1duFaC8E0hXq24L8g/pJfa9eVddMhuSk/+KY+shqDKqb6nE+Q92hfpvAYQrP1QWxz0ydAiwAFgMHgJ6KGPqBH8AMoAvIIn17lmVv4qh71C8VkT1Rj6ob1Jawplk9H9kNq5tTaTlU4fyPurcknV3mxR7FV7UptmsErgNbw3YXAcsK+gZgeUm6BoH5hfltoJa0DHXAvMAxHqvtkf0ctS/scETtj23KiFrUOwmS3UG/VD2nDiXqdDOQ7hkNuIzkeILggflZeFdRr1HU1MtVBN2OPwcjCUfPzHt/MKH/re4vI5hufvxTeKGeUDeqbcF+ieNbVvWjOrOM5HBiwX21s8R+ZmIXI2pz2ePRD7yJZJ1Aa4l9E3nbFjEEtCYJsix7CtyKxM3k10MKs4G5kWwgy7JXVc/fvYSsW11YFKjzgHPAvKIYKO+ksLBNfZioxc6gX6+eVV8m8n9Jba4kCE5OJwgG1BuhS2L8VI9Y75OqbjHv6Sr8iebTiz4m+oJ8B4ZLdDXgM3AGGCjIe9X4nRgX+VTzCyzObS2KvCPY3yzIfxRTVNamNfLrNwN+AV+Ba0Av8KWwdlUYXwHeAxeBbYz9QCp3sTYUc3tB1mB+Y46iz/DbU1snTE09UHvN2/eguvK/OI0IZsedUoW/zudIHkrmZMIAAAAASUVORK5CYII="/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -1,93 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 51 51"
|
||||
style="enable-background:new 0 0 51 51;"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="icon-bitcoin.svg"
|
||||
inkscape:version="0.92.1 r15371"><metadata
|
||||
id="metadata23"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1015"
|
||||
id="namedview21"
|
||||
showgrid="false"
|
||||
inkscape:zoom="15.54902"
|
||||
inkscape:cx="25.5"
|
||||
inkscape:cy="25.5"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><style
|
||||
type="text/css"
|
||||
id="style2">
|
||||
.st0{fill:url(#coin_1_);}
|
||||
.st1{filter:url(#Adobe_OpacityMaskFilter);}
|
||||
.st2{fill:#FFFFFF;}
|
||||
.st3{mask:url(#mask-3);fill:#FFFFFF;}
|
||||
</style><linearGradient
|
||||
id="coin_1_"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="-273.8224"
|
||||
y1="413.966"
|
||||
x2="-274.172"
|
||||
y2="414.57"
|
||||
gradientTransform="matrix(50.3194 0 0 -50.3886 13809.4346 20893.9863)"><stop
|
||||
offset="0"
|
||||
style="stop-color:#FFA24B"
|
||||
id="stop4" /><stop
|
||||
offset="1"
|
||||
style="stop-color:#F7891C"
|
||||
id="stop6" /></linearGradient><path
|
||||
id="coin"
|
||||
class="st0"
|
||||
d="M25.5,51c14.1,0,25.5-11.4,25.5-25.5S39.5,0,25.5,0S0,11.4,0,25.5S11.4,51,25.5,51z"
|
||||
style="fill:#fab915;fill-opacity:1" /><defs
|
||||
id="defs13"><filter
|
||||
id="Adobe_OpacityMaskFilter"
|
||||
filterUnits="userSpaceOnUse"
|
||||
x="15"
|
||||
y="11"
|
||||
width="21"
|
||||
height="28.7"><feColorMatrix
|
||||
type="matrix"
|
||||
values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0"
|
||||
id="feColorMatrix10" /></filter></defs><mask
|
||||
maskUnits="userSpaceOnUse"
|
||||
x="15"
|
||||
y="11"
|
||||
width="21"
|
||||
height="28.7"
|
||||
id="mask-3"><g
|
||||
class="st1"
|
||||
id="g16"><path
|
||||
id="path-2"
|
||||
class="st2"
|
||||
d="M26.2,50.4c13.9,0,25.2-11.3,25.2-25.2S40.1,0,26.2,0S1,11.3,1,25.2S12.3,50.4,26.2,50.4z" /></g></mask><g
|
||||
transform="matrix(2.7667404,0,0,2.7667404,-215.6998,-317.27681)"
|
||||
aria-label=""
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:125%;font-family:icomoon;-inkscape-font-specification:icomoon;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="text4487"><path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 89.710383,123.60521 v -0.0207 q 0.506429,-0.24804 0.785482,-0.7338 0.289388,-0.48576 0.289388,-1.11621 0,-0.69247 -0.330729,-1.1989 -0.33073,-0.50642 -0.847494,-0.74414 -0.320394,-0.14469 -0.682129,-0.19637 -0.3514,-0.0517 -0.816487,-0.0517 H 87.78802 v -0.7028 q 0,-0.10336 -0.07235,-0.1757 -0.07235,-0.0724 -0.1757,-0.0724 H 86.8165 q -0.103353,0 -0.1757,0.0724 -0.07235,0.0723 -0.07235,0.1757 v 0.7028 h -0.806152 v -0.7028 q 0,-0.10336 -0.07235,-0.1757 -0.07235,-0.0724 -0.1757,-0.0724 h -0.7028 q -0.113688,0 -0.186035,0.0724 -0.06201,0.0723 -0.06201,0.1757 v 0.7028 h -0.74414 q -0.06201,0 -0.113688,0.0517 -0.04134,0.0413 -0.04134,0.11369 v 0.68213 q 0,0.0724 0.04134,0.12402 0.05168,0.0413 0.113688,0.0413 h 0.74414 v 6.57324 h -0.692464 q -0.08268,0 -0.144694,0.062 -0.05168,0.0517 -0.05168,0.13436 v 0.59944 q 0,0.0827 0.05168,0.1447 0.06201,0.0517 0.144694,0.0517 h 0.692464 v 0.68213 q 0,0.11369 0.06201,0.1757 0.07235,0.0724 0.186035,0.0724 h 0.72347 q 0.103353,0 0.165365,-0.0724 0.07235,-0.062 0.07235,-0.1757 v -0.68213 h 0.816487 v 0.68213 q 0,0.11369 0.07235,0.1757 0.07235,0.0724 0.1757,0.0724 h 0.72347 q 0.103353,0 0.1757,-0.0724 0.07235,-0.062 0.07235,-0.1757 v -0.68213 h 0.475423 q 0.3514,0 0.661459,-0.0207 0.320394,-0.031 0.620117,-0.14469 0.661458,-0.21704 1.126546,-0.81649 0.465088,-0.60978 0.465088,-1.47794 -0.01034,-0.71314 -0.382406,-1.28158 -0.361735,-0.57877 -1.064534,-0.77515 z m -1.601969,-3.0489 q 0.279052,0 0.485758,0.0413 0.217041,0.0413 0.392741,0.13436 0.279053,0.15502 0.423747,0.45475 0.144694,0.29972 0.144694,0.67179 0,0.57878 -0.3514,0.94051 -0.341065,0.36174 -0.919841,0.36174 h -2.511474 v -2.60449 h 2.335775 z m 0.971516,6.44921 q -0.175699,0.0827 -0.382405,0.10336 -0.206706,0.0207 -0.382406,0.0207 h -2.54248 v -2.97657 h 2.645833 q 0.682129,0 1.085205,0.40308 0.403076,0.39274 0.403076,1.0542 0,0.49609 -0.227376,0.86816 -0.217041,0.37207 -0.599447,0.5271 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.26458332px"
|
||||
id="path4527" /></g></svg>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 51 51" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<path id="coin" d="M25.5,51C39.6,51 51,39.6 51,25.5C51,11.4 39.5,0 25.5,0C11.5,0 0,11.4 0,25.5C0,39.6 11.4,51 25.5,51Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
|
||||
<g id="BitPay.-Bitcoin_Symbol" transform="matrix(0.939973,0.341249,-0.341249,0.939973,10.2185,-7.19166)">
|
||||
<path d="M33.5,19.1C32.9,16.1 30.2,15.3 27,15.2L26.5,11L24,11.2L24.5,15.4C23.8,15.5 23.2,15.5 22.5,15.6L22,11.4L19.5,11.6L20,15.9C19.5,15.9 18.9,16 18.4,16.1L15,16.4L15.3,19.2C15.3,19.2 17.1,19 17.1,19.1C18.1,19 18.5,19.6 18.6,20.1L19.1,25C19.2,25 19.3,25 19.4,25C19.3,25 19.2,25 19.1,25L19.9,31.8C19.9,32.1 19.7,32.7 19.1,32.7L17.3,32.9L17.2,36L20.4,35.7C21,35.7 21.6,35.6 22.2,35.6L22.7,39.9L25.2,39.7L24.7,35.4C25.4,35.4 26.1,35.3 26.7,35.3L27.2,39.5L29.7,39.3L29.2,35C33.4,34.4 36.2,33 36.1,28.9C36,25.6 34.4,24.2 31.9,23.8C33.2,22.8 34,21.4 33.5,19.1ZM31,28.7C31.4,31.9 26,32 24.3,32.2L23.7,26.5C25.5,26.3 30.7,25.3 31,28.7ZM23.5,23.8L23,18.6C24.4,18.5 28.8,17.6 29.1,20.7C29.3,23.6 24.9,23.7 23.5,23.8Z" style="fill:white;fill-rule:nonzero;"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(-17.5917,-30.4347,30.4347,-17.5917,30.8557,34.8191)"><stop offset="0" style="stop-color:rgb(255,162,75);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(247,137,28);stop-opacity:1"/></linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 1.8 KiB |
12
www/img/icon-btc.svg
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<g id="Fondo" transform="matrix(0.0814603,0.0295859,-0.0295859,0.0814603,0.874237,-57.7095)">
|
||||
<g transform="matrix(10.8453,-3.93895,3.93895,10.8453,217.833,629.321)">
|
||||
<use xlink:href="#_Image1" x="7.557" y="5.56" width="22.579px" height="28.881px" transform="matrix(0.981703,0,0,0.995881,0,0)"/>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<image id="_Image1" width="23px" height="29px" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAdCAYAAABBsffGAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACiElEQVRIia3VPYhfRRQF8PM2myya1SxBcLUQP+JXYQpBkJUlGgu1EoRgIyxkUUQUEU0hKQ1io6K9YBRBC0Fj4UdhghYWURHBQtFI0oioWUVFs5vkZ/Hers/J/N9/F7zdO+/MuWfu3JmbbDAwg/PXw50YIzRVgfcmOYqnMY9mowaDObyE23AptmAT3vFvvIFpTOKadSfCgZ7IKbyI+7HUw+/puIs40SV+AJOD5cBr+NXoOI0bO/4HPfyPQfFekgX8PZDgczzZuV6N/esqD+7uHG4k1ppgsFuSzCXZVGBHkrw/gr+c5AVsH+f6ShytONuDi3ArnsJXFc4hbBsSv6+y6CNcUvB24kiFuzBUll0V7HDTND/0gaZpvkzySJIzBXe+Kq5tsdsL+M8kH48wMpvk9wK7YZTzuSRXFNjmJM/jGVzbmZjCTOd8puC/W3M9hTfHtNvPOIm38CPOFP//wo6a+G7n3sxf8MWYhP3Ei2hq1/SWJGUbvZ1kf5Lr057FniRX9/4vJTmU5HiSl5Mcb5pG6fpiHK64WSh4O/Eqzvbc7sOWitkEE7i3IvwZrqrwp/Fhj7eCJ0rS5TiG1/F1RfzZqpt27aMF91tc0Cc8NHA4Z8uS9NZN4r2Cv4z5Vc5EkukkJ5OcGmHwYW1v7+5EV5/ThSR3FNzNaQ81SbL27uKuJI8luSnJhTn3xfwpybHOhCQ3Jyln7HKS2aZplqo2tTPzt95WywsyKk7j8RG7XxM/UCx6TnsLVwaEV3BwnPA2/22vg9iqnf7f9/AT2sP+Bp9gL4YHj/ZduROvaKf8rg7fV5RnB7ZjdlBwRJIGl2Fr993fzXfWM903kOg6PIhPsfi/CFcSnTe2tr34BwJIUvoJiuf+AAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
13
www/img/icon-text-testnet-white.svg
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="57px" height="16px" viewBox="0 0 57 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>Group 2 Copy</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Group-2-Copy">
|
||||
<rect id="Rectangle" stroke="#FBFBFB" x="0.5" y="0.5" width="56" height="15" rx="2"></rect>
|
||||
<path d="M9.75390625,4.55761719 L7.41601562,4.55761719 L7.41601562,13 L5.48144531,13 L5.48144531,4.55761719 L3.20507812,4.55761719 L3.20507812,3.046875 L9.75390625,3.046875 L9.75390625,4.55761719 Z M15.6669922,8.60449219 L12.625,8.60449219 L12.625,11.4960938 L16.2685547,11.4960938 L16.2685547,13 L10.6972656,13 L10.6972656,3.046875 L16.2548828,3.046875 L16.2548828,4.55761719 L12.625,4.55761719 L12.625,7.10058594 L15.6669922,7.10058594 L15.6669922,8.60449219 Z M21.8808594,10.4160156 C21.8808594,10.0195293 21.7794606,9.7062186 21.5766602,9.47607422 C21.3738597,9.24592984 21.0104193,9.02148547 20.4863281,8.80273438 C19.4654897,8.44270653 18.6975937,8.03483301 18.1826172,7.57910156 C17.6676407,7.12337012 17.4101562,6.48535566 17.4101562,5.66503906 C17.4101562,4.84927978 17.7040986,4.18506116 18.2919922,3.67236328 C18.8798858,3.15966541 19.6295527,2.90332031 20.5410156,2.90332031 C21.5071663,2.90332031 22.2841767,3.17675508 22.8720703,3.72363281 C23.4599639,4.27051055 23.7447918,5.00422717 23.7265625,5.92480469 L23.7128906,5.96582031 L21.8398438,5.96582031 C21.8398438,5.45084378 21.7247733,5.06005993 21.4946289,4.79345703 C21.2644845,4.52685414 20.9352235,4.39355469 20.5068359,4.39355469 C20.1376935,4.39355469 19.850587,4.51546102 19.6455078,4.75927734 C19.4404287,5.00309367 19.3378906,5.30728984 19.3378906,5.671875 C19.3378906,6.00911627 19.4541004,6.28710828 19.6865234,6.50585938 C19.9189465,6.72461047 20.3177055,6.96386589 20.8828125,7.22363281 C21.8444058,7.54264482 22.5724259,7.9459611 23.0668945,8.43359375 C23.5613631,8.9212264 23.8085938,9.57746983 23.8085938,10.4023438 C23.8085938,11.2545616 23.5192086,11.9244767 22.9404297,12.4121094 C22.3616508,12.899742 21.5937548,13.1435547 20.6367188,13.1435547 C19.6933547,13.1435547 18.8867221,12.8803737 18.2167969,12.3540039 C17.5468717,11.8276341 17.2233072,11.0266981 17.2460938,9.95117188 L17.2597656,9.91015625 L19.1396484,9.91015625 C19.1396484,10.5345083 19.266112,10.9833971 19.519043,11.2568359 C19.7719739,11.5302748 20.1445288,11.6669922 20.6367188,11.6669922 C21.0514344,11.6669922 21.3624664,11.553061 21.5698242,11.3251953 C21.777182,11.0973296 21.8808594,10.7942727 21.8808594,10.4160156 Z M31.0478516,4.55761719 L28.7099609,4.55761719 L28.7099609,13 L26.7753906,13 L26.7753906,4.55761719 L24.4990234,4.55761719 L24.4990234,3.046875 L31.0478516,3.046875 L31.0478516,4.55761719 Z M39.0458984,13 L37.1181641,13 L33.9599609,6.64941406 L33.9189453,6.65625 L33.9189453,13 L31.9912109,13 L31.9912109,3.046875 L33.9189453,3.046875 L37.0771484,9.40429688 L37.1181641,9.39746094 L37.1181641,3.046875 L39.0458984,3.046875 L39.0458984,13 Z M45.546875,8.60449219 L42.5048828,8.60449219 L42.5048828,11.4960938 L46.1484375,11.4960938 L46.1484375,13 L40.5771484,13 L40.5771484,3.046875 L46.1347656,3.046875 L46.1347656,4.55761719 L42.5048828,4.55761719 L42.5048828,7.10058594 L45.546875,7.10058594 L45.546875,8.60449219 Z M53.3603516,4.55761719 L51.0224609,4.55761719 L51.0224609,13 L49.0878906,13 L49.0878906,4.55761719 L46.8115234,4.55761719 L46.8115234,3.046875 L53.3603516,3.046875 L53.3603516,4.55761719 Z" id="TESTNET" fill="#FFFFFF"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
7
www/img/icon-wallet-testnet.svg
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 40 40" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
|
||||
<g id="flask" transform="matrix(1.27778,0,0,1.27778,7.86111,8)">
|
||||
<path d="M13.358,7.26C13.563,7.465 13.78,7.69 14.009,7.937C14.237,8.183 14.571,8.552 15.011,9.044C15.45,9.536 15.854,10.034 16.224,10.538C16.593,11.042 16.959,11.58 17.322,12.151C17.686,12.722 17.973,13.295 18.184,13.869C18.395,14.443 18.5,14.962 18.5,15.425C18.5,16.134 18.248,16.74 17.744,17.244C17.24,17.748 16.634,18 15.925,18L3.075,18C2.366,18 1.76,17.748 1.256,17.244C0.752,16.74 0.5,16.134 0.5,15.425C0.5,14.962 0.605,14.443 0.816,13.869C1.027,13.295 1.314,12.722 1.678,12.151C2.041,11.58 2.407,11.042 2.776,10.538C3.146,10.034 3.55,9.536 3.989,9.044C4.429,8.552 4.763,8.183 4.991,7.937C5.22,7.69 5.437,7.465 5.642,7.26L5.642,1.925L4.675,1.925C4.587,1.925 4.512,1.894 4.451,1.833C4.389,1.771 4.358,1.696 4.358,1.608L4.358,0.316C4.358,0.229 4.389,0.154 4.451,0.092C4.512,0.031 4.587,0 4.675,0L14.325,0C14.413,0 14.488,0.031 14.549,0.092C14.611,0.154 14.642,0.229 14.642,0.316L14.642,1.608C14.642,1.696 14.611,1.771 14.549,1.833C14.488,1.894 14.413,1.925 14.325,1.925L13.358,1.925L13.358,7.26ZM5,1.283L14,1.283L14,0.642L5,0.642L5,1.283ZM12.717,1.925L6.283,1.925L6.283,4.14C6.705,4.011 7.105,3.926 7.483,3.885C7.861,3.844 8.168,3.838 8.406,3.867C8.643,3.896 8.863,3.948 9.065,4.021C9.267,4.094 9.408,4.156 9.487,4.206C9.566,4.255 9.632,4.304 9.685,4.351C9.737,4.392 9.806,4.437 9.891,4.487C9.976,4.537 10.124,4.601 10.335,4.68C10.546,4.759 10.763,4.811 10.985,4.834C11.208,4.857 11.478,4.835 11.794,4.768C12.11,4.701 12.418,4.576 12.717,4.395L12.717,1.925ZM15.925,17.358C16.458,17.358 16.914,17.169 17.292,16.792C17.669,16.414 17.858,15.958 17.858,15.425C17.858,14.897 17.688,14.273 17.349,13.553C17.009,12.832 16.615,12.161 16.167,11.54C15.718,10.919 15.228,10.295 14.694,9.668C14.161,9.041 13.747,8.574 13.451,8.266C13.155,7.958 12.942,7.746 12.813,7.629C12.749,7.564 12.717,7.485 12.717,7.392L12.717,5.124C12.242,5.353 11.753,5.467 11.249,5.467C10.903,5.467 10.566,5.413 10.238,5.304C9.91,5.196 9.679,5.101 9.544,5.019C9.409,4.937 9.321,4.875 9.28,4.834C9.233,4.799 9.192,4.77 9.157,4.746C9.122,4.723 9.012,4.679 8.828,4.614C8.643,4.55 8.45,4.51 8.248,4.496C8.045,4.481 7.767,4.496 7.413,4.54C7.058,4.583 6.682,4.673 6.283,4.808L6.283,7.392C6.283,7.485 6.251,7.564 6.187,7.629C6.058,7.746 5.845,7.958 5.549,8.266C5.253,8.574 4.839,9.041 4.306,9.668C3.772,10.295 3.282,10.919 2.833,11.54C2.385,12.161 1.991,12.832 1.651,13.553C1.312,14.273 1.142,14.897 1.142,15.425C1.142,15.958 1.331,16.414 1.708,16.792C2.086,17.169 2.542,17.358 3.075,17.358L15.925,17.358ZM9.825,6.425C10.358,6.425 10.812,6.614 11.187,6.992C11.563,7.37 11.75,7.825 11.75,8.358C11.75,8.892 11.563,9.346 11.187,9.721C10.812,10.096 10.358,10.283 9.825,10.283C9.292,10.283 8.836,10.096 8.458,9.721C8.081,9.346 7.892,8.892 7.892,8.358C7.892,7.825 8.081,7.37 8.458,6.992C8.836,6.614 9.292,6.425 9.825,6.425ZM9.825,9.642C10.177,9.642 10.479,9.517 10.73,9.268C10.982,9.019 11.108,8.716 11.108,8.358C11.108,8.001 10.982,7.696 10.73,7.444C10.479,7.192 10.177,7.066 9.825,7.066C9.468,7.066 9.163,7.192 8.911,7.444C8.659,7.696 8.533,8.001 8.533,8.358C8.533,8.716 8.659,9.019 8.911,9.268C9.163,9.517 9.468,9.642 9.825,9.642ZM7.892,10.925C8.249,10.925 8.552,11.051 8.801,11.303C9.05,11.555 9.175,11.859 9.175,12.217C9.175,12.568 9.05,12.87 8.801,13.122C8.552,13.374 8.249,13.5 7.892,13.5C7.534,13.5 7.231,13.374 6.982,13.122C6.733,12.87 6.608,12.568 6.608,12.217C6.608,11.859 6.733,11.555 6.982,11.303C7.231,11.051 7.534,10.925 7.892,10.925ZM7.892,12.858C8.073,12.858 8.226,12.795 8.349,12.669C8.472,12.543 8.533,12.393 8.533,12.217C8.533,12.035 8.472,11.881 8.349,11.755C8.226,11.629 8.073,11.566 7.892,11.566C7.716,11.566 7.565,11.629 7.439,11.755C7.313,11.881 7.25,12.035 7.25,12.217C7.25,12.393 7.313,12.543 7.439,12.669C7.565,12.795 7.716,12.858 7.892,12.858ZM10.783,13.5C11.053,13.5 11.281,13.594 11.469,13.781C11.656,13.969 11.75,14.197 11.75,14.467C11.75,14.73 11.656,14.956 11.469,15.144C11.281,15.331 11.053,15.425 10.783,15.425C10.52,15.425 10.294,15.331 10.106,15.144C9.919,14.956 9.825,14.73 9.825,14.467C9.825,14.197 9.919,13.969 10.106,13.781C10.294,13.594 10.52,13.5 10.783,13.5ZM10.783,14.783C10.871,14.783 10.947,14.752 11.012,14.691C11.076,14.629 11.108,14.555 11.108,14.467C11.108,14.373 11.076,14.295 11.012,14.234C10.947,14.172 10.871,14.142 10.783,14.142C10.695,14.142 10.621,14.172 10.559,14.234C10.498,14.295 10.467,14.373 10.467,14.467C10.467,14.555 10.498,14.629 10.559,14.691C10.621,14.752 10.695,14.783 10.783,14.783Z" style="fill:white;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
24
www/img/mercado-libre/24px.svg
Normal file
|
After Width: | Height: | Size: 31 KiB |
2311
www/img/mercado-libre/giftcard-pt.svg
Normal file
|
After Width: | Height: | Size: 63 KiB |
1
www/img/mercado-libre/icon-ml.svg
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
www/img/mercado-libre/meli-card-24px.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |